25 Jan 2007
Kapan pakai interface, dan kapan pakai abstract class?
Pertanyaan menarik ini muncul di milis jug-indonesia. Karena jawabannya cukup panjang, jadi saya copy-paste, sesuaikan sedikit, dan posting di blog.
First of all, ini pertanyaan advanced. Kapan pakai interface, dan kapan pakai abstract class itu cuma bisa dipahami dengan coding banyak-banyak (learning by doing), berpikir secara abstrak, dan banyak belajar desain aplikasi. Jadi jangan berkecil hati kalau Anda bingung setelah membaca artikel ini. Bukannya Anda tidak berbakat coding, tapi hanya kurang jam terbang saja.
Berikut jawaban saya.
Abstract class itu digunakan untuk mengimplementasikan pattern Template Method. Sedangkan interface digunakan (diantaranya) untuk mengimplementasikan pattern Observer.
Pakai interface bila satu class mau memiliki beberapa tipe data. Di Java, tipe data ditentukan oleh interface dan class. Mengacu pada buku Design Pattern, interface digunakan untuk menerapkan pattern Observer.
Contoh mudahnya seperti ini. Misalnya kita membuat aplikasi GUI. dan menggunakan komponen text (JTextArea). Komponen ini memiliki beberapa method untuk mengaktifkan event handling, beberapa diantaranya:
- addMouseListener(MouseListener msl) : merespon gerakan mouse
- addCaretListener(CaretListener cls) : merespon gerakan kursor
Kalau kita definsikan class seperti ini:
public class EventLog implements MouseListener, CaretListener {}
maka class EventLog bisa diumpankan pada kedua method di atas, karena class EventLog bertipe data EventLog, MouseListener, dan juga CaretListener.
Lalu, kapan kita menggunakan abstract class? Salah satunya apabila kita ingin membuat Template Method.
Kutipan dari Design Pattern GoF
By defining some of the steps of an algorithm using abstract operations, the template method fixes their ordering, but it lets Application and Document subclasses vary those steps to suit their needs.
Seperti kita ketahui, Template Method itu salah satu methodnya concrete dan (sebaiknya) final.
Contoh template method bisa dilihat di implementasi AbstractFormController di Spring Framework.
Untuk non-pengguna Spring, AbstractFormController itu mendefinisikan workflow pemrosesan HTML form. Method yang perlu diperhatikan di sini adalah method handleRequestInternal. Isi method ini kira2 seperti ini (dimodifikasi agar mudah dimengerti):
protected void handleRequestInternal() {
bindDataDariForm();
setelahBindSebelumValidasi();
validasiData();
setelahValidasi();
processFormSubmission();
}
Seperti kita lihat di atas, method ini memanggil beberapa method lain secara berurutan. Urutan ini penting, karena kita tidak mau validasi dipanggil setelah form diproses. Apa gunanya validasi kalau pemrosesan sudah selesai?
Class AbstractFormController ini punya abstract method, yaitu:
public abstract void processFormSubmission();
Kenapa dibuat abstract? Karena pada saat menulis kode tersebut, Rod Johnson tidak tahu apa yang kita ingin lakukan pada saat form diproses. Ada yang mau simpan ke database, ada yang mau kirim email, dan berbagai kegiatan lain yang tidak terbayangkan sebelumnya. Oleh karena itu, method ini dibuat abstract, sehingga kita harus membuat implementasinya (override)
Nah, kita sebagai end-user, biasanya hanya perlu mengimplement method processFormSubmission tersebut. Method lainnya hanya dioverride apabila perlu. Misalnya kita ingin pakai logika validasi sendiri, atau ada pemrosesan khusus setelah validasi.
Teknik Template Method ini tidak bisa diimplement dengan interface, karena harus ada method concrete handleRequestInternal yang berfungsi untuk mendefinsikan workflow.
Demikian, mudah-mudahan bisa dimengerti.
23 Jan 2007
Saya akan berbicara pada pertemuan rutin komunitas Java, JaMU (Java Meet Up). Acaranya akan diadakan di kantor Sun Microsystem, Sabtu, 27 Januari 2006.
Tema yang akan saya bawakan adalah Ruthless Testing. Materi ini sudah dibahas pada beberapa artikel di blog ini. Silahkan datang langsung ke kantor Sun untuk mengikuti presentasinya. Gratis, tidak dipungut biaya. Anda tidak harus menguasai Java untuk bisa hadir.
Materi presentasi bisa dilihat secara online.
Presentasi dibuat menggunakan perangkat canggih bernama S5 (Simple Standards-Based Slide Show System), tools yang dibuat Eric Meyer, pakar CSS. Dengan S5, presentasi dapat dibuka oleh mayoritas browser yang digunakan masyarakat. Tidak tergantung lagi pada OpenOffice apalagi Microsoft Office.
Selamat membaca … sampai ketemu di JaMU.
18 Jan 2007
Pada artikel ini, kita akan coba buat demo penggunaan JMS menggunakan Spring Framework dan ActiveMQ. Spring Framework 2.0 telah dilengkapi dengan helper class untuk memudahkan kita menggunakan JMS (Java Messaging Service). Sayangnya dokumentasi di Spring Reference kurang lengkap, sehingga ada beberapa bagian yang harus kita cari sendiri.
Jangan khawatir, bagian yang kurang tersebut bisa dibaca di artikel ini.
Berikut skenario yang ingin saya buat:
-
Jalankan JMS server (kali ini saya gunakan ActiveMQ)
-
Siapkan MessageListener, yang akan bereaksi bila menerima pesan pada destination tertentu
-
Kirim beberapa pesan ke destination yang didengarkan oleh MessageListener
-
Pastikan pesan tersebut diterima dengan baik
Kita akan buat kasus sederhana saja, melibatkan tiga class:
-
Sender.java : pengirim pesan
-
Receiver.java : penerima pesan (MessageListener)
-
Main.java : class untuk menjalankan pengirim dan penerima
Berikut adalah kode programnya.
Sender.java
package tutorial.spring.jms;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
public class Sender {
private String message = "default message";
private JmsTemplate jmsTemplate;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void setMessage(String message) {
this.message = message;
}
public void send() {
jmsTemplate.send(new MessageCreator(){
public Message createMessage(Session sess) throws JMSException {
return sess.createTextMessage(message);
}
});
}
}
Receiver.java
package tutorial.spring.jms;
import javax.jms.JMSException;
public class Receiver implements MessageListener {
public void onMessage(Message msg){
if (msg instanceof TextMessage) {
TextMessage txtMsg = (TextMessage) msg;
try {
System.out.println(txtMsg.getText());
} catch (JMSException e) {
e.printStackTrace();
}
} else {
System.out.println("Unsupported message type : "+msg.getClass());
}
}
}
Main.java
package tutorial.spring.jms;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jms-ctx.xml");
Sender sender = (Sender) ctx.getBean("sender");
sender.setMessage("Percobaan menggunakan JMS dengan Spring. ");
sender.send();
sender.setMessage("Pesan ini seharusnya diterima oleh Message Driven POJO");
sender.send();
}
}
Integrasi antara kode Java dan ActiveMQ diatur di konfigurasi Spring, jms-ctx.xml. Berikut kodenya.
jms-ctx.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="messageListener" class="tutorial.spring.jms.Receiver" />
<bean id="listenerContainer" class="org.springframework.jms.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="destinationName" value="TEST.FOO"/>
<property name="messageListener" ref="messageListener"/>
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<constructor-arg index="0"><null/></constructor-arg>
<constructor-arg index="1"><null/></constructor-arg>
<constructor-arg index="2" value="tcp://localhost:61616"></constructor-arg>
</bean>
<bean id="sender" class="tutorial.spring.jms.Sender">
<property name="jmsTemplate" ref="jmsTemplate"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
<property name="defaultDestinationName" value="TEST.FOO"/>
</bean>
</beans>
Apabila kita ingin menggunakan JMS server yang lain (selain ActiveMQ), cukup ganti deklarasi jmsConnectionFactory pada jms-ctx.xml di atas. Destination name juga di-hard code dengan nilai TEST.FOO. Nantinya pada aplikasi nyata, nilai ini mungkin ingin kita konfigurasi lebih jauh, atau diparameterisasi dalam database.
ActiveMQ mendukung dynamic destination creation, artinya destination TEST.FOO akan dibuatkan bila belum ada. Pada aplikasi server JMS yang lain, mungkin kita harus membuat TEST.FOO secara manual di server tersebut.
Selamat mencoba, semoga sukses.
06 Jan 2007
Menyimpan kode program Java ke repository tidak sulit. Yang lebih sulit adalah menyimpan artifak database, yaitu:
- Skema database
- Stored Procedure
- Functions
- Sample/Initial data
Kalau dilakukan dengan cara manual, akan sangat merepotkan, karena programmer harus melakukan langkah-langkah berikut untuk memastikan kode programnya tersimpan di repository:
- Copy semua source code melalui Query Editor
- Paste satu per satu ke text file
- Commit ke repository
- Ulangi langkah 1 - 3 untuk setiap kali perubahan
Dengan skala ribuan procedure, cara ini sangat merepotkan dan dijamin tidak akan dilakukan oleh programmer. Harus ada cara yang lebih baik.
Untungnya –seperti halnya masalah yang umum kita temukan– sudah banyak orang lain yang mengalami masalah sama, dan sudah ada yang memecahkannya. Kali ini solusinya adalah ScriptDB4SVN. Aplikasi kecil yang seumur hidupnya hanya bertugas melakukan langkah 1-3 di atas.
Sayangnya aplikasi ini hanya bisa digunakan untuk Microsoft SQL Server.
Aplikasi ini membutuhkan .Net Framework 2.0 yang dapat didownload secara cuma-cuma di website Microsoft. Segera setelah .Net Framework diinstal, kita dapat langsung menjalankan ScriptDB4SVN.
Sebelumnya, kita harus edit dulu file konfigurasinya. Kita harus beritahu ScriptDB4SVN tentang:
- Host database
- Nama database yang akan digunakan
- Daftar tabel yang akan didump datanya
Berikut adalah contoh konfigurasinya
Setelah konfigurasi selesai dibuat, jalankan ScriptDB4SVN.exe. Hasilnya seperti ini.

Setiap kali ada perubahan di database, dobel-klik ScriptDB4SVN dan commit file yang berubah. Harus diperhatikan, ScriptDB4SVN tidak otomatis menjalankan svn add. Jadi kalau ada Store Procedure baru, kita harus jalankan svn add secara manual.
Pembaca yang teliti mungkin akan melihat script sql dengan nama aneh pada screenshot di atas. Itu adalah script replikasi. Kalau script tersebut dijalankan di Query Analyzer, maka dia akan merekonstruksi database sehingga sama dengan kondisi database target pada saat ScriptDB4SVN dijalankan.
Dengan adanya tools ini, masing-masing programmer dapat bekerja di database lokalnya sendiri. Secara periodik, dia harus melakukan svn update dan merekonstruksi database lokalnya dengan script terbaru sehingga tetap sinkron dengan kondisi terbaru.