Sebelum ngobrol panjang lebar bagi kalian yang belum tau apa itu Java Message Service silakan baca pengantarnya di post berikut.
Apa itu Point-to-Point ( PTP ) Messaging :
- PTP berkisar antara 3 istilah ini Sender/Producer, Message Queue, Receiver/Consumer. Sender mengirim pesan dengan ke JMS Provider, setelah itu JMS Provider menyimpan pesan tersebut dalam Message Queue, ketika ada Receiver yang sedang terhubung ke JMS Provider, maka JMS Provider akan mengirimkan pesan itu ke Receiver lalu setelah diterima pesan tersebut dihapus dari Message Queue oleh JMS Provider.
- Pesan yang dikirim melalui PTP hanya boleh di terima oleh satu Receiver, kok bisa? itu karena ketika pesan sudah dikirim ke satu client maka akan langsung dihapus jadi client yang lain tidak akan bisa menerima lagi... lha wong sudah dihapus kok.
- Sender mengirim pesan dengan subjek queue tertentu dan Receiver dapat menerimanya dengan terhubung ke JMS Provider dengan subjek queue tersebut. Subjek Queue ini yang dimaksud dengan preconfigured-object destination diatas. Artinya admin JMS Provider membuat satu anam queue tertentu dimana itu yang akan digunakan sebagai jembatan client yang satu dengan yang lain berkomunikasi.
- Multiple sender bisa mengirim dengan subjek queue yang sama tapi tetap hanya satu receiver yang akan menerima satu pesan.
1. Download JMS Provider.
JMS Provider bisa dianggap seperti server yang bertugas menerima dan mengirim pesan antar jms client. Paling pas kalau JMS Provider dianalogikan seperti kantor pos tempat dimana surat-surat berkumpul.
Jadi kita harus mendownload JMS Provider dan yang akan kita gunakan adalah JMS Provider dari Apache Foundation yatu Apache ActiveMQ, silakan download di link berikut.
Dalam contoh ini kita akan menggunakan ActiveMQ-5.9.0
Berikut hasil extract dari file zip dari ActiveMQ yang kalian download :
![]() |
Susunan direktori ActiveMQ |
![]() |
Susunan folder bin dari ActiveMQ |
2. Tambahkan library ActiveMQ ke classpath projek
Bisa dilihat di screenshoot susunan direktori ActiveMQ diatas ada file activemq-al-5.9.0.jar , tambahkan library itu ke dalam projek classpath.
Berikut contoh menggunakan Netbeans :
3. Jalankan ActiveMQ
Berikutnya adalah menjalankan JMS Provider alias ActiveMQ yang digunakan untuk Tukang pos nya. Bisa kalian lihat di folder bin di screenshoot di atas, untuk menjalankannya silakan di double-click file activemq.bat
Di atas adalah window yang muncul ketika kalian menjalankannya, biarkan window itu tetep terbuka seperti itu. Ingat! Jangan ditutup! kalau kalian tutup sama saja kalian matikan lagi. Paham!
Untuk mengetes apa benar sudah nyala silakan buka browser dan ketik http://localhost:8161/
Link diatas adalah default untuk melihat admin dari ActiveMQ, tampilannya dibawah :
Perhatikan 2 tanda panah di atas :
Untuk mengetes apa benar sudah nyala silakan buka browser dan ketik http://localhost:8161/
Link diatas adalah default untuk melihat admin dari ActiveMQ, tampilannya dibawah :
Perhatikan 2 tanda panah di atas :
- Panah paling atas menunjukkan admin console baru dari activemq.
- Panah paling bawah adalah admin console lama dari activemq.
Kita sama kan persepsi, kita sepakat gunakan yang admin console lama karena tampilannya sederhana.
Ketika ditanya username dan password maka default usernamenya adalah admin dan default passwordnya adalah admin.
Tampilannya seperti dibawah :
Perhatikan menu yang di tandai dengan kotak merah, itu adalah menu untuk melihat subjek/destination dari pesan yang dikirim dari producer dan juga yang akan diakses oleh consumer.
Untuk menu yang lain kita bahas lain kali dengan topik posting yang relevan.
4. Time for Coding
Untuk client yang mengirim pesan kodenya seperti di bawah :
import java.util.logging.Level; import java.util.logging.Logger; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; public class PTP { public static void main(String[] args) { try { String username=null; String password=null; String url="tcp://localhost:61616"; ConnectionFactory factory=new ActiveMQConnectionFactory(username, password, url); Connection connection = factory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Queue destination = session.createQueue("ptp"); MessageProducer producer = session.createProducer(destination); TextMessage message = session.createTextMessage("Helo World!"); producer.send(message); session.close(); producer.close(); connection.close(); System.out.println("----Finishing Sending----"); } catch (JMSException ex) { Logger.getLogger(PTP.class.getName()).log(Level.SEVERE, null, ex); } } }
Pembahasan :
- Buat koneksi dengan JMS Provider
String username=null; String password=null; String url="tcp://localhost:61616"; ConnectionFactory factory=new ActiveMQConnectionFactory(username, password, url); Connection connection = factory.createConnection();
Untuk membuat instance Connection kita membutuhkan ConnectionFactory dan untuk membuat instance dari ConnectionFactory caranya berbeda-beda sesuai dengan JMS Provider yang digunakan.
Diatas untuk membuat ConnectionFactory untuk ActiveMQ menggunakan new ActiveMQConnectionFactory( user, password, url ).
Itu khusus untuk ActiveMQ sedangkan untuk provider yang lain akan berbeda seperti untuk Fiorano MQ, IBM MQSeries dan teman-temannya.
Nah loh! Kalau seperti itukan jadi tight-coupled, katanya Loosely-Coupled!!!!
Jangan berprasangka dulu dong! Kenapa? karena biasanya instance dari Connection atapun ConnectionFactory diambil dari JNDI yang artinya kdoe diatas akan diganti kode JNDI yang merujuk kepada ConnectionFactory itus sendiri yang disimpan di file luar gitu, jadi dengan menggunakan JNDI untuk membuat ConnectionFatory akan membuatnya loosely-coupled.
Ada yang aneh!! Kok username dan password null!
Hahhhh!! Iya juga!!! Just Kidding....
Secara default username dan password dari ActiveMQ bisa tidak diisi alias null, jika seperti itu maka ActiveMQ langsung mengasumsikan bahwa koneksi menggunakan default username dan default password.
Secara default username dan password dari ActiveMQ bisa tidak diisi alias null, jika seperti itu maka ActiveMQ langsung mengasumsikan bahwa koneksi menggunakan default username dan default password.
Lah kalau gitu semua orang bisa mengaksesnya dong jika tau url nya!!
Lagi-lagi jangan prasangka buruk dulu, settingan itu bisa dirubah, tapi tidak disini kita bahasnya mungkin di post lain jadi untuk sekarang kamu harus puas dengan username dan password default.
Url disitu adalah adalah alamat untuk terhubung ke ActiveMQ yang sedang running.
Untuk merubah portnya silakan buka file activemq.xml di folder conf yang ada disusunan direktori ActiveMQ.
Berikutnya setelah kita sudah mempunyai instance dari ConnectionFactory kita membuat instance dari Connection seperti snippet code diatas. Untuk membuat instance dari Connection ini generic seperti itu dan tidak berbeda untuk JMS Provider yang lain, jadi yang dependent terhadap JMS Providernya cuma ConnectionFactory saja.
- Membuat Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
* Parameter petama dalam methode diatas adalah boolean yang menandakan apakah session ini bersifat transacted atau tidak, jika false berarti tidak.
Maksudnya transacted adalah aplikasi client yang menerima harus secara eksplisit memanggil methode commit( ) untuk melakukan acknowledgement sehingga JMS Provider tau kalau pesan diterima dengan baik. Enaknya menggunakan mode transacted ini adalah kita bisa secara manual untuk melakukan commit dan juga ada fitur rollback dengan memanggil methode rollback( ).
Untuk contoh PTP ini kita pakai false, untuk bagaimana dengan contoh true itu butuh post tersendiri.
* Parameter kedua memiliki 4 nilai berikut :
1. Session.AUTO_ACKNOWLEDGE
Client otomatis menyatakan bahwa pesan yang diterima valid dan oleh karena valid maka JMS Provider akan menghapus pesan tersebut dari JMS Provider.
2. Session.DUPS_OK_ACKNOWLEDGE
Sama seperti Session.AUTO_ACKNOWLEDGE, letak perbedaanya cuma ini bersifat lazily.
3. Session.CLIENT_ACKNOWLEDGE
Aplikasi client harus secara manual atau eksplisit melakukan acknowledge dengan memanggil methode acknowledge( ) dari instance Message.
4. Session.SESSION_TRANSACTED
Ini digunakan ketika parameter pertama bernilai true alias bersifat transacted.
Note :
1. Sebenarnya untuk MessageProducer a.k.a aplikasi sender ( yang mengirim pesan), 2 parameter ini tidak berpengaruh alias kita isi apa saja ndak ada masalah, karena 2 parameter ini berfungsi ketika ada pada sisi client yang menerima alias Consumer.
- Membuat Destination a.k.a Queue
Queue destination = session.createQueue("ptp");
Subjek/Queue ini yang akan diakses oleh receiver nantinya dan JMS Provider akan menyimpan dan mengantrikan pesan yang dikirim dengan nama “ptp”. Jika subjek itu tidak ada maka ActiveMQ akan membuatnya otomatis.
Sebenarnya aplikasi baik itu yang mengirim atau yang menerima seharusnya tidak diperbolehkan untuk membuat subje/queue karena hal itu bukanlah praktek yang bagus. Setting default ActiveMQ memang diperkenankan jika subjek/queue tidak ada maka akan otomatis dibuat tetapi hal ini bisa diatur di file configurasi actvemq.xml yang mungkin akan dibahas di topik tersendiri.
Bisa dianggap ini adalah nama antrian.
- Membuat Producer
MessageProducer producer = session.createProducer(destination);
Membuat instance dari MessageProducer yang nantinya akan digunakan untuk mengirim pesan. Ibaratnya ini adalah tukang pos-nya. Parameter yang dibutuhkan adalah instance dari Queue diatas.
- Membuat Message
TextMessage message = session.createTextMessage("Helo World!");
Ini adalah instance dari Message yang akan dikirimkan ke JMS Provider oleh MessageProducer diatas.
Diatas adalah contoh dari TextMessage yang ditujukan untuk mengirim pesan teks.
Selain TextMessage ada lagi MapMessage, BytesMessage, StreamMessage, ObjectMessage yang semuanya itu turunan dari class Message.
- Mengirim Message
producer.send(message);Metode ini untuk mengirim pesan ke JMS Provider untuk diantrikan dalam Queue dengan nama “ptp”.
- Menutup resources
session.close(); producer.close(); connection.close();
Menutup semua resource yang terbuka. Sebenarnya hanya dengan menutup instance dari Connection saja sudah otomatis menutup Session dan MessageProducer
Sekarang waktunya kode untuk consumer a.k.a receiver.
Ada 2 cara untuk menerima pesan dari JMS Provider
Cara 1 ( mengunakan methode receive( ) ) :
Sekarang waktunya kode untuk consumer a.k.a receiver.
Ada 2 cara untuk menerima pesan dari JMS Provider
Cara 1 ( mengunakan methode receive( ) ) :
import java.util.logging.Level; import java.util.logging.Logger; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; public class Receiver { public static void main(String[] args) { try { String username=null; String password=null; String url="tcp://localhost:61616"; ConnectionFactory factory=new ActiveMQConnectionFactory(username, password, url); Connection connection = factory.createConnection(); Session session = connection.createSession(false, Session.SESSION_TRANSACTED); Queue destination = session.createQueue("ptp"); connection.start(); MessageConsumer consumer = session.createConsumer(destination); Message message = consumer.receive(); if(message instanceof TextMessage){ TextMessage pesan=(TextMessage) message; System.out.println("--Pesan diterima--"); System.out.println(pesan.getText()); }//end of if session.close(); consumer.close(); connection.close(); } catch (JMSException ex) { Logger.getLogger(PTP.class.getName()).log(Level.SEVERE, null, ex); } } }Cara 2 ( mengunakan MessageListener atau dikenal dengan istilah Asynchronous receiver ) :
import java.util.logging.Level; import java.util.logging.Logger; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; public class Receiver { public static void main(String[] args) { try { String username=null; String password=null; String url="tcp://localhost:61616"; ConnectionFactory factory=new ActiveMQConnectionFactory(username, password, url); Connection connection = factory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Queue destination = session.createQueue("ptp"); connection.start(); MessageConsumer consumer = session.createConsumer(destination); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { if(message instanceof TextMessage){ try { TextMessage pesan=(TextMessage) message; System.out.println("--Pesan diterima--"); System.out.println(pesan.getText()); } //end of if catch (JMSException ex) { Logger.getLogger(Receiver.class.getName()).log(Level.SEVERE, null, ex); } } } }); } catch (JMSException ex) { Logger.getLogger(PTP.class.getName()).log(Level.SEVERE, null, ex); } } }
Pembahasan :
Disini akan dibahas yang menjadikannya perbedaan dengan kode Producer diatas sedang untuk kode untuk koneksi penjelasannya sama.
- Membuat Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Perhatikan!! Kodenya sama dengan yang di Producer diatas tapi 2 parameter untuk mengindikasikan transacted dan acknowledge take into action here. Jadi kalau diatas sudah dijelaskan kalau untuk aplikasi yang mengirim pesan a.k.a Producer tidak ada efeknya, itu berbeda dengan aplikasi yang menerima a.k.a Receiver. Dua parameter ini akan menentukan gimanan aplikasi yang menerima akan melakukan acknowledge. Jadi camkan itu di pikiran!!
- Membuat Destination a.k.a Queue
Queue destination = session.createQueue("ptp");
Perhatikan!! nama subjek untuk Queue harus sama dengan yang ada di producer. Logikanya sederhana. Untuk mendapatkan pesan yang dikirim dari producer yang disimpan oleh provider dengan nama queue tertentu maka wajar kan kalau aplikasi penerima juga tersambung dengan nama Queue yang sama.
Jadi ibaratnya nama queue ini yang akan jadi jembatan penghubung antara producer dan consumer.
- Menjalankan Connection
connection.start();
Ini penting!! Bagian ini berbeda dengan kode yang untuk Producer di atas, agar kita bisa menerima pesan dari JMS Provider kita harus memanggil methode start( ) dari instance Connection.
Dan yang tidak kalah penting adalah methode start( ) harus dipanggil sebelum kita memanggil methode receive( ) untuk menerima pesan dengan cara ke-1 di atas. Karena jika tidak program akan menunggu dengan hampa tanpa ada pesan yang diterima gara-gara Connection belum di start.
Untuk producer tanpa di connection.start( ) pesan masih bisa dikirim.
- Membuat MessageConsumer
MessageConsumer consumer = session.createConsumer(destination);Membuat instance dari class MessageConsumer. Class ini menjadi aktor utama untuk menerima pesan.
- Menerima pesan
cara 1 :
Message message = consumer.receive(); if(message instanceof TextMessage){ TextMessage pesan=(TextMessage) message; System.out.println("--Pesan diterima--"); System.out.println(pesan.getText()); }//end of if
Ketika methode consumer.receive( ) maka program akan ngeblock alias kode di bawah receive( ) tidak akan dikerjakan.
Ketika JMS provider mengirimkan pesan maka methode receive( ) akan kembali dengan mengembalikan instance dari class Message.
Impilikasi menggunakan methode ini :
* Bahaya!! Tapi jika methode receive( ) dipanggil dan waktu itu JMS Provider tidak terdapat pesan untuk Queue yang dimaksud maka aplikasi akan ngeblok terus dan terus menunggu dengan hampa dan keputuasaan karena yang ditunggu nggak kunjung datang.
* Dengan menggunakan methode ini kita hanya bisa menerima 1 pesan saja. Jika kita ingin menerima lebih dari 1 pesan maka kita harus mengulang pemanggilan methode receive( ). Sungguh merepotkan sekali kan!!
cara 2 :
MessageConsumer consumer = session.createConsumer(destination); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { if(message instanceof TextMessage){ try { TextMessage pesan=(TextMessage) message; System.out.println("--Pesan diterima--"); System.out.println(pesan.getText()); }catch (JMSException ex) { Logger.getLogger(Receiver.class.getName()).log(Level.SEVERE, null, ex); } } } });
Cara ini dikenal dengan Asynchronous receive. Kok bisa gitu? Karena dengan cara ini tidak perlu ada yang namanya blovking program. Setiap kali ada pesan yang tersedia di Queue yang bersangkutan maka JMS Provider akan memanggil onMessage( ). Agar bisa seperti itu kita harus meng-attach MessageListener pada MessageConsumer. Enak kan nggak perlu nunggu!
Perumpaan untuk cara ini kita tinggal dirumah sambil nonton TV dan ketika ada surat untuk kita di Kantor pos maka Tukang pos akan mengirimkannya ke rumah kita.
Untuk kedua cara itu silakan diperhatikan cara menampilkan pesan yang diterima... Kita mula-mula merubah instance dari Message menjadi TextMessage kemudian menggunakan methode getText( ) untuk mendapat isi pesan.
Loh kenapa kok dirubah ke TextMessage! Wajar toh, ini kan hanya buat contoh dan sebelumnya kita tau bahwa yang dikirim adalah instance dari TextMessage maka dari itu di receiver kita merubahnya kembali menjadi TextMessage. Kita bisa mengirim jeni pesan apapun sesuai dengan keinginan melalu beberapa tipe pesan seperti yang sudah dijelaskan di atas. Untuk contoh disini kita hanya menggunakan yang paling simpel yaitu pesan teks. Silakan coba sendiri untuk jenis pesan yang lain.
- Menutup Reources
session.close(); consumer.close(); connection.close();
Jangan lupa untuk menutup resource!
Ada yang aneh!! Kok di cara pertama resources di close tapi di cara ke dua tidak ada kode untuk menutup resources.
Pertama yang perlu diingat bahwa menutup resources itu penting dan lakukan itu.
* Untuk cara pertama kita menuliskan code untuk menutup resource karena methode receive( ) tidak akan melakukan blocking sehinggan methode untuk menutup resource yang tepat ada dibawahnya tidak akan dikerjakan sampai ada pesan yang diterima sehinggan receive( ) tidak akan ngeblok lagi.
* Untuk cara kedua karena tidak perlu ngeblok maka kalau kita menaruh methode untuk menutup resources di situ maka langsung akan dieksekusi. Bayangkan JMS Provider saja belum sempat mengirimkan pesan ke aplikasi penerima lah kok connection sudah ditutup ibaratnya tukang pos datang ke rumah kita tapi pintunya ditutup dan ditinggal tidur tentu saja suratnya nggak dikasihkan kan! Begitulah analoginya.
Lalu apa tetep dibiarkan tidak ditutup.! Tentu saja tidak, ini kan hanya contoh dan biasanya kita bikin aplikasi kan pakai GUI, jadi kita bisa menempatkan kode untuk menutup resources ketika jendela GUI ditutup gitu.
Ingat diatas hanya contoh, menutup resources itu harus kita perhatikan dengan seksama dalam tempo yang sesingkat-singkatnya. Malang 21 Nopember 2013. Sekian sampai jumpa di posting berikutnya.
Tidak ada komentar:
Posting Komentar