Tutorial ini menjelaskan cara membangun aplikasi Java yang berkomunikasi dengan RabbitMQ menggunakan JSON-LD. Aplikasi ini dapat menambah data Place ke database dan mengirim statusnya ke RabbitMQ menggunakan JSON-LD, dengan mengonsumsi pesan dari topik RabbitMQ tertentu dan menggunakan Jackson untuk konversi objek Java ke JSON-LD.
5. Konfigurasi Maven Proxy
Khusus bagi koneksi proxy (seperti ITB). Bila tidak menggunakan
proxy, skip langsung ke slide selanjutnya.
Buat file C:Users<username>.m2settings.xml, isi dengan template
berikut. Perhatikan: Ganti bagian user dan pass sesuai akun AI3 Anda.
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>cache.itb.ac.id</host>
<port>8080</port>
<username>user</username>
<password>pass</password>
<nonProxyHosts>127.0.0.1|localhost|*.itb.ac.id|167.205.*.*</nonProxyHosts>
</proxy>
</proxies>
</settings>
6. Project tutorial-rabbitmq
1. Pastikan koneksi internet Anda aktif
2. Jalankan IntelliJ IDEA
3. Klik Import Project atau New > Project from
Existing Sources
4. Pilih folder project
5. Pilih Import project from external model > Maven
6. Centang:
1. Import Maven projects automatically
2. Automatically download:
◦ Sources
◦ Documentation
7. Klik Next sampai selesai
●
IntelliJ akan menanyakan SDK (ada di slide
selanjutnya)
7. Platform Settings > SDKs
Bila ditanya SDK, Anda perlu menambahkan JDK 8.
Add New SDK > Java
●
Name: 1.8
●
Contoh Path: C:Program FilesJavajdk1.8.0_66
(sesuai build number)
8. Struktur Project
●
Project ini menggunakan Maven project management system,
yang didukung oleh semua IDE Java termasuk IntelliJ IDEA,
Eclipse, dan NetBeans.
●
saat ini Maven sedang mengunduh dependencies/libraries yang
dibutuhkan oleh project (oleh karena itu butuh koneksi Internet)
●
Libraries utama yang digunakan:
●
Spring Boot, terutama:
– Spring Web untuk web support. Termasuk embedded web server yaitu Tomcat.
– Spring Data JPA untuk akses database relational.
●
Apache Wicket untuk web UI
●
Jackson untuk dukungan format JSON-LD
●
Camel sebagai message router, yang mendukung RabbitMQ component
9. Maven Project
●
Aktifkan Maven Project
di sisi kanan, dan pastikan
tidak ada error (merah-
merah)
●
Bila masih ada error, proses
download mungkin masih
berlangsung atau ada
masalah koneksi
●
Coba klik Reimport All
Maven Projects (lihat
gambar)
10. Run Project
●
Di view Project di sisi
kiri, pilih:
●
tutorial-rabbitmq
> src
> main
> java
> org.soluvas.tutorial.rabbitmq
> DaemonApp
●
Klik kanan di class
DaemonApp, klik
Run
12. Mengirim JSON-LD ke RabbitMQ
Untuk menambah Place, kirimkan JSON-LD ke topic starter.place, caranya:
1.Buka RabbitMQ Management di http://localhost:15672/ (user: guest,
password: guest)
2.Klik tab Exchanges
3.Klik exchange amq.topic
4.Masuk bagian Publish message, masukkan:
●
Routing key: starter.place
●
Payload:
{
"@type": "Place",
"name": "Warung Mamah",
"description": "Enak top markotop"
}
5.Klik Publish message.
6.Cek di web UI aplikasi bahwa place Warung Mamah telah ditambahkan.
13. Struktur Aplikasi
●
Untuk struktur dan cara kerja Maven, Spring
Boot & Wicket, Spring Data JPA akan dibahas
di tutorial lain (TODO)
●
Hanya membahas penggunaan libraries
berikut:
●
Jackson untuk dukungan format JSON-LD
●
Camel sebagai message router, yang mendukung
RabbitMQ component
14. Cara Kerja Aplikasi
1)PlaceRepository diimplementasi oleh Spring Data JPA untuk mengelola
tabel place di RDBMS
2)RabbitMqConfig membuat ConnectionFactory untuk RabbitMQ Client
3)ToJson membuat Jackson ObjectMapper untuk konversi JSON-LD <-> Java
object
4)AsError mengubah Exception bawaan Java menjadi object Error yang bisa
dikonversi ke JSON-LD
5)ProducerTemplate diimplementasi oleh Camel untuk mengirimkan message
ke RabbitMQ
●
kebetulan belum dipakai di tutorial ini
6)StarterRouter adalah fungsi utama:
1)mengambil JSON-LD Place dari topic starter.place
2)menyimpannya ke tabel place di RDBMS
3)mengembalikan JSON-LD berupa status berhasil (Status.java) atau gagal (Error.java)
17. StarterThing.java
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonTypeInfo(use= JsonTypeInfo.Id.NAME, property="@type")
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSubTypes({
@JsonSubTypes.Type(name="Status", value=Status.class),
@JsonSubTypes.Type(name="Error", value=Error.class),
@JsonSubTypes.Type(name="Place", value=Place.class),
})
public interface StarterThing extends Serializable {
}
●
interface yang akan diimplementasikan oleh class Status, Error, dan Place
●
diberi Jackson annotations
●
@JsonInclude NON_NULL: hanya property yang diisi yang akan diserialize ke JSON-
LD
●
@JsonTypeInfo “@type”: informasi class dimasukkan ke property “@type” sesuai
standar JSON-LD
●
@JsonIgnoreProperties: property yang tidak dikenali tidak akan menimbulkan error
●
@JsonSubTypes: daftar class yang dikenali
18. Place.java & PlaceRepository.java
JPA @Entity ini berisi:
1)id - @GeneratedValue, long
2)name - varchar(255)
3)description - text
4)creationTime - timestamp
Digunakan sebagai object yang menyimpan
representasi row di tabel place dalam database
SQL.
19. Place.java
@Entity
@EntityListeners(Place.PlaceListener.class)
@Table(indexes = {@Index(name="ik_place_creationtime", columnList = "creationtime")})
public class Place implements StarterThing {
public static class PlaceListener {
@PrePersist
public void setInitialValues(Place place) {
place.setCreationTime(new DateTime());
}
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String name;
@Column(columnDefinition = "text")
private String description;
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime creationTime;
...
20. RabbitMqConfig.java
@Configuration RabbitMqConfig ini bertugas
untuk membuat ConnectionFactory yang
dibutuhkan RabbitMQ Client untuk koneksi ke
server RabbitMQ.
Konfigurasi koneksi RabbitMQ dibaca dari file
application.properties:
# RabbitMQ
amqp.host=localhost
amqp.username=guest
amqp.password=guest
21. RabbitMqConfig.java
@Configuration
public class RabbitMqConfig {
private static final Logger log = LoggerFactory.getLogger(RabbitMqConfig.class);
@Inject
private Environment env;
@Bean
public ConnectionFactory amqpConnFactory() {
final ConnectionFactory connFactory = new ConnectionFactory();
connFactory.setHost(env.getRequiredProperty("amqp.host"));
connFactory.setUsername(env.getRequiredProperty("amqp.username"));
connFactory.setPassword(env.getRequiredProperty("amqp.password"));
log.info("AMQP configuration: host={} username={}", connFactory.getHost(),
connFactory.getUsername());
return connFactory;
}
}
23. ToJson.java
@Service
public class ToJson implements Function<Object, String> {
protected ObjectMapper mapper;
public ToJson() {
mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.registerModule(new GuavaModule());
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
@Override
public String apply(@Body Object o) {
try {
return o != null ? mapper.writeValueAsString(o) : null;
} catch (JsonProcessingException e) {
Throwables.propagate(e);
return null;
}
}
public ObjectMapper getMapper() {
return mapper;
}
}
24. StarterRouter.java
●
@Component ini extends base class yang disediakan
Camel yaitu RouteBuilder
●
Method configure() harus di-override, yang berisi
definisi route
●
Route merupakan instruksi kepada Camel untuk:
– mengambil message dari endpoint tertentu, dalam hal
ini RabbitMQ Component
– melakukan pengolahan
– melakukan konversi dari/ke JSON-LD via Jackson
– menampilkan log (bila perlu)
– mekanisme penanganan kesalahan
25. StarterRouter: Penanganan Kesalahan
onException(Exception.class).bean(asError).bean(toJson).handled(true);
errorHandler(new LoggingErrorHandlerBuilder(log));
Code tersebut:
●
bila terjadi Exception di dalam route:
●
akan diserahkan ke bean asError, yang akan mengubah Exception
menjadi object Error
●
akan diserahkan ke bean toJson, yang akan mengkonversi object Error
menjadi JSON-LD String
●
menandai handled=true, bahwa kesalahan sudah ditangani oleh code
kita
●
bila Camel mendeteksi error:
●
tampilkan dalam log menggunakan LoggingErrorHandlerBuilder
26. StarterRouter: Consume topic RabbitMQ
final String topic = "starter.place";
from("rabbitmq://dummy/amq.topic?
connectionFactory=#amqpConnFactory&exchangeType=topic
&autoDelete=false&routingKey=" + topic)
●
Consume menggunakan konfigurasi RabbitMQ di bean
amqpConnFactory (lihat RabbitMqConfig.java)
●
Consume dari exchange amq.topic
●
Sifat exchange adalah autoDelete=false (exchange tidak
akan dihapus setelah dipakai)
●
Consume dari routing key starter.place
27. StarterRouter: Log input
.to("log:IN." + topic + "?
showHeaders=true&showAll=true&multiline=true")
●
Message input dari RabbitMQ consumer akan
ditampilkan di log dengan nama IN.starter.place
●
Tampilkan:
●
headers
●
semua isi message body
●
mendukung multiline
●
More info: http://camel.apache.org/log.html
28. StarterRouter: Mengolah message
.process(exchange -> {
final StarterThing thing =
toJson.getMapper().readValue(
exchange.getIn().getBody(byte[].class),
StarterThing.class);
if (thing instanceof Place) {
Place place = (Place) thing;
log.info("Saving {} ...", place);
place = placeRepo.save(place);
// reply
exchange.getIn()
.setBody(new Status(place));
} else {
// unknown thing, ignore
exchange.getOut().setBody(null);
}
})
●
Gunakan Jackson untuk
mengkonversi message body
(byte[]) menjadi StarterThing
●
interface StarterThing bisa
diimplementasi oleh class yang
berbeda-beda
●
Bila thing adalah class Place, maka:
●
gunakan placeRepo untuk menyimpan
Place tersebut ke RDBMS
●
mengembalikan Status berisi data
Place yang sudah update
●
Bila thing tidak dikenali, maka:
●
set exchange out menjadi null
●
dengan mengeset exchange out, maka
reply tidak akan dikirimkan
29. StarterRouter: Konversi reply ke JSON-LD
.bean(toJson) ●
Gunakan Jackson
untuk mengkonversi
reply (bila ada)
bertipe Status atau
Error menjadi JSON-
LD String
30. StarterRouter: Konversi reply ke JSON-LD
.to("log:OUT" + topic); ●
Optional
●
Reply akan
ditampilkan di log
dengan nama
OUT.starter.place
sebelum dikirim ke
RabbitMQ
32. pom.xml dependencies:
commons-codec & jdatauri
commons-codec
mendukung berbagai
macam codec, termasuk
Base64 yang umum
dipakai oleh Data URI
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.8</version>
</dependency>
jdatauri untuk parsing
Data URI
<dependency>
<groupId>com.github.ooxi</groupId>
<artifactId>jdatauri</artifactId>
<version>1.0</version>
</dependency>