Living life and Make it Better

life, learn, contribute

Endy Muhardin

Software Developer berdomisili di Jabodetabek, berkutat di lingkungan open source, terutama Java dan Linux.

Lowongan Programmer

Di tempat saya bekerja saat ini (BaliCamp), saya sedang membutuhkan anggota tim. Tidak butuh yang terlalu canggih, saya justru cari fresh graduate. Nantinya kandidat yang lolos akan ditempatkan di tim saya, mengembangkan aplikasi untuk mengelola software development process.

Ada banyak nilai tambah yang bisa diperoleh dari pekerjaan ini, selain tentunya gaji dan fasilitas standar seperti layaknya karyawan lainnya. Biar saya jelaskan sedikit.

Pertama, yang akan kita buat di sini adalah aplikasi manajemen proyek yang spesifik untuk software development. Artinya, kita nanti akan melihat secara langsung bagaimana proyek software dikelola dengan mengikuti kaidah CMMI. Pengetahuan yang selama ini hanya dipelajari (sambil ngantuk) di kelas tentang RUP, XP, Waterfall, dsb akan dilihat langsung implementasinya di lapangan. Dan dibuatkan softwarenya. Jadi, dengan membuat aplikasi ini, kita jadi memahami bagaimana best-practices dalam pengelolaan proyek.

Kedua, kita akan bekerja dengan menggunakan Spring Framework dan Hibernate. Ini adalah dua framework utama dalam dunia Java. Anggota tim (yang nota bene adalah fresh graduate) akan mengikuti training tentang kedua teknologi ini. Saya sendiri yang akan memberikan trainingnya.

Ketiga, dalam proses pembuatan aplikasi ini, kita akan menggunakan teknologi tercanggih yang tersedia di dunia open source. Kita akan menyimpan source-code dan dokumentasi proyek dalam Subversion. Semua best-practices yang saya tulis di buku Subversion akan diimplementasikan dalam proyek. Issue atau bug akan dikelola dengan bug tracker. Testing akan dilakukan di segala lini, sesuai dengan artikel yang pernah saya tulis di sini, sini, sini, dan sini. Secara harian, CruiseControl akan mengambil semua source code terbaru dan melakukan daily build. Singkatnya, semua persenjataan proyek akan kita gunakan secara optimal.

Jangan khawatir kalau merasa asing dengan berbagai teknologi tersebut. Akan ada sesi training khusus untuk itu. Lagi-lagi saya yang akan memberikan trainingnya.

Baiklah, sekarang apa persyaratannya?

Pelanggan blog ini tentunya sudah tahu kalau saya sangat pemilih dalam menentukan anggota tim. Jadi, persiapkan diri dengan baik.

Tidak seperti lowongan lainnya yang biasa Anda lihat di milis atau portal tenaga kerja, saya tidak mempermasalahkan latar belakang pendidikan. SMU ke atas boleh daftar. IPK Anda Tiarap?? Jangan khawatir, silahkan layangkan lamaran Anda. Tidak akan didiskriminasi.

Persyaratan yang wajib dimiliki oleh peminat adalah:

  1. Konsep dasar OOP

  2. Dasar-dasar Java

  3. Pernah menggunakan minimal 2 (dua) bahasa pemrograman

  4. Konsep struktur data, misalnya tree, list

  5. Konsep relasional termasuk join dan subquery

  6. Mengerti SQL untuk minimal satu produk database

  7. HTML dan CSS

  8. Dasar-dasar jaringan komputer

  9. Bahasa Inggris (minimal membaca)

  10. Pernah membuat minimal satu aplikasi utuh (dari tampilan depan sampai ke database, lengkap dengan validasi) dengan minimal 4 (empat) tabel yang berelasi.

Seperti layaknya lowongan pekerjaan yang lain, ada beberapa hal yang masuk kategori lebih diutamakan bila menguasai atau dalam istilah programmer, nice to have. Berikut daftarnya:

  • Bisa menulis Ant buildfile

  • Memiliki personal website (blog)

  • Sehari-hari menggunakan Linux

Lokasi kerja saat ini di Menara Dea, Kawasan Mega Kuningan, 10 menit berjalan kaki dari Mal Ambassador. Ada sedikit kemungkinan tim akan pindah ke Desa Sigma di German Centre, Bumi Serpong Damai.

Berminat?? Silahkan klik Compose New Mail di aplikasi email Anda, dan attach resume dalam format PDF. Kemudian kirimkan ke endy [at] artivisi [dot] com atau emuhardin [at] balicamp [dot] com.

Bila resume Anda meyakinkan, saya akan panggil untuk interview. Siapkan aplikasi yang pernah dibuat dalam CD, paket sedemikian rupa sehingga mudah diinstal. Sertakan semua file yang dibutuhkan. Nantinya saya akan sediakan PC kosong yang hanya berisi sistem operasi agar Anda bisa mendemokan aplikasi tersebut.

Kalau ada pertanyaan, silahkan langsung posting komentar di bawah tulisan ini.


Remoting dengan Spring

Aplikasi yang kita buat, tidak hanya digunakan oleh manusia. Ada kalanya aplikasi yang kita buat akan diakses oleh aplikasi orang lain. Jadi, user atau pengguna aplikasi kita bukanlah orang, melainkan mesin. Dalam hal ini, aplikasi kita dapat disebut dengan aplikasi server yang menyediakan service bagi aplikasi client.

Bagaimana caranya agar aplikasi kita dapat digunakan oleh aplikasi lain? Caranya tentunya dengan menyediakan antarmuka yang sesuai bagi masing-masing aplikasi client. Ada banyak bahasa yang dijadikan patokan dalam komunikasi antar aplikasi. Beberapa protokol yang umum digunakan adalah:

  • CORBA

  • RMI (khusus Java)

  • SOAP

  • XML-RPC

  • Hessian

  • Burlap

  • dan masih banyak yang lainnya

Dengan cara tradisional, menyediakan antarmuka untuk masing-masing protokol ini cukup rumit. Selain harus mengerti protokolnya, kita juga harus menulis banyak kode untuk memformat data kita mengikuti aturan yang ditetapkan protokol tersebut. Kita juga harus menulis kode program agar dapat menerima data dalam protokol yang kita ingin sediakan.

Spring Framework menyediakan library pembantu bagi kita agar kita dapat menyediakan akses dalam protokol tersebut dengan mudah. Bagaimana caranya, mari kita bahas dalam artikel ini.

Sebagai contoh sederhana, misalnya kita ingin menyediakan layanan untuk mengambil data Person. Untuk menyederhakan masalah, Person hanya mengandung data nama dan email saja.

Person.java

package tutorial.remoting;

public class Person implements java.io.Serializable {
    private String name;
    private String email;
    
    public Person() {
        this("", "");
    }
    
    public Person(String name, String email){
        this.name = name;
        this.email = email;
    }
    
    public String getName(){
        return name;
    }
    
    public String getEmail(){
        return email;
    }
    
    public String toString(){
        return name + " : " + email;
    }
}

Perhatikan bahwa kita harus mendefinisikan Person sebagai object yang Serializable. Ini penting agar object ini bisa ditransfer melalui jaringan.

Kemudian, kita sediakan interface yang mendefinisikan layanan yang ingin kita sediakan bagi aplikasi lain. Kita sebut saja interface ini sebagai PersonService.

PersonService.java

package tutorial.remoting;

import java.util.List;
 
public interface PersonService {    
    public Person get(int id);
    public List getAllPerson();
} 

PersonService ini nantinya bisa kita implementasi sesuai dengan kebutuhan. Kita bisa mengambil datanya dari database, dari phonebook handphone, atau bahkan dari aplikasi lain. Agar contoh kodenya lebih sederhana, kita buat saja implementasinya dengan ArrayList. Para pembaca nanti bisa mencoba dengan implementasi lain yang lebih hi-tech seperti Hibernate atau OpenJPA.

Berikut adalah implementasi dari PersonService, kita sebut saja PersonServiceImpl.

PersonServiceImpl.java

package tutorial.remoting.remote;

import java.util.List;
import java.util.ArrayList;

import tutorial.remoting.Person;
import tutorial.remoting.PersonService;

public class PersonServiceImpl implements PersonService {

    private List allPerson = new ArrayList();
    
    public PersonServiceImpl(){
        Person p = new Person("Endy Muhardin", "endy@artivisi.com");
        Person p1 = new Person("Maya Mujawati", "moedja@yahoo.com");
        allPerson.add(p);
        allPerson.add(p1);
    }
    
    public Person get(int id){
        if (id >= allPerson.size()) return null;
        return (Person) allPerson.get(id);
    }

    public List getAllPerson(){
        return allPerson;
    }
} 

Seperti kita lihat di atas, tidak ada yang istimewa dengan kode program di atas. Bahkan validasi untuk field id pun tidak kita sediakan. Tentu saja kalau kita berikan masukan angka 2 atau lebih pada method public Person get(int id) akan terjadi ArrayIndexOutOfBoundException.

Selesai sudah … sekarang kode tersebut dapat diakses oleh aplikasi lain.

Apa?? Saya mendengar ada suara-suara kurang puas dari penonton.. Coba lebih keras??

Bagaimana cara mengaksesnya dari aplikasi client? Nampaknya belum ada kode program apa-apa untuk menyediakan layanan webservice. Mana bisa dibilang selesai?

Ok .. baiklah, memang ada satu langkah lagi. Yaitu mempublikasikan interface tersebut agar bisa diakses orang banyak. Kita akan sediakan akses melalui tiga protokol, yaitu:

  1. RMI

  2. Hessian

  3. Burlap

Tiga protokol?? Apa tidak terlalu ambisius? Nanti saya pusing baca kode sekian banyak.

Demikian terdengar komentar dari penonton. Hmm … penonton Indonesia memang terlalu banyak protes.

Tenang saja. Kita akan gunakan Spring untuk mempublikasikan aplikasi kecil kita ini. Saya akan buktikan bahwa kodenya sedikit dan mudah dipahami. Sekarang, mari kita mulai dengan mempublikasikan protokol RMI. Di masa lalu, untuk menyediakan layanan ini, paling tidak kita harus:

  1. mengkompilasi stub

  2. mengkompilasi skeleton

  3. mengkonfigurasi Security setting

  4. menjalankan RMIRegistry

  5. mendaftarkan objek PersonServiceImpl ke RMIRegistry

  6. memberikan stub ke aplikasi client

Sekarang tidak lagi. Kita cukup mendaftarkan interface PersonService, implementasi PersonServiceImpl di konfigurasi Spring. Berikut adalah isi file remote-ctx.xml

remote-ctx.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean id="personServiceTarget" class="tutorial.remoting.remote.PersonServiceImpl"/>
    
    <bean class="org.springframework.remoting.rmi.RmiServiceExporter">        
        <property name="serviceName" value="PersonRmiService"/>
        <property name="service" ref="personServiceTarget"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>  
        <property name="registryPort" value="4321"/>
    </bean>
</beans>

Hanya dengan membaca file XML di atas, kita sudah bisa menduga apa yang terjadi. Kita mempublikasikan layanan yang didefinisikan pada interface PersonService pada port 4321 dengan nama layanan PersonRmiService. Di sisi server, layanan ini akan disediakan oleh objek personServiceTarget yang merupakan instan dari class PersonServiceImpl. Kita memanfaatkan class RmiServiceExporter yang dimiliki Spring.

Untuk menjalankan aplikasi kecil kita, buat sebuah class sederhana untuk mengaktifkan Spring Framework. Berikut adalah kode programnya.

PersonRmiService.java

package tutorial.remoting.server;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class PersonRmiService {
    public static void main(String[] xx) {
        ApplicationContext ctx = 
        new FileSystemXmlApplicationContext("webapp/WEB-INF/remote-ctx.xml");
    }
}

Silahkan jalankan class di atas. Asal classpath sudah disetting dengan benar, kita siap mengaksesnya dari client. Kita juga akan menggunakan bantuan dari Spring Framework untuk menemukan dan menginisialisasi layanan RMI yang berada di port 4321. Berikut adalah konfigurasi Spring di sisi client.

client-ctx.xml

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>    
    <bean id="personServiceRmi" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl" value="rmi://localhost:4321/PersonRmiService"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>
    </bean>
</beans>

Berikut adalah kode program untuk mengakses RMI service kita.

Main.java

package tutorial.remoting.client;

import java.util.List;

import tutorial.remoting.PersonService;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {
    public static void main(String[] args){
        // initialize application context
        ApplicationContext ctx = new FileSystemXmlApplicationContext("client-ctx.xml");
    
        // accessing RMI service
        System.out.println("======= Accessing RMI Service ==========");
        PersonService ps1 = (PersonService) ctx.getBean("personServiceRmi");
        List all1 = ps1.getAllPerson();
        for(int i=0; i<all1.size(); i++) {
            System.out.println(all1.get(i));
        }
}

Perhatikan konsol, dan saksikan RMI service kita sudah dieksekusi dengan sukses.

Sekarang, kita publikasikan melalui protokol Hessian dan Burlap. Protokol ini adalah hasil karya Caucho untuk mempublikasikan service di atas protokol HTTP. Hessian menggunakan format binary, sedangkan Burlap menggunakan format XML.

Karena berbasis HTTP, maka kita perlu menggunakan HTTP Server yang mendukung Java (khususnya Servlet). Kita bisa gunakan Tomcat atau Jetty. Yang jelas, kita perlu mendeklarasikan servlet untuk melayani client. Deklarasi dibuat di dalam file web.xml sebagai berikut.

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app PUBLIC
	"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
	"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/remote-ctx.xml
		</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<servlet>
		<servlet-name>remoting</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>2</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>remoting</servlet-name>
		<url-pattern>/remoting/*</url-pattern>
	</servlet-mapping>

	<session-config>
		<session-timeout>10</session-timeout>
	</session-config>


</web-app>

Kita membutuhkan satu file konfigurasi untuk mengkonfigurasi layanan Hessian dan Burlap. Berikut adalah isi file remoting-servlet.xml.

remoting-servlet.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean name="/PersonHessianService" class="org.springframework.remoting.caucho.HessianServiceExporter">
        <property name="service" ref="personServiceTarget"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>          
    </bean>
    
    
    <bean name="/PersonBurlapService" class="org.springframework.remoting.caucho.BurlapServiceExporter">
        <property name="service" ref="personServiceTarget"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>          
    </bean>
    
    <bean name="/PersonHttpInvokerService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="personServiceTarget"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>          
    </bean>
    
    
</beans>

Letakkan file remoting-servlet.xml ini di sebelah web.xml. Kita juga perlu mengikutkan file remote-ctx.xml yang kita buat untuk RMI di atas, karena deklarasi objek PersonServiceImpl ada di sana. Bila kita tidak ingin mengikutkan file ini, kita bisa memindahkan deklarasi objek tersebut ke dalam file remoting-servlet.xml.

Sekarang kita bisa mengkompilasi dan mendeploy aplikasi webnya. Untuk mengaksesnya, ubah sedikit kode program di aplikasi client menjadi sebagai berikut.

Main.java

package tutorial.remoting.client;

import java.util.List;

import tutorial.remoting.PersonService;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {
    public static void main(String[] args){
        // initialize application context
        ApplicationContext ctx = new FileSystemXmlApplicationContext("client-ctx.xml");
    
        // accessing RMI service
        System.out.println("======= Accessing RMI Service ==========");
        PersonService ps1 = (PersonService) ctx.getBean("personServiceRmi");
        List all1 = ps1.getAllPerson();
        for(int i=0; i<all1.size(); i++) {
            System.out.println(all1.get(i));
        }
        
        // accessing Hessian Service
        System.out.println("======= Accessing Hessian Service ==========");
        PersonService ps2 = (PersonService) ctx.getBean("personServiceHessian");
        List all2 = ps2.getAllPerson();
        for(int i=0; i<all2.size(); i++) {
            System.out.println(all2.get(i));
        }
        
        // accessing Burlap Service
        System.out.println("======= Accessing Burlap Service ==========");
        PersonService ps3 = (PersonService) ctx.getBean("personServiceBurlap");
        List all3 = ps3.getAllPerson();
        for(int i=0; i<all3.size(); i++) {
            System.out.println(all3.get(i));
        }
        
        // accessing Http Invoker Service
        System.out.println("======= Accessing Http Invoker Service ==========");
        PersonService ps4 = (PersonService) ctx.getBean("personServiceHttpInvoker");
        List all4 = ps4.getAllPerson();
        for(int i=0; i<all4.size(); i++) {
            System.out.println(all4.get(i));
        }
    }
} 

Demikian juga dengan konfigurasi Spring di sisi client. Kita perlu menambahkan beberapa objek tambahan untuk mengakses layanan di berbagai protokol tersebut. Berikut adalah isi lengkap dari client-ctx.xml.

client-ctx.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>    
    <bean id="personServiceRmi" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
        <property name="serviceUrl" value="rmi://localhost:4321/PersonRmiService"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>
    </bean>
    
    <bean id="personServiceHessian" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
        <property name="serviceUrl" value="http://localhost:9090/remoting/PersonHessianService"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>
    </bean>
    
    <bean id="personServiceBurlap" class="org.springframework.remoting.caucho.BurlapProxyFactoryBean">
        <property name="serviceUrl" value="http://localhost:9090/remoting/PersonBurlapService"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>
    </bean>
    
    <bean id="personServiceHttpInvoker" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
        <property name="serviceUrl" value="http://localhost:9090/remoting/PersonHttpInvokerService"/>
        <property name="serviceInterface" value="tutorial.remoting.PersonService"/>
    </bean>
</beans>

Aplikasi kecil kita sudah selesai. Setelah mendeploy aplikasi tersebut ke Servlet Container (Tomcat atau Jetty), kita dapat mengaksesnya melalui aplikasi client. Dengan tetap menggunakan remote-ctx.xml tanpa perubahan, selain menyediakan protokol Hessian dan Burlap, protokol RMI akan tetap tersedia.

Bonus

Pembaca yang teliti akan menemukan satu protokol tambahan pada contoh di atas, yaitu HttpInvoker. Ini adalah protokol khusus yang disediakan oleh Spring.

Protokol Hessian dan Burlap tidak mendukung struktur objek secara sempurna. Dia akan mengalami kesulitan apabila objek yang kita kirim tidak sesederhana Person, misalnya memiliki List yang berisi objek lain. Agar bisa mengirim struktur objek yang sempurna, kita harus menggunakan RMI.

Tetapi sayangnya, protokol RMI kurang lazim. Dia membutuhkan port tersendiri yang mungkin saja diblok oleh administrator jaringan, sehingga tidak sefleksibel HTTP.

SpringHttpInvoker menjembatani keterbatasan ini. Kita bisa mengirim objek kompleks secara utuh di atas protokol HTTP dengan menggunakan SpringHttpInvoker.

Demikian … semoga bermanfaat.


Nyambi, bolehkah??

Posting ini saya tulis karena di milis JUG sedang rame membahas tentang boleh tidaknya karyawan nyambi. Sepanjang karir saya, urusan nyambi telah menjadi bagian hidup tak terpisahkan dari perkembangan pribadi saya. Jadi baiklah mari kita bahas sedikit tentang urusan nyambi ini.

Disclaimer : Pernyataan di bawah ini merupakan opini pribadi dan bukan merupakan sikap resmi perusahaan yang saat ini mempekerjakan saya.

Mari pertama kita bedakan antara masalah legal dan masalah etis.

Yang menurut saya tidak legal (haram) :

  • Nyambi di jam kantor (ngerjain project lain2 di kantor)

  • Pakai resource kantor untuk project lain (telp, internet, komputer, dsb), tanpa sepengetahuan atasan

Yang menurut saya legal :

  • Pagi datang ontime, sore tenggo, sampe rumah ngerjain project lain.

Nah, kalo urusan etis, ini rada sulit juga, soalnya urusan kepantasan ini tergantung pendidikan yang diberikan orangtua masing-masing.

Yang menurut saya kurang etis:

  • Berebut pasar dengan kantor. Misal: kantornya terima project dengan kisaran nilai 100-500 juta, eh kita juga terima project dengan nilai 150jt. Lebih tidak etis lagi kalo ikut tendernya saingan.

  • Ngerjain project sampingan sampe begadang, akibatnya pas ngantor ngantuk dan gak konsen.

  • Yang ini dari sisi kantor. Mempekerjakan karyawan lembur sampai nginap, tanpa uang lembur. Padahal kalo si karyawan pulang, dia bisa dapat tambahan uang dari waktu miliknya.

Yang menurut saya etis:

  • Mengerjakan produk/project yang sama, tapi beda segmen. Misalnya kantor terima project Java 100-500 jt. Kalo dibawah itu dia gak terima karena gak nutup biaya. Nah, kita terima project 10 jt, yang kalo dikasi ke kantor pun gak diterima. It’s fine … asal tidak ilegal.

  • Mengkomersilkan sisi lain teknologi, misalnya di kantor coding, di luar ngasi training atau nulis buku.

Sebenarnya kalo kita tanpa ada unsur paranoid, karyawan nyambi ada juga untungnya bagi perusahaan.

Misalnya, di kampus tempat saya ngajar dulu, dosen itu dianjurkan untuk nulis buku, walaupun dikerjakan menggunakan resource kantor (waktu, komputer, internet). Saya tanya kenapa? Teman saya sesama dosen bilang,

kalo ada buku yang ditulis dosen, maka itu bisa meningkatkan image kampusnya.

Demikian juga apabila kita sering nulis blog, aktif di milis, banyak ngarang buku, sering masuk e-lifestyle, dsb. Perusahaan yang berpikiran maju akan dapat melihat manfaat dari ini, misalnya menggunakan resume karyawan tersebut untuk tender, atau diiklankan pada waktu pitching project.

Nah, menurut saya, selain yang legal/ilegal, tidak ada hitam putih di sini. Yang paling penting adalah saling keterbukaan dan kesepakatan.

Saya sendiri selama ini berterus terang pada perusahaan tentang kegiatan komersil lain yang saya lakukan. Bila ada konflik kepentingan ya kita rundingkan. Bila setelah dirundingkan tidak ada titik temu, ya mungkin sudah saatnya berpisah untuk menjalani hidup masing-masing.

Untungnya selama ini saya tidak mengalami masalah dengan keterbukaan ini. Pada perusahaan sebelumnya, bahkan saya bisa nyambi ngajar di kampus di jam kantor, dengan dispensasi khusus.

Jadi, jangan dulu pesimis bahwa nyambi itu haram. Coba saja diskusikan dengan kantor Anda. Siapa tau boleh, dengan kompromi tertentu :D.

Demikian pendapat saya …


Intro JSF

Pada postingan kemarin, kita telah melihat bagaimana membuat aplikasi web dengan ICEFaces, yang notabene dijalankan di atas framework JSF. Tapi JSF sendiri itu apa?

Java Server Faces (JSF) adalah salah satu teknologi terbaru dalam pengembangan aplikasi web. Teknologi ini distandarisasi oleh Sun sehingga dukungan terhadapnya akan disediakan para vendor server.

Sebenarnya apa itu JSF? Berdasarkan penjelasan dari Sun, JSF terdiri dari:

  • Kumpulan komponen UI (tentunya berbasis web)

  • Pengaturan flow navigasi

  • Mekanisme event handling (seperti layaknya aplikasi desktop)

  • Halaman web

  • Server side objects

Karena sifatnya yang merupakan spesifikasi resmi dari Sun, di masa depan akan banyak vendor yang menyediakan dukungan terhadap framework ini, sehingga kita bisa mengharapkan adanya:

  • Visual Editor untuk halaman web

  • Visual Editor untuk mengatur aliran navigasi

  • Komponen siap pakai yang sudah AJAX-enabled

Saat tulisan ini dibuat, sepertinya editor visual yang terbaik untuk JSF masih dipegang Netbeans. Sayangnya berdasarkan pengalaman sekilas saya, editor visual ini sangat ‘menjajah’. Agar kita bisa mengedit halaman web dan navigasi secara visual, kita harus banyak extends class Netbeans.

Mudah-mudahan di masa depan dukungan tools akan semakin banyak, terutama dari Eclipse atau IDEA.

Baiklah, para pembaca tentunya sudah tidak sabar ingin melihat, seperti apa kodenya. Pada artikel ini, kita hanya akan membahas tentang:

  1. konfigurasi awal

  2. membuat dua halaman, dan

  3. menghubungkan keduanya dengan konfigurasi navigasi

Kita akan menggunakan implementasi JSF yang disediakan Sun, saat artikel ini ditulis, rilis terbaru adalah 1.2.

Selain hasil karya Sun, kita juga bisa menggunakan JSF terbitan Apache.

Mari langsung coding.

Kita akan hanya akan membuat dua halaman:

  1. Registrasi User

  2. Konfirmasi Registrasi

tanpa business logic sama sekali. Halaman pertama berisi form registrasi, yang bila di-klik tombol Register-nya, user akan diarahkan ke halaman kedua. Untuk validasi dan akses database akan dibahas dalam artikel terpisah.

Halaman pertama tampak seperti ini.

Halaman Registrasi

Sedangkan halaman kedua tampak seperti ini.

Halaman Konfirmasi

Kode untuk halaman pertama adalah sebagai berikut.

register.jsp

<code><%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>:: Pendaftaran User ::</title>
    </head>
    <body>

    <h1>Silahkan masukkan data Anda di sini</h1>
    <h:form>
    <table border="0">        
        <tbody>
            <tr>
                <td>Nama Lengkap</td>
                <td><h:inputText value="name" /></td>
            </tr>
            <tr>
                <td>Username</td>
                <td><h:inputText value="name" /></td>
            </tr>
            <tr>
                <td>Email</td>
                <td><h:inputText value="name" /></td>
            </tr>
            <tr>
                <td>Password</td>
                <td><h:inputSecret value="password"/></td>
            </tr>
            <tr>
                <td>Password (ulangi)</td>
                <td><h:inputSecret value="password2"/></td>
            </tr>
            <tr>
                <td> </td>
                <td><h:commandButton type="submit" value="Daftar" action="register"/></td>
            </tr>
        </tbody>
    </table>
    </h:form>
    
    </body>
</html>
</code>

Perhatikan kode program untuk menampilkan tombol. Di sana ada atribut action yang bernilai register. Atribut action ini nantinya akan digunakan di konfigurasi navigasi di bawah.

Sedangkan halaman kedua isinya HTML biasa, sebagai berikut.

confirmation.jsp

<code><%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>:: Konfirmasi Pendaftaran ::</title>
    </head>
    <body>

    <h1>Registrasi Berhasil !!</h1>
    
    </body>
</html>
</code>

Kedua halaman tersebut akan diakses dengan URL :

  1. http://localhost:8080/HelloJSF/register.jsf

  2. http://localhost:8080/HelloJSF/confirmation.jsf

Perhatikan bahwa kita mengakses halaman tersebut dengan URL *.jsf, padahal nama file sebenarnya adalah *.jsp.

Jadi, yang terjadi di sini adalah, kita menyerahkan pemrosesan semua URL berakhiran jsf kepada servlet JSF.

Oleh karena itu, kita perlu mendefinisikan Servlet JSF dan URL Mapping tersebut pada web.xml.

web.xml

<code><?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>com.sun.faces.verifyObjects</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.validateXml</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>
</code>

Isi web.xml sudah dijelaskan pada artikel sebelumnya tentang ICEFaces.

Selanjutnya, mari kita lihat konfigurasi navigasinya, yang menyatakan:

bila tombol Daftar ditekan, bukalah halaman confirmation.jsp

Konfigurasi tersebut ditulis di dalam file faces-config.xml sebagai berikut.

faces-config.xml

<code><?xml version='1.0' encoding='UTF-8'?>

<faces-config version="1.2" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
        <navigation-rule>            
            <from-view-id>/register.jsp</from-view-id>
            <navigation-case>
                <from-outcome>register</from-outcome>
                <to-view-id>/confirmation.jsp</to-view-id>
            </navigation-case>
        </navigation-rule>
</faces-config>
</code>

Pada konfigurasi di atas, kita mendefinisikan view bernama register.jsp, yaitu halaman registrasi kita. Kemudian ada navigation case, yang merupakan aturan navigasi untuk halaman register.jsp tersebut. Bila dihasilkan action register, tampilkan halaman confirmation.jsp.

Action register ini didapat dari nilai atribut action pada komponen tombol Daftar di dalam file register.jsp.

Di masa yang akan datang, nantinya konfigurasi navigasi ini akan diedit dengan visual editor. Sehingga kita bisa langsung drag-and-drop halaman, kemudian menggambar panah dari halaman register.jsp ke confirmation.jsp dengan tulisan ‘register’.

Aplikasi HelloJSF siap dideploy. Struktur folder lengkapnya tampak seperti ini.

Struktur Folder Aplikasi HelloJSF

Pembaca yang teliti akan segera bertanya,

Apa tidak kurang? Mana *.jar nya? Tidak ada *.jar apa-apa di sana!

Itu karena saya mendeploy ke Sun Application Server yang terbundle bersama Netbeans Enterprise Pack. Kalau saja kita deploy ke Tomcat atau Jetty, tentu lain ceritanya. Kita harus melihat dokumentasi masing-masing merek server.

Demikian perkenalan kita dengan JSF. Lain waktu kita akan sambung dengan kemampuan JSF yang lainnya.


Intro ICEFaces

Beberapa waktu terakhir ini, framework Java Server Faces terlihat semakin matang. Orang-orang sudah mulai menggunakan, memberi feedback, dan menemukan best-practices cara penggunaannya. Oleh karena itu, saya pikir sudah tiba waktunya untuk saya mempelajari framework tersebut.

Berdasarkan pengalaman rekan Samuel, dia menganjurkan penggunaan JSF dengan menggunakan stack:

Spring dan Hibernate sudah sering saya gunakan. Integrasinya dengan JSF juga tidak terlalu sulit. Hanya butuh registrasi bean di dalam konfigurasi JSF.

Facelets adalah template engine untuk JSF. Dalam dunia JSF, template engine sering disebut juga dengan istilah View Renderer. Sebenarnya View Renderer default JSF adalah JSP, tapi saya tidak suka JSP. Jadilah akhirnya kita pakai JSF dengan Facelets sebagai ViewRenderer-nya. Facelets ini mirip dengan Freemarker atau Velocity. Kalau di dunia PHP kira-kira padanannya adalah Smarty.

Keuntungan menggunakan Facelets dibanding JSP adalah dengan Facelets, desain tampilan dapat dikerjakan oleh web designer. JSF dengan JSP akan banyak sekali menggunakan taglib yang tidak akan muncul di Macromedia Dreamweaver atau editor HTML lainnya. Facelets menggunakan pendekatan yang mirip dengan Tapestry, yaitu memasukkan komponen ke dalam elemen HTML biasa, sehingga dapat dilihat secara normal oleh editor HTML.

ICEFaces adalah kumpulan komponen JSF. Dia memiliki teknologi Direct to DOM Rendering sehingga kita dapat membuat tampilan ber-AJAX dengan mudah.

Seperti halnya teknologi lainnya di dunia Java, JSF hanyalah berupa spesifikasi. Kita dapat menggunakan implementasi yang dikeluarkan Sun (sering disebut dengan Reference Implementation - RI), atau menggunakan implementasi orang lain. Selain Sun, Apache mengeluarkan MyFaces dan Oracle mengeluarkan ADF sebagai implementasi JSF.

Pada artikel ini, kita akan lihat Hello World dengan menggunakan JSF, Facelets, dan ICEFaces. Karena ini hanya perkenalan saja, requirementnya tidak rumit. Saya hanya ingin membuktikan kecanggihan teknologi Direct to DOM Rendering yang dimiliki ICEFaces. Konon teknologi ini memungkinkan kita mengupdate tampilan di sisi client dari server dengan mudah.

Aplikasi yang ingin kita buat sangat sederhana, tapi sering menjadi pertanyaan di berbagai milis pemrograman web. Kita akan membuat satu halaman yang menampilkan waktu server. Waktu server ini harus berjalan secara real-time.

Dalam bahasa pemrograman lain, menampilkan jam server secara real time di browser bukanlah suatu hal yang mudah. Programmer harus memilih satu di antara beberapa teknik berikut:

  • Menggunakan meta refresh untuk request ke server setiap beberapa detik

  • Mengambil jam server sekali saja di awal loading page, kemudian increment nilainya di sisi client dengan JavaScript

  • Menggunakan streaming HTML

  • Menggunakan AJAX Push

Atau berbagai teknik lainnya. Yang jelas tidak mudah untuk melakukan hal ini.

Dengan menggunakan JSF + ICEFaces, hal ini menjadi mudah. ICEFaces adalah salah satu implementasi JSF yang menggunakan teknologi Direct to DOM Rendering. Artinya, server bisa seenaknya mengubah HTML yang ada di sisi client (browser). Dengan teknik ini, menampilkan jam server secara real time menjadi mudah.

Berikut adalah langkah-langkahnya:

  1. Buat halaman HTML yang akan menampilkan waktu server

  2. Buat kode Java yang bertugas menyediakan waktu server

  3. Gunakan JSF + ICEFaces untuk menghubungkan keduanya

  4. Aktifkan partial rendering agar tidak menimbulkan flicker

Mari kita bahas satu persatu.

Halaman HTML

Halaman ini adalah halaman dinamis yang berisi nilai yang dikeluarkan oleh server. Bedakan dengan halaman dinamis yang dikendalikan oleh JavaScript, di mana pada kasus tersebut tidak dibutuhkan sisi server yang menyediakan data.

Kode tampilan ini sederhana saja. Dibuat dalam format XHTML, karena begitulah keinginan Facelets.

whattimeisit.xhtml

<code><!-- <?xml version="1.0" encoding="UTF-8"?> -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>:: Menampilkan Jam Server ::</title>
    </head>
    <body>
        <p>
                <b>Waktu Server Saat Ini : #{serverClock.currentTime}</b>
        </p>
    </body>
</html>
</code>

Perhatikan bahwa satu-satunya dynamic code di atas adalah #{serverClock.currentTime}. Sisanya HTML biasa. Bagi yang belum tahu, dynamic code tersebut ditulis dalam Expression Language (EL) yang didukung oleh JSF. Kalau di dalam Java, kode tersebut sama dengan serverClock.getCurrentTime(). Sekarang mari kita lihat kode Java yang membekingi template whattimeisit, yaitu ServerClock.java.

ServerClock.java

<code>package tutorial.icefaces;

import com.icesoft.faces.async.render.IntervalRenderer;
import com.icesoft.faces.async.render.RenderManager;
import com.icesoft.faces.async.render.Renderable;
import com.icesoft.faces.webapp.xmlhttp.PersistentFacesState;
import com.icesoft.faces.webapp.xmlhttp.RenderingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class ServerClock implements Renderable {
    private DateFormat formatter;
    private PersistentFacesState state;
    private IntervalRenderer renderer;
    private static final int renderInterval = 1000; // render setiap 1 detik

    public ServerClock() {
        formatter = new SimpleDateFormat("EEE, HH:mm:ss");
        state = PersistentFacesState.getInstance();
    }
    
    public String getCurrentTime() {
        return formatter.format(Calendar.getInstance().getTime());
    }

    public PersistentFacesState getState() {
        return state;
    }

    public void renderingException(RenderingException renderingException) {
        if(renderer != null) {
            renderer.remove(this);
            renderer = null;
        }
    }
    
    public void setRenderManager(RenderManager manager) {
        renderer = manager.getIntervalRenderer("whattimeisit");
        renderer.setInterval(renderInterval);
        renderer.add(this);
        renderer.requestRender();
    }
}            
</code>

Constructor dan method getCurrentTime tidak terlalu istimewa. Isinya hanya inisialisasi DateFormat dan kegiatan memformat waktu saat ini menjadi String.

Selain constructor, setter, dan getter, kode lainnya berkaitan dengan pengelolaan internalnya ICEFaces. Dalam method setRenderManager, kita menyuruh ICEFaces untuk mengupdate browser setiap 1 detik. RenderManager adalah object yang bertugas merender tampilan. Dia beroperasi ke sekumpulan Renderable, yang salah satunya adalah class kita ServerClock.

Bila kita mengimplementasikan Renderable, ada dua method yang harus kita sediakan, yaitu renderingException dan getState. Method ini dengan mudah dapat kita buat. Selain kedua method ini, ICEFaces tidak butuh tambahan kode lagi.

Saatnya kita siapkan konfigurasi. JSF membutuhkan dua konfigurasi, yaitu web.xml (seperti aplikasi web biasa) dan faces-config.xml. Mari kita lihat web.xml sedikit demi sedikit.

<code>    <context-param>
        <param-name>com.sun.faces.verifyObjects</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.validateXml</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>server</param-value>
    </context-param>
</code>

Kode di atas adalah konfigurasi untuk JSF. Konfigurasi ini berlaku umum, terlepas dari kita menggunakan Facelets dan ICEFaces ataupun library lainnya. Selanjutnya adalah konfigurasi Facelets.

<code>    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>facelets.DEVELOPMENT</param-name>
        <param-value>true</param-value>
    </context-param>
</code>

Pada konfigurasi di atas, kita mengganti default ekstensi file template, yang tadinya jsp atau jspx menjadi xhtml. Kita juga memberitahu Facelets bahwa kita sedang dalam tahap development. Dengan demikian, pesan error yang dikeluarkan akan lebih lengkap sehingga memudahkan debugging.

Selanjutnya, mari kita lihat konfigurasi ICEFaces.

<code>    <context-param>
        <param-name>com.icesoft.faces.uploadDirectory</param-name>
        <param-value>upload</param-value>
    </context-param>
    <context-param>
        <param-name>com.icesoft.faces.uploadMaxFileSize</param-name>
        <param-value>4048576</param-value>
    </context-param>
    <context-param>
        <param-name>com.icesoft.faces.concurrentDOMViews</param-name>
        <param-value>true</param-value>
    </context-param>
</code>

Dua konfigurasi pertama sudah cukup jelas, mengatur tentang di mana harus meletakkan file hasil upload dan berapa maksimal ukuran file yang dapat diterima. Konfigurasi ketiga menyuruh ICEFaces berhati-hati agar dapat melayani request berbarengan ke satu halaman yang sama.

Setelah selesai dengan konfigurasi context param, mari kita masuk ke bagian servlet. JSF membutuhkan satu servlet yang harus dijalankan pada saat aplikasi diaktifkan.

<code>    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        </servlet>
</code>

Servlet ini tidak perlu dimapping ke URL, karena nantinya kita akan menggunakan servlet ICEFaces.

ICEFaces membutuhkan beberapa servlet, terlihat pada konfigurasi berikut.

<code>    <servlet>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <servlet-class>com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>Blocking Servlet</servlet-name>
        <servlet-class>com.icesoft.faces.webapp.xmlhttp.BlockingServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>uploadServlet</servlet-name>
        <servlet-class>com.icesoft.faces.component.inputfile.FileUploadServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
</code>

Selain itu, ICEFaces juga membutuhkan satu listener, dideklarasikan diatas deklarasi servlet.

<code>    <listener>
        <listener-class>com.icesoft.faces.util.event.servlet.ContextEventRepeater</listener-class>
    </listener>
</code>

Servlet ICEFaces dimapping sebagai berikut.

<code>    <servlet-mapping>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <url-pattern>/xmlhttp/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <url-pattern>*.iface</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Blocking Servlet</servlet-name>
        <url-pattern>/block/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>uploadServlet</servlet-name>
        <url-pattern>/uploadHtml</url-pattern>
    </servlet-mapping>
</code>

Terakhir untuk web.xml, kita perlu mendefinisikan session timeout.

<code>    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</code>

Hasil akhirnya adalah seperti ini.

web.xml

<code><?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>com.sun.faces.verifyObjects</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.validateXml</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>server</param-value>
    </context-param>

    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>facelets.DEVELOPMENT</param-name>
        <param-value>true</param-value>
    </context-param>

    <context-param>
        <param-name>com.icesoft.faces.uploadDirectory</param-name>
        <param-value>upload</param-value>
    </context-param>
    <context-param>
        <param-name>com.icesoft.faces.uploadMaxFileSize</param-name>
        <param-value>4048576</param-value>
    </context-param>
    <context-param>
        <param-name>com.icesoft.faces.concurrentDOMViews</param-name>
        <param-value>true</param-value>
    </context-param>
    
    
    <listener>
        <listener-class>com.icesoft.faces.util.event.servlet.ContextEventRepeater</listener-class>
    </listener>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        </servlet>
    <servlet>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <servlet-class>com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>Blocking Servlet</servlet-name>
        <servlet-class>com.icesoft.faces.webapp.xmlhttp.BlockingServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>uploadServlet</servlet-name>
        <servlet-class>com.icesoft.faces.component.inputfile.FileUploadServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>


    <servlet-mapping>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <url-pattern>/xmlhttp/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <url-pattern>*.iface</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Blocking Servlet</servlet-name>
        <url-pattern>/block/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>uploadServlet</servlet-name>
        <url-pattern>/uploadHtml</url-pattern>
    </servlet-mapping>


    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>
</code>

Selanjutnya, mari kita buat konfigurasi JSF. File konfigurasinya bernama faces-config.xml. Ini diletakkan di dalam folder WEB-INF, di sebelah web.xml. Berikut adalah kodenya.

faces-config.xml

<code><?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">

    <application>
        <view-handler>com.icesoft.faces.facelets.D2DFaceletViewHandler</view-handler>
    </application>
    
    
    <managed-bean>
        <managed-bean-name>renderManager</managed-bean-name>
        <managed-bean-class>com.icesoft.faces.async.render.RenderManager</managed-bean-class>
        <managed-bean-scope>application</managed-bean-scope>
    </managed-bean>
    
    <managed-bean>
        <managed-bean-name>serverClock</managed-bean-name>
        <managed-bean-class>tutorial.icefaces.ServerClock</managed-bean-class>        
        <managed-bean-scope>request</managed-bean-scope>
        <managed-property>
            <property-name>renderManager</property-name>
            <value>#{renderManager}</value>
        </managed-property>
    </managed-bean>
</faces-config>
</code>

Pada blok paling atas, kita mengkonfigurasi JSF agar menggunakan View Renderer Facelets yang sudah dilengkapi dengan ICEFaces. Di blok kedua, kita mendeklarasikan bean renderManager yang dibutuhkan oleh object kita serverClock pada blok ketiga.

Bagi yang sudah biasa menggunakan Spring, konfigurasi ini tidak jauh berbeda dengan konfigurasi Dependency Injection Spring. Nantinya bila kita menggunakan Spring, kita juga bisa mendeklarasikan Spring bean kita di dalam faces-config.xml tersebut.

Terakhir, jangan lupa lengkapi jar yang dibutuhkan agar kode kita bisa dikompilasi dan dideploy dengan mulus. Kombinasi jar yang dibutuhkan relatif bervariasi tergantung application server yang kita gunakan. Kadangkala ada jar yang sudah disediakan oleh application server tertentu, sehingga kita tidak perlu lagi menyediakan. Sebagai contoh, bila dideploy di Sun Application Server (Glassfish) yang terbundle bersama Netbeans 5.5, daftar jar yang dibutuhkan adalah:

  • backport-util-concurrent.jar

  • commons-collections.jar

  • commons-digester.jar

  • commons-fileupload.jar

  • commons-logging-1.0.4.jar

  • el-api.jar

  • icefaces-comps.jar

  • icefaces-facelets.jar

  • icefaces.jar

  • krysalis-jCharts-1.0.0-alpha-1.jar

  • xercesImpl.jar

  • xml-apis.jar

Struktur folder akhir dari aplikasi ini adalah sebagai berikut.

Struktur Folder Aplikasi JSF

Untuk Eclipse, daftar pustaka yang dibutuhkan sedikit berbeda. Demikian gambarnya. Daftar pustaka ICEFaces untuk Eclipse

Setelah semua file dibuat dan dipaket sesuai dengan aturan aplikasi web Java, kita bisa mendeploynya ke application server. Lalu, silahkan mengakses http://localhost:8080/HelloICE/whattimeisit.iface atau URL lain sesuai setting deployment.

Hasilnya akan tampak seperti ini.

Tampilan Akhir Server Time

Namun demikian, ternyata halaman tersebut masih melakukan refresh setiap satu detik sehingga mengganggu pandangan. Oleh karena itu, mari kita aktifkan fitur partial submit yang dimiliki ICEFaces. Dengan fitur ini, halaman HTML akan diupdate secara parsial sehingga tidak perlu me-reload seluruh halaman.

Buka file whattimeisit.xhtml dan cari baris berikut.

<code><body>
        <p>
                <b>Waktu Server Saat Ini : #{serverClock.currentTime}</b>
        </p>
    </body>
</code>

Ubah menjadi seperti ini.

<code><body>
        <p>
		<ice:form partialSubmit="true">
                <b>Waktu Server Saat Ini : #{serverClock.currentTime}</b>
		</ice:form>
        </p>
    </body>
</code>

Jangan lupa untuk mendeklarasikan komponen di awal halaman, dengan menggunakan tag sebagai berikut.

<code><f:view xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ice="http://www.icesoft.com/icefaces/component"></code>

Keseluruhan file whattimeisit.xhtml akan terlihat seperti ini.

<code><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ice="http://www.icesoft.com/icefaces/component">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>What time is it</title>
</head>
<body>
<ice:form>
<p>
                <b>Waktu Server Saat Ini : #{serverClock.currentTime}</b>
        </p>
</ice:form>
</body>
</html>
</f:view></code>

Redeploy aplikasi, dan lihat hasilnya. Tidak ada lagi flicker (kedipan).

Eclipse project untuk contoh di atas dapat didownload di sini.

Selamat mencoba, semoga bermanfaat.