Wednesday, April 29, 2009

Aspect Oriented Programming

Dalam membuat software, kita harus memikirkan banyak hal dalam satu waktu seperti proses bisnis, security, logging, persistence, multithreading, transaction, dll. Dari sekian banyak hal yang harus dipikirkan di atas, kita bisa mengelompokkannya menjadi dua kategori (dalam istilah AOP disebut concern). Kategori pertama adalah core concern, yaitu fungsi-fungsi utama sebuah software dibangun. Dalam hal ini tentu saja adalah proses bisnis. Kategori kedua adalah system-wide concern atau crosscutting concern, yaitu fungsi-fungsi yang tersebar di seluruh bagian software. Fungsi-fungsi ini bukan fungsi utama tetapi pendukung sistem, namun keberadaannya tetap diperlukan untuk memenuhi requirement software yang baik. Contohnya adalah security, pooling, logging, dan persistence.

OOP, seperti Java dan C++, telah terbukti sebagai metodologi yang baik untuk implementasi core concern, tapi tidak cukup baik untuk crosscutting concern. Ambil contoh logging. Dengan Java kita terbiasa menulis kode untuk logging bercampur dengan bisnis proses, misalnya untuk debugging. Jika kita ingin mengubah logging, maka kita harus melakukan perubahan di core concern, dalam hal ini class atau method untuk proses bisnis. Sebagai ilustrasi lihat gambar berikut ini yang memperlihatkan sebuah sistem yang terdiri dari beberapa concern menjadi satu, dalam AOP disebut tangled (awut-awutan).



Perhatikan ilustrasi lain berikut ini, Ramnivas Laddad menggambarkan beberapa concern dalam multidimensional-space sebagai berikut



Dari gambar terlihat bahwa sebuah software terdiri dari tiga concern yaitu persistence, logging, dan business logic. Namun dalam implementasinya ketiga concern tersebut tetap menjadi satu dimensi karena metodologi OOP mengharuskannya demikian. Gambar di atas jika diimplementasikan dalam code lebih kurang seperti ini

public class MyAllInOneClass {
public void superMethod() {

// lakukan autorisasi

// logging start business process
// lakukan proses bisnis
// logging end business process
}
public void save() {...}
public void load() {...}
}

Dari implementasi class di atas terlihat bahwa concern persistence berada dalam satu class dengan core concern, juga security dan logging concern berada dalam satu method dengan core concern.

AOP adalah metodologi yang memisahkan antara core concern dan crosscutting concern dengan memperkenalkan sebuah modul yang disebut aspect. Dengan AOP, kita mengimplementasikan crosscutting concern dalam aspect, tidak lagi dalam core concern. Dengan demikian kita tidak perlu mengkhawatirkan masalah crosscutting concern lagi pada saat awal kita membangun software. Kita bisa fokus membangun proses bisnis karena crosscutting concern tersebut bisa ditambahkan ke dalam sistem tanpa kita perlu mengubah core concern.

OOP telah sukses membuktikan diri sebagai metodologi yang tepat untuk memecahkan sistem yang kompleks menjadi sederhana dengan membaginya ke dalam class-class yang dikenal dengan istilah modularisasi. Dalam loosely coupling, OOP juga bisa diandalkan dengan memisahkan interface dan class-class implementasinya.

AOP tidak dimaksudkan untuk menggantikan OOP, sebaliknya, AOP akan menjadikan OOP semakin handal dalam membuat modularisasi melalui pemisahan concern. Dan walaupun pemisahan abstract dan implementasi dalam interface dan class berhasil untuk core concern, namun tidak untuk crosscutting concern. Perhatikan bahwa untuk setiap kita melakukan logging kita tetap harus memanggil API logger di setiap method yang mau logging. Artinya code untuk memanggil API logging akan tersebar di seluruh core concern yang membutuhkannya, yang seperti telah digambarkan di atas sebagai code tangling (awut-awutan). Dengan AOP, kita tidak perlu memanggil API untuk logging dari core concern. Dua gambar berikut adalah ilustrasi sebelum dan sesudah AOP digunakan. Perhatikan bahwa pada gambar pertama kita memanggil API logging sedangkan pada gambar kedua seluruh modul benar-benar terpisah.





AOP Methodology

Membangun sistem menggunakan AOP mirip dengan membangun sistem menggunakan metodologi lainnya : mengidentifikasi concern, mengimplementasikan concern, dan membentuk sistem akhir dengan menggabungkan concern-concern tersebut.

1. Aspectual Decomposition

Pada tahap ini kita melakukan decompose requirements untuk mengidentifikasi core concern dan crosscutting concern.

2. Concern Implementation

Pada tahap ini kita mengimplementasikan tiap concern secara independen. Perhatikan bahwa pada tahap ini masing-masing concern diimplementasikan pada modulnya sendiri, terpisah dengan modul lain. Dengan demikian kita bisa membuat modul per modul secara bertahap, tidak perlu memikirkan sekian banyak modul dalam satu waktu.

3. Aspectual Recomposition

Pada tahap ini kita membuat recomposition rules dengan membuat modularization unit atau aspect. Proses recomposition disebut juga weaving atau integrating, dan akan membentuk sistem akhir berdasarkan aspect tersebut.

Berikut ilustrasi yang digambarkan oleh Ramnivas Laddad :



Bagaimanakah weaver bekerja? Cara yang paling sederhana adalah melalui source-to-source translation. Source code untuk masing-masing modul dan aspect diproses untuk membentuk woven source code. Aspect compiler kemudian mengirimkan woven-source-code tersebut kepada compiler bahasa pemrograman yang dipakai untuk membentuk byte-code. Dengan pendekatan ini menggunakan Java, maka Java-based AOP implementation mengubah masing-masing source code pada tiap modul kedalam woven java source code kemudian java compiler mengubahnya menjadi byte code. Perhatikan bahwa weaver tidak akan mengubah original source code sama sekali.

Berikut adalah contoh untuk memperjelas bagaimana AOP diimplementasikan pada Java

1. Kita memiliki core logic sebagai berikut



2. Kita memiliki crosscutting concern berupa logging interface seperti berikut

public interface Logger {
public void log(String message);
}

3. Kita memiliki aspect berikut



3. Setelah proses weaving maka kita memiliki source code kira-kira seperti berikut

Wednesday, April 22, 2009

EJB 3 Web Service Overview

Menggunakan JavaEE 5, kita bisa menggunakan POJO atau EJB 3 stateless session bean untuk membangun web service. Ada beberapa spesification dalam JavaEE 5 untuk membangun web service, antara lain :

1. Java API for XML-based Web Service 2.0 (JAX-WS 2.0), inti web service dan merupakan ekstensi dari JAX-RPC 1.0
2. Java API for XML Binding 2.0, binding dari WSDL ke Java.
3. WS Basic Profile 1.1, interoperability dengan .NET.
4. Web Services Metadata 2.0, pendekatan metadata untuk mendefinisikan web service.
5. Java API for XML-RPC 1.1, untuk kompatibility dengan JavaEE 1.4 web service.

Implementasi WS : POJO atau EJB3 Stateless Session Bean

Berikut perbandingan yang diberikan Debu Panda antara POJO web service dan EJB web service :


Implementasi EJB3 & JAX-WS 2.0

Membangun web service dengan EJB3 sesuai tabel di atas, memberikan lebih banyak keuntungan, dalam hal ini dari service-service yang ditawarkan oleh EJB container. Karena itu kita akan membahas web service dengan EJB3. Beberapa annotation yang digunakan dalam web service adalah sbb :

@WebService
Digunakan untuk memberitahu EJB container bahwa bean tersebut adalah sebuah web service. Annotation ini bisa diletakkan pada bean class atau interface. Jika diletakkan pada bean class maka EJB container akan men-generate-kan interfacenya.

@Remote
public interface BidManagerWS {...}

@Stateless
@WebService(targetNamespace="urn:edu/mat/test/webservice")
@SOAPBinding(style=SOAPBinding.Style.DOCUMENT)
public class BidManagerWSBean implements BidManagerWS {...}

selanjutnya saat deploy interface akan digenerate. Perhatikan bahwa interface yang dimaksud bukan interface session bean. Karena kita menggunakan session bean sebagai web service maka kita tetap menggunakan annotation @Remote dan @Stateless. Dan di bean class kita tambahkan annotation @WebService. Interface hasil generate saat deployment definitely bukan session interface di atas. Sebagai contoh berikut adalah interface yang dimaksud :

@WebService(name = "BidManagerWSBean", targetNamespace = "urn:edu/mat/test/webservice")
@XmlSeeAlso({
ObjectFactory.class
})
public interface BidManagerWSBean {...}

Interface hasil generate tersebut bisa digunakan client untuk berkomunikasi dengan web service kita.

@SOAPBinding
Seperti telah disebutkan pada entry sebelumnya bahwa service yang disupport adalah document-oriented dan RPC-oriented. Kita menggunakan annotation ini untuk mengontrol style web service.

@SOAPBinding(style=SOAPBinding.Style.DOCUMENT)
public class ItemManagerWSBean extends BaseStatelessSessionManager { ... }

atau

@SOAPBinding(style=SOAPBinding.Style.DOCUMENT)
public class BidManagerWSBean extends BaseStatelessSessionManager implements BidManagerWS { ... }

@WebMethod
Jika kita menggunakan @WebService pada interface, maka semua public method di interface tersebut akan menjadi methodnya web service. Jika kita menggunakan @WebService pada bean class maka kita harus menggunakan @WebMethod pada method yang diinginkan untuk menjadi method web service. Jika tidak, maka seluruh public method di class bean tersebut akan menjadi methodnya web service (sama seperti pada @WebService di interface).

Jika kita tidak menginginkan suatu public method menjadi methodnya web service maka gunakan : @WebMethod(exclude=true).

@WebMethod
public void deleteItem(String itemId) {...}

@WebParam
Digunakan untuk kustomisasi parameter web service. Nama parameter akan menjadi sama dengan nama pada @WebParam

public Item addItem(@WebParam(name="itemTitle") String itemTitle, @WebParam(name="itemDesc") String itemDesc) {...}

@WebResult
Digunakan untuk kustomisasi return value suatu method web service. Nama return value di WSDL akan menjadi sama dengan pada @WebResult ini

@WebMethod
@WebResult(name="item")
public Item addItem(@WebParam(name="itemTitle") String itemTitle) {...}

@OneWay
Digunakan pada method web service yang tidak memiliki return value alias void return value.

@WebMethod
@OneWay
public void pingServer() {...}

Sunday, April 19, 2009

Web Service Related Terminology

Ada beberapa pendekatan mengimplementasikan web service. Tiga yang paling banyak digunakan adalah Representational State Transfer (REST), XML-RPC, dan SOAP. Namun kebanyakan aplikasi enterprise menggunakan SOAP.

SOAP

Awalnya SOAP adalah kependekan dari "Simple Object Access Protocol". Tapi kemudian oleh W3C singkatan tersebut dihapus sehingga sekarang SOAP bukan singkatan dari apapun. Kini pengertian SOAP adalah protokol untuk pertukaran message berformat XML. Sebuah client web service mengirim request berbentuk XML kepada provider web service. Provider mem-parsing request tersebut, menjalankan service, dan mengirim response kembali ke client juga dalam bentuk XML. Baik request dan response tersebut keduanya menggunakan protokol SOAP.

WSDL

Web Service Description Language (WSDL) adalah sebuah dokumen XML yang menyediakan segala informasi yang diperlukan untuk menentukan lokasi dan cara mengakses web service. Provider web service lah yang bertanggung jawab membuat WSDL. WSDL juga mendeskripsikan message, tipe, return value, dan detil lain yang dimiliki web service.

UDDI

Konsep lain dalam teknologi web service adalah web service registry. Setelah membuat sebuah web service, provider bisa memilih untuk mempublikasikan dokumen WSDL pada sebuah registry. Registry tersebut bisa jadi milik organisasi provider web service atau milik pihak ketiga. Client yang berminat menggunakan web service akan mencari informasi tentang sebuah web service di direktori registry untuk menentukan lokasi sebuah web service dan mendapatkan WSDL-nya. Selanjutnya client menggunakan dokumen WSDL untuk membuat request ke web service. Kegiatan publish, searching, dan retrieve tersebut ditentukan oleh UDDI (Universal Description, Discovery, and Integration)

SOA

Perbedaan web service dan Service Oriented Architecture (SOA) adalah bahwa SOA merupakan sebuah rancangan/arsitektur sistem sedangkan web service adalah sebuah platform. SOA bisa diimplementasikan menggunakan teknologi untuk messaging seperti JMS atau remoting seperti RMI, namun yang paling populer adalah menggunakan web service.

Web service style

Ada dua tipe utama web service yaitu RPC-oriented dan document oriented.

Web service development style

Ada tiga cara membangun web service yaitu bottom-up, top-down, dan meet-in-the-middle. Bottom-up adalah cara yang paling populer digunakan.

Bottom-up digunakan jika sistem kita telah terlebih dahulu siap dan kemudian ada keputusan untuk membangun web service dari sistem yang sudah ada tersebut. Jadi bottom-up dilakukan dengan membuat WSDL dari class-class java yang sudah ada sekarang.

Top-down digunakan jika kita ingin membuat web service benar-benar dari awal. Cara ini dilakukan dengan membuat dokumen WSDL lebih dulu baru kemudian dibuat interface dan class-classnya.

Kedua cara tersebut biasanya sudah ada generatornya. Misal kita bisa men-generate dokumen WSDL dari class java maupun sebaliknya.

Cara yang ketiga yaitu meet-in-the-middle, dilakukan dengan membuat dokumen WSDL dan class-class implementasi bersamaan. Cara ini sulit dilakukan karena kita harus menjaga sinkronisasi antara keduanya.

Message-Driven Bean

Message-Driven Bean (MDB) adalah komponen EJB yang digunakan untuk berhubungan dengan asynchronous message sebagai consumer. MDB dikelola menggunakan pooling. Segera setelah message tiba di destination, container mengambil sebuah MDB dari pool untuk meng-handle-nya. Tidak seperti session bean, MDB tidak memiliki remote atau local business interface. MDB bisa digunakan untuk berbagai macam messaging teknologi seperti JMS dan JCA. MDB yang digunakan bersama JMS harus implements interface MessageListener (ingat interface yang punya method onMessage pada JMS?). Sama seperti stateless session bean, MDB memiliki dua callback method yaitu PostConstruct yang dipanggil setelah MDB dibuat, dan PreDestroy yang dipanggil sebelum MDB dihapus dari pool untuk didestroy. Pada MDB, kita biasanya tidak secara eksplisit menangani transaksi, melainkan kita menyerahkan urusan tersebut kepada container. Secara default, container memulai transaksi sebelum method onMessage dipanggil dan mengakhiri transaksi saat onMessage berakhir atau terjadi rollback melalui MessageDrivenContext.

Perhatikan contoh MDB berikut :

public class MessageReceiverMDB implements MessageListener {
@Resource
private MessageDrivenContext context;

public void onMessage(Message message) {
try {
ObjectMessage objectMessage = (ObjectMessage)message;
ShippingRequest shippingRequest = (ShippingRequest)objectMessage.getObject();
System.out.println(shippingRequest);
} catch (Exception e) {
e.printStackTrace();
context.setRollbackOnly();
}
}
}

Bagaimana jadinya jika message yg dikirim bukan bertipe ObjectMessage? Code di atas akan gagal dan melakukan rollback. Rollback berarti message yang sudah diambil akan dikembalikan ke destination (queue/topic). Dan selanjutnya MDB akan berusaha mengambil message tersebut lagi, kemudian gagal lagi. Maka terjadi looping yang terus menerus mengalami kegagalan yang sama. Karena itu sebaiknya pada onMessage tidak dilakukan rollback message sehingga method di atas sebaiknya menjadi :

public class MessageReceiverMDB implements MessageListener {
public void onMessage(Message message) {
try {
ObjectMessage objectMessage = (ObjectMessage)message;
ShippingRequest shippingRequest = (ShippingRequest)objectMessage.getObject();
System.out.println(shippingRequest);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Hal yang sama juga bisa terjadi jika kita tidak mendesain exception-handling dengan baik. Perhatikan code berikut :

public class MessageReceiverMDB implements MessageListener {
public void onMessage(Message message) {
try {
ObjectMessage objectMessage = (ObjectMessage)message;
ShippingRequest shippingRequest = (ShippingRequest)objectMessage.getObject();
System.out.println(shippingRequest);
} catch (JMSException e) {
e.printStackTrace();
}
}
}

Bagaimana jika terjadi exception selain JMSException? Misalnya RuntimeException, RemoteException, atau EJBException. Method onMessage di atas akan melempar exception yang tidak di-handling. Dan exception yang tidak di-handling menyebabkan transaction rollback. Jika transaction rollback, maka looping yang terus menerus mengalami kegagalan akan terus terjadi. Karena itu sebaiknya onMessage tidak melempar exception, sehingga kode di atas sebaiknya kembali menjadi :

public class MessageReceiverMDB implements MessageListener {
public void onMessage(Message message) {
try {
ObjectMessage objectMessage = (ObjectMessage)message;
ShippingRequest shippingRequest = (ShippingRequest)objectMessage.getObject();
System.out.println(shippingRequest);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Friday, April 17, 2009

Message-oriented middleware

Dulu saya pernah mendapat email dari teman bahwa sebuah software house terkemuka akan mengadakan training java. Salah satu isi training itu adalah tentang message-oriented middleware (MOM). Sempat bertanya-tanya juga dalam hati apakah yang dimaksud MOM tersebut. Dari namanya terlihat panjang dan kayaknya mengerikan :). Tapi hari ini saya baru tahu dari sebuah ebook bahwa message-oriented middleware itu adalah software yang memungkinkan asynchronous message antar sistem atau komponen. Software tersebut menyimpan message dari sender yang disebut producer, dan lokasi tempat penyimpanan message disebut destination. Dan komponen atau sistem lain yang menerima message itu disebut consumer.

Dan baru saya ngeh setelah tahu macam-macam message-oriented middleware yang termasuk IBM Web-Sphere MQ, TIBCO Rendezvous, SonicMQ, ActiveMQ, dan Oracle Advanced Queuing. Kenapa? Karena dulu pernah berada dalam sebuah tim project yang menggunakan ActiveMQ kekekeke... Ternyata JMS, fiuh.

Fuzzy

Perhatikan contoh-contoh berikut

1. The description of a human characteristics such as healthy.
2. The classification of patients as depressed.
3. The classification of certain objects as large.
4. The classification of people by age such as old.

Pada contoh-contoh di atas, terminologi seperti depressed, old, dan large adalah kabur dalam artian bahwa hal tersebut tidak bisa dengan jelas didefinisikan. Namun sebagai manusia, kita sering berhubungan dengan informasi-informasi tersebut dan mengunakannya untuk membuat keputusan. Terminologi tersebut sangat kontras dengan kata-kata seperti married, over 39 years old, atau under 6 feet tall.

Dalam matematika, kita terbiasa menggunakan himpunan untuk, katakanlah, bilangan integer. Tapi saat berbicara tentang himpunan depressed people, sulit untuk memutuskan apakah seseorang berada dalam himpunan tersebut atau tidak. Memaksa dengan menjawab ya atau tidak mungkin bisa dilakukan tapi akan ada informasi yang hilang yaitu seberapa besar kadar depresinya.

Membicarakan Fuzzy Logic berarti berbicara tentang degree. Sebagai contoh, bandingkan kedua kalimat berikut :

"BMG meramalkan bahwa peluang terjadinya hujan pada esok hari sebesar 50%."
"BMG mengatakan bahwa besok akan terjadi hujan deras."

Kalimat pertama adalah tentang teori kemungkinan atau probabilitas, bahwa besok bisa saja hujan. Tapi bisa juga tidak. Kemungkinannya sama. Sedangkan kalimat kedua mengatakan bahwa besok terjadi hujan, itu adalah fakta, dengan intensitas tertentu. Apakah hujan tersebut bisa disebut deras atau tidak itu tergantung kadarnya (dan opini). Fuzzy logic berhubungan dengan kadar (degree) terhadap sesuatu.

Jika Boolean logic hanya memiliki state 1 dan 0, maka Fuzzy logic punya range kontinyu antara 0 dan 1. Jadi sesuatu bisa setengah benar (0,5), hampir benar (0,9) atau hampir tidak benar (0,1).

Model matematika fuzzy diperkenalkan oleh Zadeh pada 1965. Profesor Zadeh ini beranggapan bahwa arti suatu kata dalam natural language adalah masalah degree. Jika kita memiliki dalil seperti John is young maka kita tidak selalu bisa mengatakan bahwa hal tersebut benar atau salah. Jika kita mengetahui bahwa umur John adalah x maka kebenarannya, atau lebih tepatnya kecocokan, dari x dengan young adalah masalah kadar (degree). Ini tergantung pemahaman kita terhadap young tersebut. Jika dalilnya diganti dengan John is under 22 years old dan kita tahu umur John, maka kita bisa memberi jawaban ya atau tidak (benar atau salah umur John di bawah 22 tahun). Jelas bahwa 18 dan 20 itu muda, tapi dengan sudut pandang yang bebeda 18 lebih muda daripada 20. Hal ini menjelaskan bahwa keanggotaan himpunan fuzzy tidak seharusnya dalam basis 0 ATAU 1, tapi ANTARA 0 DAN 1.

Berikut adalah contoh pemodelan fuzzy untuk young :




Contoh pemodelan yang lain :




Menggunakan contoh kedua di atas, jika kita memiliki nilai umur x adalah 20 maka dalil John is young adalah benar 100%. Jika x adalah 66 maka nilai Y(66) = (70-66)/20 = 0.2. Jadi nilai kemudaannya atau derajat kemudaannya adalah 0.2.

JMS Flashback

Hari ini coba-coba membaca kembali tentang JMS karena gak nyangkut-nyangkut saat googling Fuzzy Logic hahaha, cuman sekedar catatan saja buat pengingat kalau-kalau suatu hari nanti dibutuhkan.

Java Messaging Service (JMS) adalah teknologi Java yang digunakan untuk memroses asynchronous message. Ada dua mode yang digunakan yaitu point-to-point dan publish/subscribe. Pada mode point-to-point, producer mengirim message ke queue. Message yang dikirim hanya dibaca sekali oleh sebuah consumer. Setelah sebuah consumer membacanya, message dihapus dari queue. Ringkasnya, satu message = satu consumer. Consumer tidak harus sedang aktif saat message dikirim oleh producer.

Pada mode publish/subscribe, producer mengirim message ke sebuah topic di mana satu atau lebih consumer telah melakukan registrasi atau subscribe ke topic tersebut. Message akan tetap ada di topic tersebut sampai seluruh consumer yang telah subscribe membacanya. Jika consumer belum teregistrasi saat message dikirim maka consumer tidak bisa membaca message tersebut. Untuk membaca message dari sebuah topic, consumer harus aktif. JMS mengatasi hal ini dengan mengijinkan client untuk membuat durable subscription. Durable subscription dapat menerima message saat consumer tidak aktif (mirip queue) .

JMS tidak menjamin message yang diterima consumer berada pada urutan yang sesuai waktu dikirim producer. Ada dua macam tipe consumer. Synchronous dan Asynchronous consumer.

Synchronous consumer membaca message dari destination jika message ada di destination. Jika tidak ada message di destination maka consumer akan tetap looping selama limit waktunya belum tercapai menggunakan method MessageConsumer.receive(). Jika diberi parameter 0 maka akan menjadi limit tak berhingga a.k.a hidup selamanya.

Sedangkan Asynchronous consumer membaca message dari destination menggunakan MessageListener. MessageListener diregistrasikan pada MessageConsumer melalui method MessageConsumer.setMessageListener(MessageListener). MessageListener ini mirip event listener dimana jika message ada di destination maka JMS akan mengirim message dengan memanggil method onMessage pada listener.

Terminologi synchronous dan asynchronous consumer hanya berhubungan dengan cara sebuah consumer mengambil message, bukan cara JMS mengirim message. JMS mengirim message sesuai queue/topic seperti dijelaskan sebelumnya.

Backward Chaining

Tidak seperti forward-chaining yang digunakan untuk mendapatkan fakta-fakta baru, backward chaining menggunakan rule untuk menjawab pertanyaan tentang apakah sebuah consequence clause itu benar atau tidak.

Kita masih akan mengunakan rules yang sama seperti entry pada forward-chaining tapi kali ini dengan persoalan yang berbeda. Misalnya kita ingin mengetahui apakah vehicle benar sebuah Minivan, maka kita harus mencari dari rules tersebut yang memiliki consequence vehicle = Minivan, dan kita mendapat rule berikut :

Minivan : IF vehicleType = automobile
AND size = medium
AND num_doors = 3
THEN vehicle = Minivan

Dari situ diketahui bahwa untuk membuktikan vehicle = Minivan kita harus membuktikan bahwa vehicleType = automobile dan size = medium dan num_doors = 3.

Untuk membuktikan vehicleType = automobile kita harus mencari dari rules yang memiliki consequence tersebut dan kita mendapat :

Automobile : IF num_wheels = 4
AND motor = yes
THEN vehicleType = automobile

Selanjutnya untuk membuktikan bahwa vehicleType = automobile kita harus membuktikan bahwa num_wheels = 4 dan motor = yes. Karena pada rules yang kita miliki tidak terdapat consequence untuk num_wheels = 4, maka kita bisa menghentikan penelusuran atau meminta input dari user berapa nilai dari num_wheels. Begitu pula untuk motor = yes. Misalnya user telah memasukkan nilai untuk num_wheels dan motor adalah masing-masing '4' dan 'yes', maka kini kita memiliki tiga fakta baru yaitu

num_wheels = 4
motor = yes
vehicleType = automobile

yang sekaligus membuktikan bahwa vehicleType = automobile adalah benar. Selanjutnya kita harus membuktikan bahwa size = medium. Karena kita tidak memiliki rule yang mempunyai consequence size = medium, maka kita kembali harus meminta input dari user. Misal user memberikan nilai size adalah medium maka kini kita mempunyai fakta baru

num_wheels = 4
motor = yes
vehicleType = automobile
size = medium

Menuju antecedent berikutnya yaitu num_doors = 3, kita juga tidak mempunyai rule tersebut. Misalnya user memberikan input '3' untuk num_doors maka kini kita mempunyai fakta-fakta

num_wheels = 4
motor = yes
vehicleType = automobile
size = medium
num_doors = 3
vehicle = Minivan

yang sekaligus membuktikan bahwa vehicle adalah benar sebuah Minivan.

Thursday, April 16, 2009

Forward Chaining

Dalam reasoning system dengan IF-THEN rules, ada sebuah algoritma yang dikenal dengan nama Forward Chaining, untuk lebih jelas bagaimana algoritma ini bekerja sebaiknya diilustrasikan dengan contoh. Misal kita memiliki sembilan rules yang sudah didefinisikan sebelumnya seperti berikut

Vehicle Rule Base:

Bicycle :

IF vehicleType = cycle
AND num_wheels = 2
AND motor = no
THEN vehicle = Bicycle

Tricycle :

IF vehicleType = cycle
AND num_wheels = 3
AND motor = no
THEN vehicle = Tricycle

Motorcycle :

IF vehicleType = cycle
AND num_wheels = 2
AND motor = yes
THEN vehicle = Motorcycle

Sportscar :

IF vehicleType = automobile
AND size = small
AND num_doors = 2
THEN vehicle = Sports car

Sedan :

IF vehicleType = automobile
AND size = medium
AND num_doors = 4
THEN vehicle = Sedan

Minivan :

IF vehicleType = automobile
AND size = medium
AND num_doors = 3
THEN vehicle = Minivan

SUV :

IF vehicleType = automobile
AND size = large
AND num_doors = 4
THEN vehicle = Sports Utility Vehicle

Cycle :

IF num_wheels < 4
THEN vehicleType = cycle

Automobile :

IF num_wheels = 4
AND motor = yes
THEN vehicleType = automobile

Misalnya kita mempunyai fakta-fakta berikut :

num_wheels = 4
motor = yes
num_doors = 3
size = medium


kita ingin mengetahui fakta-fakta baru apa saja yang akan kita dapat dengan menelusuri Vehicle Rule di atas. Perhatikan bahwa kita menelusuri rule dari atas ke bawah (dari rule Bicycle ke rule Automobile).

Dengan fakta-fakta di atas, penelusuran kita jatuh pada rule Automobile. Dengan demikian kita mempunyai fakta baru yaitu vehicleType = automobile, dan fakta-fakta yang kini kita miliki adalah


num_wheels = 4
motor = yes
num_doors = 3
size = medium
vehicleType = automobile

Kemudian penelusuran berlanjut kembali ke awal dan jatuh pada rule Minivan. Dari rule ini kita kembali mendapatkan fakta baru yaitu vehicle = Minivan, dan kini kita memiliki fakta-fakta


num_wheels = 4
motor = yes
num_doors = 3
size = medium
vehicleType = automobile
vehicle = Minivan

Penelusuran kembali ke awal, dan karena sudah tidak ada lagi rule yang memenuhi, maka penelusuran berhenti dengan mendapatkan kesimpulan terakhir bahwa vehicle adalah sebuah Minivan.

Tapi bagaimana jika rule-rule tersebut overlap? Bagaimana jika ada rule yang merupakan subset dari rule lain? Karena itulah urut-urutan rule yang diproses menjadi penting. Dalam penelusuran, sebaiknya dipilih rule yang lebih spesifik daripada rule yang bersifat umum/general terlebih dahulu. Karena itulah rule yang bersifat spesifik selalu diletakkan pada bagian teratas Vehicle rule di atas.

Kaca Spion

Kaca Spion (Catatan Andy Noya)

Sejak bekerja saya tidak pernah lagi berkunjung ke Perpustakaan Soemantri Brodjonegoro di Jalan Rasuna Said, Jakarta . Tapi, suatu hari ada kerinduan dan dorongan yang luar biasa untuk ke sana . Bukan untuk baca buku, melainkan makan gado-gado di luar pagar perpustakaan. Gado-gado yang dulu selalu membuat saya ngiler. Namun baru dua tiga suap, saya merasa gado-gado yang masuk ke mulut jauh dari bayangan masa lalu. Bumbu kacang yang dulu ingin saya jilat sampai piringnya mengkilap, kini rasanya amburadul. Padahal ini gado-gado yang saya makan dulu. Kain penutup hitamnya sama. Penjualnya juga masih sama. Tapi mengapa rasanya jauh berbeda? malamnya, soal gado-gado itu saya ceritakan kepada istri. Bukan soal rasanya yang mengecewakan, tetapi ada hal lain yang membuat saya gundah.

Sewaktu kuliah, hampir setiap siang, sebelum ke kampus saya selalu mampir ke perpustakaan Soemantri Brodjonegoro. Ini tempat favorit saya. Selain karena harus menyalin bahan-bahan pelajaran dari buku-buku wajib yang tidak mampu saya beli, berada di antara ratusan buku membuat saya merasa begitu bahagia. Biasanya satu sampai dua jam saya di sana . Jika masih ada waktu, saya melahap buku-buku yang saya minati. Bau harum buku, terutama buku baru, sungguh membuat pikiran terang dan hati riang. Sebelum meninggalkan perpustakaan, biasanya saya singgah di gerobak gado-gado di sudut jalan, di luar pagar. Kain penutupnya khas, warna hitam. Menurut saya, waktu itu, inilah gado-gado paling enak seantero Jakarta . Harganya Rp 500 sepiring sudah termasuk lontong. Makan sepiring tidak akan pernah puas. Kalau ada uang lebih, saya pasti nambah satu piring lagi. Tahun berganti tahun. Drop out dari kuliah, saya bekerja di Majalah TEMPO sebagai reporter buku Apa dan Siapa Orang Indonesia . Kemudian pindah menjadi reporter di Harian Bisnis Indonesia . Setelah itu menjadi redaktur di Majalah MATRA. Karir sayaterus meningkat hingga menjadi pemimpin redaksi di Harian Media Indonesia dan Metro TV.

Sampai suatu hari, kerinduan itu datang. Saya rindu makan gado-gado di sudut jalan itu. Tetapi ketika rasa gado-gado berubah drastis, saya menjadi gundah. Kegundahan yang aneh. Kepada istri saya utarakan kegundahan tersebut. Saya risau saya sudah berubah dan tidak lagi menjadi diri saya sendiri. Padahal sejak kecil saya berjanji jika suatu hari kelak saya punya penghasilan yang cukup, punya mobil sendiri, dan punya rumah sendiri, saya tidak ingin berubah. Saya tidak ingin menjadi sombong karenanya.

Hal itu berkaitan dengan pengalaman masa kecil saya di Surabaya . Sejak kecil saya benci orang kaya. Ada kejadian yang sangat membekas dan menjadi trauma masa kecil saya. Waktu itu umur saya sembilan tahun. Saya bersama seorang teman berboncengan sepeda hendak bermain bola. Sepeda milik teman yang saya kemudikan menyerempet sebuah mobil. Kaca spion mobil itu patah.

Begitu takutnya, bak kesetanan saya berlari pulang. Jarak 10 kilometer saya tempuh tanpa berhenti. Hampir pingsan rasanya. Sesampai di rumah saya langsung bersembunyi di bawah kolong tempat tidur. Upaya yang sebenarnya sia-sia. Sebab waktu itu kami hanya tinggal di sebuah garasi mobil, di Jalan Prapanca. Garasi mobil itu oleh pemiliknya disulap menjadi kamar untuk disewakan kepada kami. Dengan ukuran kamar yang cuma enam kali empat meter, tidak akan sulit menemukan saya. Apalagi tempat tidur di mana saya bersembunyi adalah satu-satunya tempat tidur di ruangan itu. Tak lama kemudian, saya mendengar keributan di luar. Rupanya sang pemilik mobil datang. dengan suara keras dia marah-marah dan mengancam ibu saya. Intinya dia meminta ganti rugi atas kerusakan mobilnya.

Pria itu, yang cuma saya kenali dari suaranya yang keras dan tidak bersahabat, akhirnya pergi setelah ibu berjanji akan mengganti kaca spion mobilnya. Saya ingat harga kaca spion itu Rp 2.000. Tapi uang senilai itu, pada tahun 1970, sangat besar. Terutama bagi ibu yang mengandalkan penghasilan dari menjahit baju. Sebagai gambaran, ongkos menjahit baju waktu itu Rp 1.000 per potong. Satu baju memakan waktu dua minggu. Dalam sebulan, order jahitan tidak menentu. Kadang sebulan ada tiga, tapi lebih sering cuma satu. Dengan penghasilan dari menjahit itulah kami - ibu, dua kakak, dan saya - harus bisa bertahan hidup sebulan.

Setiap bulan ibu harus mengangsur ganti rugi kaca spion tersebut. Setiap akhir bulan sang pemilik mobil, atau utusannya, datang untuk mengambil uang. Begitu berbulan-bulan. Saya lupa berapa lama ibu harus menyisihkan uang untuk itu. Tetapi rasanya tidak ada habis-habisnya. Setiap akhir bulan, saat orang itu datang untuk mengambil uang, saya selalu ketakutan. Di mata saya dia begitu jahat. Bukankah dia kaya? Apalah artinya kaca spion mobil baginya? Tidakah dia berbelas kasihan melihat kondisi ibu dan kami yang hanya menumpang di sebuah garasi?

Saya tidak habis mengerti betapa teganya dia. Apalagi jika melihat wajah ibu juga gelisah menjelang saat-saat pembayaran tiba. Saya benci pemilik mobil itu. Saya benci orang-orang yang naik mobil mahal. Saya benci orang kaya.

Untuk menyalurkan kebencian itu, sering saya mengempeskan ban mobil-mobil mewah. Bahkan anak-anak orang kaya menjadi sasaran saya. Jika musim layangan, saya main ke kompleks perumahan orang-orang kaya. Saya menawarkan jasa menjadi tukang gulung benang gelasan ketika mereka adu layangan. Pada saat mereka sedang asyik, diam-diam benangnya saya putus dan gulungan benang gelasannya saya bawa lari. Begitu berkali-kali. Setiap berhasil melakukannya, saya puas. Ada dendam yang terbalaskan. Sampai remaja perasaan itu masih ada. Saya muak melihat orang-orang kaya di dalam mobil mewah. Saya merasa semua orang yang naik mobil mahal jahat. Mereka orang-orang yang tidak punya belas kasihan. Mereka tidak punya hati nurani.

Nah, ketika sudah bekerja dan rindu pada gado-gado yang dulu semasa kuliah begitu lezat, saya dihadapkan pada kenyataan rasa gado-gado itu tidak enak di lidah. Saya gundah. Jangan-jangan sayalah yang sudah berubah. Hal yang sangat saya takuti. Kegundahan itu saya utarakan kepada istri. Dia hanya tertawa. ''Andy Noya, kamu tidak usah merasa bersalah. Kalau gado-gado langgananmu dulu tidak lagi nikmat, itu karena sekarang kamu sudah pernah merasakan berbagai jenis makanan. Dulu mungkin kamu hanya bisa makan gado-gado di pinggir jalan. Sekarang, apalagi sebagai wartawan, kamu punya kesempatan mencoba makanan yang enak-enak. Citarasamu sudah meningkat,'' ujarnya. Ketika dia melihat saya tetap gundah, istri saya mencoba meyakinkan, "Kamu berhak untuk itu. Sebab kamu sudah bekerja keras." Tidak mudah untuk untuk menghilangkan perasaan bersalah itu. Sama sulitnya dengan meyakinkan diri saya waktu itu bahwa tidak semua orang kaya itu jahat. Dengan karir yang terus meningkat dan gaji yang saya terima, ada ketakutan saya akan berubah. Saya takut perasaan saya tidak lagi sensisitif. Itulah kegundahan hati saya setelah makan gado-gado yang berubah rasa. Saya takut bukan rasa gado-gado yang berubah, tetapi sayalah yang berubah. Berubah menjadi sombong.

Ketakutan itu memang sangat kuat. Saya tidak ingin menjadi tidak sensitif. Saya tidak ingin menjadi seperti pemilik mobil yang kaca spionnya saya tabrak. Kesadaran semacam itu selalu saya tanamkan dalam hati. Walau dalam kehidupan sehari-hari sering menghadapi ujian. Salah satunya ketika mobil saya ditabrak sepeda motor dari belakang. Penumpang dan orang yang dibonceng terjerembab. Pada siang terik, ketika jalanan macet, ditabrak dari belakang, sungguh ujian yang berat untuk tidak marah. Rasanya ingin melompat dan mendamprat pemilik motor yang menabrak saya. Namun, saya terkejut ketika menyadari yang dibonceng adalah seorang ibu tua dengan kebaya lusuh. Pengemudi motor adalah anaknya. Mereka berdua pucat pasi. Selain karena terjatuh, tentu karena melihat mobil saya penyok. Hanya dalam sekian detik bayangan masa kecil saya melintas. Wajah pucat itu serupa dengan wajah saya
ketika menabrak kaca spion.

Wajah yang merefleksikan ketakutan akan akibat yang harus mereka tanggung. Sang ibu, yang ecet-lecet di lutut dan sikunya, berkali-kali meminta maaf atas keteledoran anaknya. Dengan mengabaikan lukanya, dia berusaha meluluhkan hati saya. Setidaknya agar saya tidak menuntut ganti rugi. Sementara sang anak terpaku membisu. Pucat pasi. Hati yang panas segera luluh. Saya tidak ingin mengulang apa yang pernah terjadi pada saya. Saya tidak boleh membiarkan benih kebencian lahir siang itu. Apalah artinya mobil yang penyok berbanding beban yang harus mereka pikul. Maka saya bersyukur. Bersyukur pernah berada di posisi mereka. Dengan begitu saya bisa merasakan apa yang mereka rasakan. Setidaknya siang itu saya tidak ingin lahir sebuah benih kebencian. Kebencian seperti yang pernah saya rasakan dulu. Kebencian yang lahir dari pengalaman hidup yang pahit.

"My mom said man only need few rich, the remain is only for show up"

Tuhan Menciptakan Kejahatan?

Apakah Tuhan menciptakan segala yang ada?
Apakah kejahatan itu ada?
Apakah Tuhan menciptakan kejahatan?


Seorang Profesor dari sebuah universitas terkenal itu menantang mahasiswa-mahasiswa nya dengan pertanyaan ini, “Apakah Tuhan menciptakan segala yang ada?”.

Seorang mahasiswa dengan berani menjawab, “Betul, Dia yang menciptakan semuanya”.

“Tuhan menciptakan semuanya?” Tanya professor sekali lagi.

“Ya, Pak, semuanya” kata mahasiswa tersebut.

Profesor itu menjawab, “Jika Tuhan menciptakan segalanya, berarti Tuhan menciptakan Kejahatan. Karena kejahatan itu ada, dan menurut prinsip kita bahwa pekerjaan kita menjelaskan siapa kita, jadi kita bisa berasumsi bahwa Tuhan itu adalah kejahatan.”

Mahasiswa itu terdiam dan tidak bisa menjawab hipotesis professor tersebut. Profesor itu merasa menang dan menyombongkan diri bahwa sekali lagi dia telah membuktikan kalau agama itu adalah sebuah mitos.

Mahasiswa lain mengangkat tangan dan berkata, “Profesor, boleh saya bertanya sesuatu?”

“Tentu saja,” jawab si Profesor

Mahasiswa itu berdiri dan bertanya, “Profesor, apakah dingin itu ada?”

“Pertanyaan macam apa itu? Tentu saja dingin itu ada. Kamu tidak pernah sakit flu?” Tanya si professor diiringi tawa mahasiswa lainnya.

Mahasiswa itu menjawab, “Kenyataannya, Pak, dingin itu tidak ada. Menurut hukum fisika, yang kita anggap dingin itu adalah ketiadaan panas. Suhu -460F adalah ketiadaan panas sama sekali. Dan semua partikel menjadi diam dan tidak bisa bereaksi pada suhu tersebut. Kita menciptakan kata dingin untuk mendeskripsikan ketiadaan panas.

Mahasiswa itu melanjutkan, “Profesor, apakah gelap itu ada?” Profesor itu menjawab, “Tentu saja itu ada.”

Mahasiswa itu menjawab, “Sekali lagi anda salah, Pak. Gelap itu juga tidak ada. Gelap adalah keadaan dimana tidak ada cahaya. Cahaya bisa kita pelajari, gelap tidak. Kita bisa menggunakan prisma Newton untuk memecahkan cahaya menjadi beberapa warna dan mempelajari berbagai panjang gelombang setiap warna. Tapi Anda tidak bisa mengukur gelap.

Seberapa gelap suatu ruangan diukur dengan berapa intensitas cahaya diruangan tersebut. Kata gelap dipakai manusia untuk mendeskripsikan ketiadaan cahaya.”

Akhirnya mahasiswa itu bertanya, “Profesor, apakah kejahatan itu ada?” Dengan bimbang professor itu menjawab, “Tentu saja, seperti yang telah kukatakan sebelumnya. Kita melihat setiap hari di Koran dan TV. Banyak perkara kriminal dan kekerasan di antara manusia. Perkara-perkara tersebut adalah manifestasi dari kejahatan.”


Terhadap pernyataan ini mahasiswa itu menjawab, “Sekali lagi Anda salah, Pak. Kajahatan itu tidak ada. Kejahatan adalah ketiadaan Tuhan. Seperti dingin atau gelap, kejahatan adalah kata yang dipakai manusia untuk mendeskripsikan ketiadaan Tuhan. Tuhan tidak menciptakan kajahatan.

Kajahatan adalah hasil dari tidak adanya kasih Tuhan dihati manusia. Seperti dingin yang timbul dari ketiadaan panas dan gelap yang timbul dari ketiadaan cahaya.”

Profesor itu terdiam. Nama mahasiswa itu adalah Albert Einstein.

Wednesday, April 15, 2009

Logika

Logika matematika, pertama kali mengenalnya saat masih kelas 1 SMU. Hari ini ketemu lagi saat baca-baca buku kuliah AI (to tell the truth, sebenarnya cuman buka-buka sekilas, bukannya benar-benar dibaca hehehe). Ada satu yang membuat teringat lagi pada Logika Matematika yaitu saat membaca Knowledge Representation. Ada satu teknik yang digunakan untuk membuktikan apakah sebuah statement benar atau tidak, berdasarkan fakta-fakta lain yang diketahui, namanya resolution.

Untuk lebih jelasnya lebih baik digunakan contoh,

1. not feathers(Tweety) or bird(Tweety)

2. feathers(Tweety)

Di atas ada dua buah statement. Statement 1 mengatakan bahwa "baik Tweety tidak memiliki bulu atau Tweety adalah seekor burung". Statement 2 mengatakan bahwa Tweety memiliki bulu. Kita selalu menggunakan asumsi bahwa sebuah statement bernilai true, jadi :

1. (T) not feathers(Tweety) or bird(Tweety)

2. (T) feathers(Tweety)

Konsekuensi dari asumsi di atas adalah bahwa jika statement 2 true, maka not feathers(Tweety) bernilai false, jadi :

1. (T=F or X) not feathers(Tweety) or bird(Tweety)

2. (T) feathers(Tweety)

Seperti kita ketahui bahwa pada operasi OR, hanya akan menghasilkan true jika keduanya true atau salah satu operand bernilai true. Dalam hal ini karena operand not feathers(Tweety) bernilai false, maka bird(Tweety) bernilai true, sehingga :

1. (T=F or T) not feathers(Tweety) or bird(Tweety)

2. (T) feathers(Tweety)

Menyalahkan Sebenarnya Tidak Penting

Satu lagi kisah dari kaskus

'MENYALAHKAN SEBENARNYA TIDAK PENTING'

Aku baru masuk kuliah saat bertemu dengan Keluarga White. Mereka sangat berbeda dengan keluargaku, namun aku langsung merasa betah bersama mereka. Aku dan Jane White berteman di sekolah, dan keluarganya menyambutku, yg notabene orang luar, layaknya sepupu jauh.

Dalam keluargaku, jika ada masalah, menyalahkan orang itu selalu penting. 'Siapa yang melakukan ini?' ibuku membentak melihat dapur berantakan. 'lni semua salahmu, Katharine,' ayahku berkeras jika kucing berhasil keluar rumah atau mesin cuci piring rusak.

Sejak kami kecil, aku dan saudara-saudaraku saling mengadu. Kami menyiapkan kursi untuk si Terdakwa di meja makan. Tapi Keluarga White tidak mencemaskan siapa berbuat apa. Mereka merapikan yang berantakan dan melanjutkan hidup mereka.

lndahnya hal ini kusadari penuh pada musim panas ketika Jane meninggal.

Keluarga White memiliki enam anak: tiga lelaki, tiga perempuan. Satu putranya meninggal saat masih kecil, mungkin karena itulah kelima yang tersisa menjadi dekat.

Di bulan Juli, aku dan tiga putri White memutuskan berjalan-jalan naik mobil dari rumah mereka di Florida ke New York. Dua yang tertua, Sarah dan Jane, adalah mahasiswa, dan yang terkecil, Amy, baru menginjak enam belas tahun. Sebagai pemilik SIM baru yang bangga, Amy gembira ingin melatih keterampilan mengemudinya selama perjalanan itu. Dengan tawanya yang lucu, ia memamerkan SIM-nya kepada siapa saja yang ditemuinya.

Kedua kakaknya ikut mengemudikan mobil pada bagian pertama perjalanan, tapi saat mereka tiba di daerah yang berpenduduk jarang, mereka membolehkan Amy mengemudi. Di suatu tempat di South Carolina , kami keluar dari jalan tol untuk makan. Setelah makan, Amy mengemudi lagi. Ia tiba di perempatan dengan tanda stop untuk mobil dari arah kami. Entah ia gugup atau tidak memperhatikan atau tidak melihat tandanya tak akan ada yang tahu. Amy terus menerjang perempatan tanpa berhenti. Pengemudi trailer semi-traktor besar itu tak mampu mengerem pada waktunya, dan menabrak kendaraan kami. Jane langsung meninggal.

Aku selamat hanya dengan sedikit memar. Hal tersulit yang kulakukan adalah menelepon Keluarga White dan memberitakan kecelakaan itu dan bahwa Jane meninggal. Sesakit apa pun perasaanku kehilangan seorang sahabat, aku tahu bagi mereka jauh lebih pedih kehilangan anak.

Saat suami-istri White tiba di rumah sakit, mereka mendapatkan dua putri mereka di sebuah kamar. Kepala dibalut perban; kaki Amy digips. Mereka memeluk kami semua dan menitikkan air mata duka dan bahagia saat melihat putri mereka. Mereka menghapus air mata kedua putrinya dan menggoda Amy hingga tertawa sementara ia belajar menggunakan kruknya.

Kepada kedua putri mereka, dan terutama kepada Amy, berulang-ulang mereka hanya berkata, 'Kami gembira kalian masih hidup.'

Aku tercengang.

Tak ada tuduhan.

Tak ada tudingan.

Kemudian, aku menanyakan Keluarga White mengapa mereka tak pernah membicarakan fakta bahwa Amy yang mengemudi dan melanggar rambu-rambu lalu lintas. Bu White berkata, 'Jane sudah tiada, dan kami sangat merindukannya. Tak ada yang dapat kami katakan atau perbuat yang dapat menghidupkannya kembali. Tapi hidup Amy masih panjang. Bagaimana ia bisa menjalani hidup yang nyaman dan bahagia jika ia merasa kami menyalahkannya atas kematian kakaknya?'

Mereka benar. Amy lulus kuliah dan menikah beberapa tahun yang lalu. Ia bekerja sebagai guru sekolah anak luar biasa. Putrinya sendiri sudah dua, yang tertua bernama Jane.

Aku belajar dari Keluarga White bahwa menyalahkan sebenarnya tidak penting. Bahkan, kadang-kadang, tak ada gunanya sama sekali.

Forgiveness does not change the past, but it does enlarge
the future. (Paul Boese)

Tuesday, April 14, 2009

Breadth-First & Depth-First Search

Dulu saat masih kuliah, ada beberapa mata kuliah yang mengajarkan algoritma searching seperti Kecerdasan Buatan, Algoritma & Struktur Data, juga Desain & Analisa Algoritma. Ketiganya juga membahas dua buah algoritma searching yaitu Breadth-First Search dan Depth-First Search.

Saat hari ini saya membuka-buka kembali buku-buku kuliah, saya kembali teringat kedua algoritma tersebut (walaupun dulunya juga tidak begitu perduli ada algoritma ini itu). Benar juga, selama ini jika dihadapkan dengan masalah-masalah yang berhubungan dengan searching tree saya tidak pernah menerapkan algoritma-algoritma yang dulu saya pelajari saat kuliah. Kebanyakan adalah menggunakan ide dan pemikiran yang muncul saat menghadapi persoalan-persoalan tersebut.

Setelah membaca beberapa halaman buku kuliah yang iseng-iseng saya buka tersebut (baca-baca lagi karena dulu amat sangat jarang membuat catatan hehehe...), terlintas kembali bagaimana logika algoritma tersebut. Untuk menyederhanakannya sebaiknya kita gunakan contoh tree berikut

Misalkan kita ingin mencari apakah ada path dari A menuju G. Node - node mana saja yang akan kita lewati? Kita akan menggunakan sebuah list yang berisi node-node yang dilewati oleh algoritma searching tersebut.

Pada saat awal, list akan berisi node awal yaitu A, {A}. Selanjutnya dari node A akan menuju node B dan C, jangan lupa menghapus node A dari list karena telah digantikan oleh node B dan C, {B, C}. Selanjutnya adalah menghapus B dari list dan menggantinya dengan node D dan E, {C, D, E}. Ingat bahwa breadth-first memperlakukan node yang memiliki depth terendah lebih dulu sehingga D dan E diletakkan setelah C karena D dan E memiliki depth 3 sedangkan C memiliki depth 2 (sama dengan B). Selanjutnya kita menghapus C dan menggantinya dengan F dan G sehingga list akan berisi {D, E, F, G}. Akhirnya node G ditemukan juga dan membuat searching berakhir dengan sukses.

Bagaimana jika menggunakan depth-first search? Pertama kali list berisi node A, {A}. Kemudian A dihapus dari list dan diganti dengan B dan C, {B, C}. Selanjutnya B diganti dengan D dan E dengan meletakkan keduanya di depan (kebalikan breadth-first), {D, E, C}. Karena D dan E berupa leaf maka keduanya bisa dhapus dari list sehingga tersisa C, {C}. Kemudian node C diganti dengan F dan G, {F, G}. Node G ditemukan dan proses searching berakhir dengan sukses.

Jika digambarkan, maka urut-urutan node mana yang diproses terlebih dahulu pada breadth-first search akan terlihat seperti berikut

Sedangkan jika menggunakan depth-first search akan terlihat urut-urutan node yang diproses seperti berikut

Monday, April 13, 2009

Mutable & Immutable

Hari ini saya membaca ebook tentang JAAS dan pada salah satu sub bab dijelaskan mengenai sebuah class yang immutable. Mutable dan immutable pertama kali saya pelajari saat dulu mengambil sertifikasi java, tapi kok tumben masih ingat sampai sekarang hehehe...

Waktu itu contoh yang paling gampang adalah class String. String termasuk immutable karena sekali dibuat maka state string tersebut tidak dapat diubah. Termasuk jika kita menggabung dua string melalui method String.concat() misalnya. Karena cukup penasaran mengapa hal itu bisa terjadi maka saya lihat source method String.concat() tersebut. Ternyata cukup mudah dipahami, method tersebut mengembalikan sebuah nilai string baru lewat salah satu konstruktor yang dimiliki String. Berikut adalah isi method String.concat()

public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char buf[] = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}

Dengan demikian jika kita menginginkan class yang kita buat menjadi immutable caranya cukup mudah : pastikan tidak ada satu method atau variabel pun yang bisa dipanggil untuk mengubah state object tersebut. Jika method yang kita buat memiliki return value berupa class yang sama dengan class yang immutable tersebut, maka kita bisa mengakalinya seperti String.concat() tersebut, yaitu memberikan return value berupa new object. Untuk variabel, sebaiknya mengikuti aturan java bean, yaitu dengan membuat private variabel dan memiliki method getter-setter untuk mengakses variabel tersebut. Karena class yang kita inginkan immutable, maka kita tidak perlu memiliki setter. Untuk mengeset nilai variabel bisa kita lakukan dengan memiliki konstruktor yang mengeset nilai variabel-variabel tersebut. Pastikan juga tidak ada method lain yang bisa mengubah nilai variabel tersebut selain konstruktor.

Autentifikasi Menggunakan JAAS Configuration Class

Menggunakan file teks untuk melakukan konfigurasi pada proses autentifikasi dengan JAAS seperti pada contoh berikut

SimpleLoginContext
{
edu.mat.jaas.SimpleLoginModule REQUIRED;
};


membutuhkan argumen -Djava.security.auth.login.config=nama_file.config saat runtime. Untuk menghindarinya, kita bisa memanfaatkan database untuk menggantikan fungsi file teks tersebut. Berikut adalah contoh tabel app_configuration untuk menggantikan isi file tersebut

CREATE TABLE app_configuration (
login_module_class text NOT NULL,
control_flag text,
app_name text NOT NULL
);
ALTER TABLE ONLY app_configuration
ADD CONSTRAINT "APP_CONFIGURATION_PK" PRIMARY KEY (app_name, login_module_class);

Selanjutnya yang perlu dibuat adalah tabel principal yang digunakan untuk menyimpan principal-principal yang aplikasi kita miliki, serta tabel db_user untuk meyimpan user yang menggunakan aplikasi dan yang akan kita autentifikasi tentunya

CREATE TABLE principal (
principal_name text NOT NULL,
principal_class text
);
ALTER TABLE ONLY principal
ADD CONSTRAINT "PRINCIPAL_PK" PRIMARY KEY (principal_name);

CREATE TABLE db_user (
username text NOT NULL,
phone text,
address text,
passwd text
);
ALTER TABLE ONLY db_user
ADD CONSTRAINT "DB_USER_PK" PRIMARY KEY (username);

Seperti telah dijelaskan sebelumnya bahwa satu user/subject bisa memiliki lebih dari satu role/principal, dan sebuah principal/role bisa berasosiasi dengan lebih dari satu user/subject, maka relasi db_user dengan principal adalah many to many. Dengan demikian, data model akan memunculkan sebuah tabel baru principal_db_user dengan struktur seperti berikut

CREATE TABLE principal_db_user (
principal_name text NOT NULL,
username text NOT NULL
);
ALTER TABLE ONLY principal_db_user
ADD CONSTRAINT "PK" PRIMARY KEY (principal_name, username);
ALTER TABLE ONLY principal_db_user
ADD CONSTRAINT "FK1" FOREIGN KEY (principal_name) REFERENCES principal(principal_name);
ALTER TABLE ONLY principal_db_user
ADD CONSTRAINT "FK2" FOREIGN KEY (username) REFERENCES db_user(username);

Setelah data model selesai dibuat, bagaimana menghubungkannya dengan JAAS? Jawabannya ada pada class abstract Configuration. Kita bisa membuat sebuah class yang extends Configuration dan implements method getAppConfigurationEntry() untuk mendapatkan LoginModule dari tabel app_configuration. Berikut adalah contoh class yang dimaksud

public class DbConfiguration extends Configuration {
static private DbConfiguration dbConfig;

static public void init() {
dbConfig = new DbConfiguration();
Configuration.setConfiguration(dbConfig);
}

static public DbConfiguration getDbConfiguration() {
return dbConfig;
}

public AppConfigurationEntry[] getAppConfigurationEntry(String applicationName) {
...
String sql = "SELECT login_module_class, control_flag FROM app_configuration WHERE app_name=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, applicationName);
ResultSet rs = pstmt.executeQuery();
List entries = new ArrayList();
while (rs.next()) {
String loginModuleClass = rs.getString("login_module_class");
String controlFlagValue = rs.getString("control_flag");
AppConfigurationEntry.LoginModuleControlFlag controlFlag = resolveControlFlag(controlFlagValue);
AppConfigurationEntry entry = new AppConfigurationEntry(loginModuleClass, controlFlag, new HashMap());
entries.add(entry);
}

return (AppConfigurationEntry[]) entries
.toArray(new AppConfigurationEntry[entries.size()]);
} catch (SQLException e) {
...
}
}

public void refresh() {

}

static LoginModuleControlFlag resolveControlFlag(String name) {
...
if ("REQUIRED".equals(uppedName)) {
return LoginModuleControlFlag.REQUIRED;
} else if ("REQUISITE".equals(uppedName)) {
return LoginModuleControlFlag.REQUISITE;
} else if ("SUFFICIENT".equals(uppedName)) {
return LoginModuleControlFlag.SUFFICIENT;
} else if ("OPTIONAL".equals(uppedName)) {
return LoginModuleControlFlag.OPTIONAL;
} else {
...
}
}
}

Kemudian bagaimana cara menggunakan class yang baru saja kita buat ini? Kita bisa mengeset konfigurasi global dengan cara DbConfiguration.init();. Dengan demikian aplikasi kita akan menggunakan konfigurasi yang sama yaitu DbConfiguration. Berikut contoh main() method

String appName = "
SimpleLoginContext";
// set Configuration
DbConfiguration.init();

// create callback handler
DbCallbackHandler callbackHandler = new DbCallbackHandler();
callbackHandler.setName(username);
callbackHandler.setPassword(password);

LoginContext ctx = new LoginContext(appName, callbackHandler);
...

Wednesday, April 8, 2009

Simple JAAS Example

Dalam 2 entry sebelumnya saya sudah tahu bagaimana caranya mengimplementasikan policy & permission, serta Subject dan Principal. Sekarang bagaimana mengimplementasikannya di JAAS untuk membentuk sebuah sistem security sederhana?

Seperti kepanjangannya, JAAS digunakan untuk autentifikasi dan autorisasi. Autentifikasi adalah proses yang memastikan bahwa user 'yang mengaku sebagai scott' adalah benar 'scott' yang dimaksud oleh sistem kita. Agar bisa diautentifikasi, user 'yang mengaku sebagai scott' harus memasukkan credential, biasanya berupa username dan password, untuk dicocokkan dengan data user scott yang kita miliki. Pada JAAS, sebuah interface bernama CallbackHandler digunakan untuk mendapatkan data-data credential tersebut dari user, dan sebuah interface LoginModule digunakan untuk melakukan autentifikasi (masih ingat method LoginModule.commit() pada entry sebelumnya?).

Sedangkan autorisasi adalah proses untuk memastikan bahwa user yang sudah sukses diautentifikasi sebelumnya hanya dapat mengakses resource yang berhak diaksesnya saja. Subject.doAsPrivileged adalah method yang digunakan untuk tujuan ini.

Sekarang akan kita lihat implementasi CallbackHandler dan LoginModule serta bagaimana memanggilnya dari aplikasi kita :

public class SimpleCallbackHandler implements CallbackHandler{
private String name;
private String password;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i <>
Callback callback = callbacks[i];
if (callback instanceof NameCallback) {
NameCallback nameCB = (NameCallback) callback;
nameCB.setName(name);
} else if (callback instanceof PasswordCallback) {
PasswordCallback passwordCB = (PasswordCallback) callback;
passwordCB.setPassword(password.toCharArray());
}
}
}
}

public class SimpleLoginModule implements LoginModule {
private Subject subject;
private CallbackHandler callbackHandler;
private String name;
private String password;

public boolean abort() throws LoginException {
...
}

public boolean commit() throws LoginException {
if ("scott".equals(name)) {
Principal p = new SysAdminPrincipal(name);
subject.getPrincipals().add(p);
return true;
} else if ("matt".equals(name)) {
Principal p = new UserPrincipal(name);
subject.getPrincipals().add(p);
return true;
} else {
return false;
}
}

public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
this.callbackHandler = callbackHandler;
this.subject = subject;
}

public boolean login() throws LoginException {
NameCallback nameCB = new NameCallback("Username");
PasswordCallback passwordCB = new PasswordCallback("Password", false);
Callback[] callbacks = new Callback[] { nameCB, passwordCB };
try {
callbackHandler.handle(callbacks);
} catch (IOException e) {
e.printStackTrace();
LoginException ex = new LoginException("IOException logging in.");
ex.initCause(e);
throw ex;
} catch (UnsupportedCallbackException e) {
String className = e.getCallback().getClass().getName();
LoginException ex = new LoginException(className + " is not a supported Callback.");
ex.initCause(e);
throw ex;
}
name = nameCB.getName();
password = String.valueOf(passwordCB.getPassword());
if ("scott".equals(name) && "tiger".equals(password)) {
// login in scott
return true;
} else if ("matt".equals(name) && "butterfly".equals(password)) {
// login in matt
return true;
} else {
return false;
}
}

public boolean logout() throws LoginException {
...
}
}

dan berikut adalah main method untuk melakukan autentifikasi dan autorisasi

public static void main(String[] args) {
policyFile = new File("file:/root/workspace/JAAS/config/security.policy");

testAccess("scott", "tiger");
testAccess("matt", "butterfly");
}

private static void testAccess(final String username, String password) {
SimpleCallbackHandler cb = new SimpleCallbackHandler();
cb.setName(username);
cb.setPassword(password);

// ambil login context dari configuration file untuk ambil login module mana yg diload
LoginContext ctx = null;
try {
ctx = new LoginContext("SimpleLoginContext", cb);
ctx.login();
} catch(Exception e) {
e.printStackTrace();
}

// jika login sukses maka bisa didapatkan subjectnya
Subject subject = ctx.getSubject();
System.out.println("Logged in " + subject);
// Create privileged action block which limits permissions to only the Subject's permissions.
try {
Subject.doAsPrivileged(subject, new PrivilegedAction() {
public Object run() {
policyFile.canRead();
System.out.println(username + " can access Policy file.");
return null;
}
}, null);
} catch (SecurityException e) {
System.out.println(username + " can NOT access Policy file.");
} catch(Exception e) {
}
}

Seperti terlihat pada method testAccess(), di sana hanya ada CallbackHandler yang dimasukkan sebagai parameter LoginContext, tidak tampak SimpleLoginModule sebagai implementasi LoginModule. Lalu bagaimana keduanya berhubungan? Selain mempunyai parameter CallbackHandler, LoginContext di atas mempunyai satu parameter lagi yaitu "SimpleLoginContext". SimpleLoginContext berada pada file konfigurasi yang akan kita buat yaitu jazz.config :

SimpleLoginContext
{
edu.mat.jaas.SimpleLoginModule REQUIRED;
};

Sekarang terlihat jelas di situlah LoginModule yang kita cari berada. Dan sekarang setelah proses autentifikasi selesai, saatnya melakukan autorisasi melalui

Subject.doAsPrivileged(subject, new PrivilegedAction() {
public Object run() {
policyFile.canRead();
System.out.println(username + " can access Policy file.");
return null;
}
}, null);

Seperti contoh pada entry sebelumnya, kita perlu membuat file policy yang berisi

grant Principal edu.mat.jaas.UserPrincipal "matt"
{
// not granted anything
};

grant Principal edu.mat.jaas.SysAdminPrincipal "scott"
{
permission java.io.FilePermission "file:/root/workspace/JAAS/config/security.policy", "read";
};

grant codeBase "file:/root/workspace/JAAS/build/*"
{
permission javax.security.auth.AuthPermission "modifyPrincipals";
permission javax.security.auth.AuthPermission "modifyPublicCredentials";
permission javax.security.auth.AuthPermission "modifyPrivateCredentials";
permission javax.security.auth.AuthPermission "createLoginContext.*";
permission javax.security.auth.AuthPermission "doAs";
permission javax.security.auth.AuthPermission "doAsPrivileged";
permission java.security.SecurityPermission "setPolicy";
permission java.security.SecurityPermission "getPolicy";
permission java.lang.RuntimePermission "accessClassInPackage.sun.security.provider";
permission java.lang.RuntimePermission "getProtectionDomain";
};

Untuk menjalankan contoh di atas, tambahkan baris berikut saat run -Djava.security.manager -Djava.security.policy=security.policy -Djava.security.auth.login.config=jazz.config
 

©2009 Stay the Same | by TNB