Dian Aditya

Penjahit Digital.

GIS Part 2 - Pencarian Informasi Spasial Menggunakan Hibernate Search/Lucene

Berikut ini adalah posting saya yang kedua mengenai GIS, karena topik ini dibagi menjadi 4 bagian, saya sangat menyarankan anda untuk membaca secara berurutan.

Pencarian Informasi Spasial menggunakan Hibernate Search/Lucene

Pernah pakai aplikasi yang berhubungan dengan point of interest seperti foursquare atau google latitude? Ya dua aplikasi yang saya sebutkan tersebut adalah contoh implementasi dari sebuah service yang sangat berkaitan erat dengan lokasi dan koordinat. Ketika kita membuka aplikasi, melalui browser atau perangkat mobile misalnya, aplikasi akan secara otomatis membaca koordinat dimana perangkat berada melalui GPS (dengan seizin pemilik perangkat tentunya) dan kemudian menamplikan lokasi-lokasi terdekat dengan radius tertentu dari lokasi user berada.

Pada bagian ini saya akan membahas bagaimana implementasi pengolahan data spatial menggunakan Hibernate Search.Hibernate Search adalah salah satu komponen Hibernate yang mengintegrasikan kemampuan search engine dari Apache Lucence kedalam Hiberante dan JPA model. Apache Lucene adalah pustaka yang sangat powerful untuk melakukan pencarian teks bebas secara efisien, disamping itu Lucene juga mendukung spatial search yang akan saya bahas kali ini. Hibernate Search mulai mendukung spatial search sejak versi 4.2.0.Beta1, versi terupdate ketika tulisan ini dibuat adalah 4.2.0.Beta2.

Karena masih dalam versi beta, beberapa fitur masih belum dapat digunakan dengan sempurna, salah satunya adalah error untuk query sort berdasarkan jarak terdekat.

Dalam kasus kali ini saya akan menggunakan fitur spatial search untuk menampilkan objek terdekat dari suatu koordinat dalam radius tertentu (lihat ilustrasi dibawah ini). Kumpulan objek dan koordinat disimpan dalam database. Koordinat berbasis latitude (garis lintang) dan longitude (garis bujur).

Pada ilustrasi diatas titik tengah berada pada monumen nasional, lingkaran berwarna abu-abu adalah daerah dalam radius 3 KM dari titik tengah. Titik biru yang berada di dalam lingkaran adalah daerah yang terseleksi. Sedangkan titik diluarnya adalah sebaliknya.

Kode

Untuk permulaan mari membuat desain table sederhana, karena Hibernate berbasis Object Relational Mapping (ORM) untuk contoh ini saya akan membuat sebuah JPA entity untuk mewakilkan table.

1
2
3
4
5
6
7
8
9
10
11
12
@Entity
@Table
@Indexed
@Spatial(name = "location")
public class Location implements Coordinates, Serializable {
 private long id;
 private String name;
 private Double latitude;
 private Double longitude;
 ...
}

Anotasi @Indexed mengindikasikan bahwa class tersebut akan diindex oleh Lucene. Anotasi @Spatial wajib agar data dapat diquery, entity juga diharuskan untuk mengimplementasikan interface org.hibernate.search.spatial.Coordinates.

1
2
3
4
5
public interface Coordinates {
 Double getLatitude();
 Double getLongitude();
}

Selanjutnya mari membuat data awal.

ID NAME LATITUDE LONGITUDE
1 Krukut -6.1583 106.81458
2 Kampung Bali -6.18476 106.8187
3 Kebon Sirih -6.18595 106.83517
4 Senen -6.17657 106.84376
5 Gondangdia -6.19449 106.83105
6 Kemayoran -6.16684 106.84874
7 Cikini -6.19397 106.84221
8 Gunung Sahari -6.16086 106.84462
9 Cideng -6.17554 106.80891
10 Jati Pulo -6.18186 106.80307
11 Tomang -6.17307 106.79646
12 Glodok -6.14738 106.81303
13 Cempaka Baru -6.17059 106.86522

Langkah terakhir adalah membuat query untuk menampilkan lokasi dalam radius 3 KM dari titik tengah.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 *
 * @param radius
 * Radius dalam Kilometer
 * @param lat
 * Latitude
 * @param lng
 * Longitude
 * @return List Location dalam radius dari titik tengah (lat, lng)
 */
public List<location> getLocations(int radius, double lat, double lng) {
 FullTextEntityManager em = Search.getFullTextEntityManager(entityManager);
 QueryBuilder builder = em.getSearchFactory().buildQueryBuilder().forEntity(Location.class).get();
 Query query = builder.spatial().onCoordinates("location").within(radius, Unit.KM).ofLatitude(lat).andLongitude(lng).createQuery();
 FullTextQuery q = em.createFullTextQuery(query, Location.class);

 return q.getResultList();
}

Method diatas akan mencari instance (Location) yang berada di dalam radius dari latitude dan longitude yang telah dimasukkan.

GIS Part 1 - Mengkonsumsi Data Tiles Dengan Leaflet

Sesuai dengan prefix judul posting saya kali ini, GIS (Geographic Information System) atau dalam bahasa Indonesia disebut SIG (Sistem Informasi Geografis), saya akan membahas secara tuntas implementasi sederhana dari GIS dari awal hingga akhir. Ya, saya ulangi lagi, tuntas dari awal hingga akhir (jangan lupakan kata sederhana). Kasus yang akan saya jadikan contoh kali ini adalah pengolahan informasi lokasi berdasarkan koordinat, contoh paling populer dari kasus ini adalah Foursquare dan Google Latitude. Karena pembahasan kasus ini cukup panjang, saya akan membagi postingan ini menjadi 4 bab, diantaranya:

Lengkap bukan?

Mengkonsumsi Data Tiles dengan Leaflet

Tiles adalah ubin, lalu apa hubungannya ubin dengan peta? Analogi sederhananya adalah sebagai berikut, untuk melapisi dinding kamar mandi ataupun dapur di rumah anda, diperlukan kumpulan keramik berbentuk persegi yang ditempelkan secara rapi dalam susunan grid. Konsep inilah yang mendasari tiles pada peta, yaitu kumpulan bitmap berbentuk persegi yang disusun untuk membentuk sebuah peta. Tiles secara umum adalah gambar berukuran 256 x 256 pixel, meskipun tidak selalu begitu, sebagai contoh CloudMade menyediakan gambar berukuran 64 x 64 pixel untuk kebutuhan mobile, namun secara keseluruhan gambar 256 x 256 pixel menjadi standart secara de facto yang dipimpin oleh Google Maps. Dalam implementasinya banyak pustaka yang disediakan di internet untuk mengkonsumsi tiles. Untuk menampilakan ke dalam web umumnya pustaka dibangun diatas javascript, beberapa pustaka javascript yang populer digunakan adalah:

  • Google Maps API. Sedikit catatan untuk penggunaan GMaps API, layanan ini bersifat komersial untuk kondisi tertentu. Google juga menentukan kebijakan dengan menyertakan iklan di dalamnya. Ingin menggunakan kode javascript GMaps pada local intranet? Sepertinya anda perlu membayar sekitar $10.000 per tahun untuk dapat melakukannya.
  • Openlayers, digunakan oleh OpenstreetMap, kaya fitur, serta opensource. Akan tetapi cukup kompleks dan memiliki ukuran yang cukup besar untuk sebuah file javascript.
  • Leaflet, dikembangkan oleh CloudMade dibawah lisensi BSD. Cukup ringan, stabil dan cepat jika dibandingkan dengan Openlayers, serta desain kode berbasis OOP yang sangat mudah dipahami. Foursquare adalah salah satu website yang menggunakan Leaflet.

Dalam contoh kali ini saya akan menggunakan leaflet sebagai pustaka untuk mengkonsumsi dan menampilkan data tiles dari Osmosa salah satu reimplementasi dari OpenstreetMap. Untuk menampilkan sebuah peta menggunakan leaflet adalah cukup mudah, berikut beberapa baris kode yang perlu ditulis untuk menampilkan sebuah peta dan menampilkan lokasi dimana anda berada.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(function() {
 var map = new L.Map('map', {zoom: 10});
 var markers = new L.LayerGroup();
 map.addLayer(markers);
 // Mengambil tiles dari Osmosa.net
 var tile = new L.TileLayer('http://www.osmosa.net/osm_tiles3/{z}/{x}/{y}.png', {
 attribution: 'Tiles CC-BY-SA Osmosa, data © OpenStreetMap contributors.',
 maxZoom: 18, minZoom: 3
 });
 map.addLayer(tile);
 // Mengambil posisi user, menampilkan titik dimana user berada
 navigator.geolocation.getCurrentPosition(function(p) {
 map.setView(new L.LatLng(p.coords.latitude, p.coords.longitude), 13);
 var marker = new L.Marker([p.coords.latitude, p.coords.longitude]);
 marker.addTo(markers).bindPopup('Anda berada di sini!').openPopup();
 });
})();

Live Demo!

Browser anda mungkin akan meminta persetujuan karena contoh kode diatas mencoba melacak lokasi dimana anda berada, ijinkan untuk dapat melihat live demo. Jangan khawatir karena saya tidak akan menyimpan data lokasi atau apapun yang melanggar privasi anda.

Menggunakan Method POST, GET, PUT, DELETE Pada HTML Form Tag, Bisakah?

Pernahkah anda menggunakan menggunakan http method selain GET dan POST pada browser. Yah, tentunya hanya hanya client seperti apache http client yang mensupport http request method seperti PUT, DELETE, ataupun OPTION. Sebenarnya saat ini hampir seluruh browser sudah dapat mengirimkan request dengan menggunakan http method tersebut melalui XMLHttpRequest, yap kuncinya ada di AJAX. Lalu bagaimana dengan html form tag?

1
 <form method="PUT"></form>

Sayangnya semua browser hanya mendukung POST dan GET untuk request pada form tag, jadi ilustrasi yang saya tulis diatas tidak dapat diimplementasikan. Lalu? Tunggu dulu, buat anda yang sudah main-main dengan Yama, semuanya bisa jadi mungkin. Saya akan memberikan sedikit contoh bagaimana method selain POST dan GET bisa dikirimkan ke server melalui browser, menggunakan form tag tentunya.

Sebagai pemanasan saya mulai dengan membuat sebuah proyek Yama.

1
2
3
4
5
6
mvn archetype:generate \
 -DarchetypeGroupId=org.meruvian.yama \
-DarchetypeArtifactId=yama-struts-archetype \
-DarchetypeVersion=1.0.2 \
-DgroupId=com.example.yama \
-DartifactId=my-first-yama

Oke kemudian saya akan membuat dua buah file jsp dibawah /src/main/webapp/WEB-INF/test, satu untuk mengirim request dan yang satunya lagi untuk menerima hasil request.

index.jsp

1
2
3
<form method="delete" action="/test">
 <input type="submit" value="Test http method!" class="btn" />
</form>

success.jsp

1
Http method : <%= request.getMethod() %>

Kemudian saya buat action class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.yama.action;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.meruvian.inca.struts2.rest.ActionResult;
import org.meruvian.inca.struts2.rest.annotation.Action;
import org.meruvian.inca.struts2.rest.annotation.Action.HttpMethod;

@Action(name = "/")
public class TestAction {
private static final Log LOG = LogFactory.getLog(TestAction.class);

  @Action(name = "/test", method = HttpMethod.GET)
  public ActionResult index() {
    return new ActionResult("/WEB-INF/test/index.jsp");
  }

  @Action(name = "/test", method = HttpMethod.DELETE)
  public ActionResult delete() {
    LOG.debug("Method delete executed!");
    return new ActionResult("/WEB-INF/test/success.jsp");
  }
}

Dan yang terakhir saya tambahkan link menu dengan mengedit file menu.ftl pada /src/main/webapp/view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<li class="active">
  <a href="<@s.url value=&quot;/home&quot; />">
    <i class="icon-home icon-white"></i> Home
  </a>
</li>
<#if request.session.getAttribute("SPRING_SECURITY_CONTEXT")??>
<!-- Menu yang harus ditambahkan -->
<li>
  <a href="#/test">Test HTTP Method</a>
</li>
<!-- End of menu yang harus ditambahkan -->
<li>
  <a href="<@s.url value="logout" />"></a>
  <@s.text name="frontent.logout.text" />
</li>
<!--#if-->

Selanjutnya saya akan coba jalankan menggunakan jetty. mvn jetty:run

Request:

Request

Response:

Response

Secara teknis Yama menghandle setiap request pada tag form, kemudian mengkonversinya menjadi AJAX request. Jadi kita tidak perlu lagi membuat kode javascript untuk mengirimkan AJAX request.

Pakai Application Server Yang Mana? (Ala Saya)

Setelah sekian abad tidak melihat kalender, baru sadar ini umur ternyata dah nambah banyak. Eeeaaaa, tidak terasa sudah dua tahun lebih saya terlibat dari satu projek ke projek, bergelantungan mondar-mandir. Yah tentunya sudah lumayan juga jumlah aplikasi yang telah terdeploy ke berbagai tempat dengan beragam jenis application server. Mulai dari aplikasi yang mengharuskan berjalan diatas JavaEE container hingga stack yang diluar standart JEE seperti Cimande dengan Struts2-Spring-Hibernate yang pastinya bisa jalan di application server manapun (dengan tambahan telaten dan istiqomah untuk beberapa spesifik application server).

Yang akan saya bahas kali ini adalah beberapa pertimbangan (pribadi) tentang bagaimana memilih application server yang tepat untuk digunakan pada fase production. Sebagai permulaan ada 2 jenis kelompok besar dalam aplication server, kelompok pertama adalah full-blown Java EE container, sedangkan kelompompok ke-dua adalah servlet container. Kelompok pertama adalah dihuni oleh app server yang mendukung spesifikasi Java EE seperti EJB, JMS, JSF, dll, beberapa anggota kelompok ini adalah Glassfish, JBoss AS, Weblogic, Websphere, dan masih banyak lagi. Sedangkan kelompok ke-dua adalah app server yang tidak mendukung secara penuh spesifikasi JEE seperti Tomcat dan Jetty. Sudah dapat gambaran tentang dua kelompok besar tersebut? Oke, sekarang saya akan pilah-pilah sesuai dengan kemampuan masing-masih application server.

Mandat dari client

Yang satu ini tidak bisa di ganggu gugat, kebanyakan client memang sudah bekerja sama dengan vendor-vendor kesayangan mereka termasuk urusan application server. Jadi bila kondisi seperti ini terjadi maka aplikasi-lah yang akan saya jadikan prioritas utama agar kompatibel dengan spesifik application server. Application server dalam kasus ini biasanya didominasi oleh produk vendor propietary seperti WLS dan WAS.

Perlukah menggunakan teknologi Java EE?

Kalau boleh jujur saya punya pengalaman yang kurang baik dengan EJB (J2EE 1.4 waktu itu) yang diimplementasikan dalam aplikasi yang tidak terlalu besar (curhat). Ada yang bilang sih Java EE 6 sudah lebih baik. Pertimbangan selanjutnya adalah spesifikasi JEE yang lain seperti JMS, JSF, atau mungkin ESB, jika memang diperlukan saya akan mengutamakan app server opensource terlebih dahulu, dua favorit saya jatuh pada Glassfish dan JBossAS. Dua container tersebut memiliki komunitas yang cukup besar, tidak jarang saya menemukan penyelesaian suatu masalah cukup dengan mengetik keyword di google, bahkan tanpa perlu bertanya pada mailing list komunitasnya. Glassfish 3 sudah mendukung spesifikasi JEE 6, salah satu yang saya suka adalah fitur admin consolenya yang cukup lengkap, dan juga servlet engine-nya yang konon adalah fork dari Tomcat. JBossAS 7 cukup mengesankan dengan startup-nya yang sangat cepat termasuk admin consolenya yang sudah menggunakan ajax, walaupun menurut saya belum sekeren Glassfish punya. Dulu saya pernah berfikir setiap aplikasi yang bisa jalan di Tomcat pasti bisa di deploy di JEE container manapun, semuanya memang terbukti sebelum akhirnya saya bertemu dengan Weblogic, jadi mungkin tanpa alasan pertama saya sebisa mungkin akan menghindari app server yang satu ini.

Cukup dengan servlet container?

Saya jarang ambil pusing bila diharuskan mendeploy aplikasi dibawah platform Cimande ataupun Yama. Ya, pada kenyataannya kedua framework kebanggaan ini bisa berjalan diatas servlet container saja. Beberapa project yang saya kerjakan dideploy diatas Tomcat. Jetty? Jujur saja saya belum pernah mencoba Jetty untuk kebutuhan production, namun untuk kebutuhan servlet container saya rasa Tomcat ataupun Jetty, tidak ada pilihan yang salah diantara kedua produk tersebut.

Kebutuhan hit tinggi tanpa perlu banyak setting

Kalau yang satu ini saya belajar banyak dari roller, yap tempat saya posting blog ini yang hampir setahun lalu bermigrasi dengan mulus dari Tomcat6 ke Glassfish3. Setelah migrasi ke Glassfish beberapa problem seperti timeout yang rutin setiap kali terjadi hit tinggi berangsur menghilang. Apakah artinya Tomcat tidak lebih tangguh Glassfish? Tentunya tidak pula, tetapi untuk konfigurasi minim (walaupun naif jika harus membandingkan keduanya) saya lebih memilih aman dengan menggunakan Glassfish.

Seluruh isi dari artikel ini merupakan opini subjektif berdasarkan pengalaman saya, apapun keputusan untuk menggunakan application server manapun dengan suatu alasan tertentu adalah menjadi hak masing-masih individu.

Mengimplementasikan Clean URL Parameter Dengan Inca S2Rest Plugin

Sudah pernah baca blog saya sebelumnya tentang Memanfaatkan Struts Action Mapper untuk Membuat Clean URL?

Beberapa waktu yang lalu Meruvian melaunching Inca S2Rest Plugin, ya plugin untuk Struts2 dengan fitur utama mengadopsikan arsitektur REST ke dalam Struts2 tentunya. Secara garis besar plugin ini bisa dibilang sebagai fusion-nya Convention Plugin dengan Rest Plugin yang sudah ada sejak dahulu kala, yang jelas dengan implementasi berbeda serta fitur yang jelas lebih banyak, ceile. Seperti harapan yang menjadi kenyataan, setelah beberapa tahun terakhir kita utak-atik action mapper dan kawan-kawannya akhirnya jadilah sebuah plugin untuk mengisi celah fitur yang tidak disertakan pada plugin Struts2 yang lain.

Pada artikel kali ini saya ‘hanya’ akan membahas salah satu fitur dari Inca yaitu dukungan untuk membuat clean url parameter. Nanti dulu deh, untuk fitur-fitur lain akan saya kupas lebih tajam dalam Developer Blog, terpisah dari blog ini, untuk saat ini bisa main-main dulu ke wikinya.

Ok, kembali ke laptop, Inca S2Rest menyediakan fitur anotasi untuk membuat konfigurasi dapat di-embed ke dalam kode java, sehingga meminimalisir konfigurasi xml yang harus dimaintain oleh developer. Salah satu anotasi yang powerful adalah @ActionParam, anotasi ini berada pada level field untuk menangkap request parameter yang dikirim ke dalam action class, yap no getter and setter anymore. Anotasi ini membantu kita untuk mendapatkan request parameter, lalu bagaimana dengan membuat clean url?

Saya akan membuat sebuah contoh kasus sebuah action untuk menampilkan sebuah artikel berdasarkan tanggal lengkap beserta id dari artikel. Pertama kita tentukan format url yang akan digunakan: /articles/{tahun}/{bulan}/{tanggal}/{id}

Saya kutip sedikit dari wiki:

By default, the Inca S2RestPlugin use Regex Pattern Matcher for its Pattern Matcher.

Sehingga pattern yang sudah saya tulis sebelumnya sudah memenuhi kualifikasi untuk menentukan sebuah action sesuai dengan format url. Waktunya membatik:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Action(name = "/article") // Deklarasi action class
public class ArticleAction {
  @ActionParam("th")
  private int year;

  @ActionParam("bln")
  private int month;

  @ActionParam("tgl")
  private int date;

  @ActionParam("id")
  private String articleId;

  @Action(name = "/{th}/{bln}/{tgl}/{id}", method = HttpMethod.GET)
  public String showArticle() {
  // lakukan sesuka hati disini
  // parameter akan dengan deklarasi @ActionParam akan terisi
  // apabila request url sudah sesuai dengan pattern pada
  // properti 'name' dalam @Action
  }

}

Langkah terakhir adalah membuat skenario request dengan url (sebagai contoh): /article/2012/05/04/release-inca-sudirman-thamrin-ditutup-selama-sepekan.

Menggunakan URL Pattern Matcher Lain

Walaupun secara default Inca S2Rest menggunakan regex pattern matcher, developer dapat merubah dengan implementasi pattern matcher lain cukup dengan merubah konfigurasi:

1
<constant name="struts.patternMatcher" value="struts" />

Contoh diatas apabila developer menghendaki untuk menggunakan struts (default) pattern matcher, maka contoh kode yang harus digunakan adalah:

1
2
3
4
5
6
@Action(name="/article/*/*/*/*", params= {
  @Param(name="th", value="{1}"),
  @Param(name="bln", value="{2}"),
  @Param(name="tgl", value="{3}"),
  @Param(name="id", value="{4}")
})

Selamat mecoba dan mengimplementasikan Inca S2Rest Plugin pada aplikasi Struts2 anda.

Kekuatan Dibalik Proxy Dalam Java

Proxy sudah diperkenalkan sejak java 1.3, salah satu kekuatan (yang tidak tersembunyi) dari java yang sangat berguna dalam pembuatan aplikasi dengan tingkat modularitas tinggi.

Sebelumnya kita ambil contoh dalam kehidupan coding sehari-hari, dengan atau tanpa disadari proxy ada dimana-mana seperti Spring yang mengimplementasikannya untuk AOP, Hibernate untuk lazy loading-nya, dan Google Guice dalam hal dependency Injection.

Dalam Java, dynamic proxy adalah sebuah intance pengganti dari object sesungguhnya. Dengan proxy, pemanggilan sebuah method (method invocation) dapat dicegat (intercepted) sehingga kita dapat memasukkan cutom code sebelum ataupun setelah pemaggilan method. Sangat powerful bukan?

Dalam penggunaannya, diluar dynamic proxy standart yang disediakan oleh JDK, banyak library yang menyediakan fitur proxy dalam penggunaannya, sebagai contoh Spring menyediakan JDK dynamic proxy dan CGLIB proxy bagi user untuk memilih salah satu. Begitu pula Hibernate yang menggunakan CGLIB untuk versi 3.x ke bawah yang kemudian berpindah menggunakan secara penuh Javassisst untuk menangani urusan proxy. Ada beberapa perbedaan antara JDK dynamic proxy dengan CGLIB serta Javassist, akan saya jelaskan sebagai berikut

JDK Dynamic Proxy

  • Proxy dibangun berdasarkan pada runtime interface, dengan kata lain proxy harus memiliki interface untuk dapat diciptakan.
  • Karena proxy dipaksa untuk menjadi implementasi dari sudatu interface maka sudah dipastikan kita tidak bisa melakukan casting terhadap class lain.
  • Object menjadi turunan dari java.lang.reflect.Proxy

Berikut contoh kode sedehananya, sebuah proxy yang akan menghalau setiap method bernama call dengan mengembalikan nilai null apapun nilainya.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class DisableEveryCall implements InvocationHandler {
  private Object object;

  public DisableEveryCall(Object object) {
    this.object = object;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (method.getName().equalsIgnoreCase("call")) {
    return null;
  }

  return method.invoke(object, args);
  }
}

Method invoke akan meng-intercept setiap method, dalam kasus ini hanya method dengan nama call yang akan mereturn null dengan apapun kondisinya. Kemudian berikut cara membuat proxy-nya.

1
2
3
4
5
6
7
8
9
Callable callable = new Callable() {
  public String call() throws Exception {
    return "Called!";
  }
};

Proxy proxy = (Proxy) Proxy.newProxyInstance(Callable.class.getClassLoader(), new Class[] { Callable.class }, new DisableEveryCall(callable));
callable = (Callable) proxy;
System.out.println(callable.call());

CGLIB Proxy

  • Tidak mengharuskan interface.
  • Proxy dibangun dengan cara mensub-classkan terhadap class sesungguhnya. Hal ini mengindikasikan bahwa class apapun yang digunakan dapat dimungkinkan untuk dijadikan proxy.
  • CGLIB proxy bersifat final. Maka adalah sebuah hal sia-sia untuk memproxy sebuah proxy karena tidak akan berhasil.

Mari membuat contoh yang agak berbeda, ketika kita memanggil method toString proxy akan mengembalikan dengan nilai null bagaimanapun caranya user melakukan override terhadap method tersebut.

1
2
3
4
5
class DisableToString implements MethodInterceptor {
  public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    return "toString".equals(method.getName()) ? null : proxy.invokeSuper(obj, args);
  }
}

Pembuatan proxy dapat dilakukan dengan cara berikut

1
2
3
4
5
6
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Object.class);
enhancer.setCallback(new DisableToString());

Object proxy = enhancer.create();
System.out.println(proxy.toString());

Javassist Proxy

Tidak banyak perbedaan antara Javassist dengan CGLIB proxy, penjelasan tersebut dapat langsung saya ambil dari dokumentasi source-nya.

Package javassist.util.proxy Dynamic proxy (similar to Enhancer of cglib).

Perbedaan paling utama adalah kita tidak dapat menambahkan sebuah method baru kedalam Javassist proxy, sedangkan hal tersebut dimungkinkan pada CGLIB proxy. Serta fitur utama dari Javassist sendiri adalah bytecode manipulation library yang lebih mengedepankan manipulasi class pada saat compile-time bahkan mendefinisikan class baru pada saat run-time daripada memproxynya, sangat powerful dalam sisi lain tapi tidak dengan fitur proxy-nya. Berikut beberapa hal dalam Javassist proxy:

  • Lebih lambat dari CGLIB proxy maupun JDK proxy (untuk saat ini)

Agar mudah saya akan membuat contoh dengan pendekatan yang tidak jauh berbeda.

1
2
3
4
5
class DisableToString implements MethodHandler {
  public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
    return null;
  }
}

Langkah pembuatan proxy-nya pun hampir sama

1
2
3
4
5
6
7
8
9
10
11
12
13
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Object.class);
factory.setFilter(new MethodFilter() {
  public boolean isHandled(Method m) {
    return "toString".equals(m.getName());
  }
});

Proxy proxy = (javassist.util.proxy.Proxy) factory.createClass().newInstance();
proxy.setHandler(new DisableToString());

Object object = proxy;
System.out.println(object.toString());

Kesimpulan

Java memiliki banyak fitur menarik, salah satunya adalah dynamic proxy. Spring transaction manager dan Hibernate lazy loading mungkin adalah contoh yang paling mudah untuk memahami bagaimana proxy bekerja untuk meng-intercept sebuah method. Banyak pula library pembantu di luar sana yang menyediakan fitur proxy dengan berbagai keunggulan masing-masing.

Enjoy.

Geliat Cloud 2012, Tahunnya PaaS?

Bicara soal 2012 kembali kita dihadapkan pada topik paling hot di dunia, pasti gak akan jauh-jauh dari isu akhir dari peradaban manusia. Yah, mungkin saya akan berkata hal serupa juga andaikan saat ini saya adalah pengguna smarphone nokia, hehehe… Lupakan.

Kembali kita tarik mundur ke tahun lalu, tahun 2011 yang menurut saya jaman dimana meledaknya barang bernama Cloud. Sebuah infrastruktur/perangkat/informasi/servis/awan/-kabut/petir atau apalah namanya yang sulit dimengerti… Menjadi alasan yang saya anggap cukup kuat, kita tahu dengan populernya facebook, twitter, google, amazon youtube, dan masih banyak lagi web yang memposisikan dirinya sebagai Software as a Service (SaaS), yang secara tidak sadar telah membawa kita ke jaman sentralisasi data. Walauppun sulit untuk dijelaskan, kita dapat dengan mudah menyebut bahwa web-web tersebut adalah cloud.

Lanjut ke topik utama bahasan, PaaS, ya Platform as a Service, nama dan istilahnya masih nyambung-nyambung dengan SaaS, dan tahun 2012 sepertinya adalah tahunnya PaaS. Mengapa begitu, indikasi paling nyata adalah dengan mulai menjamurnya penyedia layanan cloud seperti Amazon dengan EC2, Google dengan Google App Engine (GAE) dan google eclipse plugin-nya, RedHat dengan Openshift, VMWare dengan Cloudfoundry yang didukung dengan Springsource Tool Suite untuk mempermudah development dan proses deploy, tidak ketinggalan ada Jelastic yang dapat melakukan checkout source code dan secara otomatis mengcompile diudara, dan masih banyak lagi. Dan kabar baiknya sebagian besar yang saya sebutkan diatas rata-rata masih bersifat gratis, maka nikmatilah sebelum masa itu berakhir (yang pasti akan terjadi).

Tidak dapat dipungkiri bahwa ini adalah trend, dan developer telah dihadapkan ke posisi yang lebih menyenangkan, menjauh dari model tradisional. Para pengembang aplikasi dapat lebih terfokus terhadap fungsionalitas dan dan kualitas aplikasi ketimbang memikirkan masalah struktur dibawahnya. Begitupun dengan penyedia layanan juga mendapatkan keuntungan dengan berfokus pada penyediaan dan pengelolaan terhadap suberdaya dan infrastrukturnya, kemudian menyediakannya sebagai produk PaaS yang diinginkan oleh user. Sama-sama untung bukan?

Dunia cloud semakin membesar, dan 2012 adalah tahunnya, yang membawa developer terbang jauh ke awan, pilihan kita hanya ikut serta, mendahului, atau tertinggal. Dengan dunia IT yang kecepatan lajunya sudah sangat kencang, mau kemana?

Yang Sering Dilakukan Siswa Dan Yang Sering Diabaikan Oleh Pembimbing Dalam Tugas Akhir

Akhir Desember lalu saya berkesempatan untuk menjadi penguji eksternal (dari pihak industri) mewakili Meruvian di salah satu SMK swasta top di Kota Malang. Sangat istimewa karena kampung halaman saya berada di Kota Batu yang berdempetan dengan Malang, berasa seperti tiket mudik gratis dimana malamnya saya bisa ketemu teman-teman lama sambil ngopi bareng di pinggiran Jl. Diponegoro, bertemu hawa dingin dan pemandangan gunung di kiri kanan yang asri. #eaaa berasa makin lebay dan gak nyambung dengan judul.

Yap, setelah 2 hari mejeng di depan para siswa sebagai killer, disisi lain banyak diskusi menarik dengan para guru di setiap jeda dan seusai ujian mengenai kompetensi para siswa didiknya. Banyak point yang akhirnya disinggung, terutama masalah standart penyajian aplikasi seperti presentasi, pembuatan flow, DFD, ERD, laporan harcopy yang segepok dan banyak lagi hal-hal yang berbau teoritis yang menariknya belum pernah diajarkan sebelumnya kepada siswa, atau boleh juga dieja ‘sudah diajarkan tapi sedikit’, dimana point-point tersebut ada dalam lembar penilaian. Berbau menghakimi memang, yah tapi itu kenyataannya, dan saya yakin hal ini terjadi hampir di seluruh SMK (opini subjektif).

Maka dari itu sebagai rekanan industri yang baik #ceile disini saya akan membeberkan beberapa hal yang sering dilakukan siswa dalam tugas akhir yang menjadi point penilaian penguji yang sering luput dari bagian pengarahan pembimbing. Semoga dapat menjadi referensi untuk siswa SMK yang akan menghadapi tugas akhir agar tidak melakukan hal-hal di berikut.

Presentasi Software: Siswa selalu update, jaman semakin berkembang, tidak salah kalau presentasi harus pakai barang canggih. Maka dipakailah software yang bernama MS Office dengan versi keluaran minimal tahun 2007 (yang kita semua tahu sebagian bersar pasti bajakan).

Estetika: Banyak gambar-gambar bertebaran di slide yang akhirnya berkesan kurang profesional. Ada yang full manga, ada yang suka warna biru sampai semua tulisan dikasih biru dengan backgroundnya laut (mana kelihatan), yang ngefans ayu tingting juga gak mau kalah gitu juga, gak lah.

ERD: Sebagian besar menggunakan entity-relationship model

sebagian kecil lainnya menggunakan object-relational model

Saya juga baru tahu kalau ERD ada macam-macam modelnya :) tetapi object-relational model yang paling lazim digunakan dalam pembuatan aplikasi, ini yang bikin heran kenapa sebagian besar pakai entity-relational model.

Detail teknologi: hampir semua hanya menulis, “Java Web + MySql”, “PHP”, atau “Java Web + XAMPP” (gak paham yang ini), tanpa dijelaskan secara detail pustaka apa saja yang digunakan, padahal untuk java pasti buanyak pustaka yang dicomot.

Pembatasan Kasus

Ini yang paling suka saya bahas, pengalaman saya juga sebagai siswa biasanya minim ide. Banyak ide yang dibuat seolah berbeda padahal isinya sama, seperti Aplikasi Toko, ada yang membuat Toko Bola online, Toko Musik onlie, dan toko-toko yang lainnya. Disinilah ‘seharusnya’ peran pembimbing untuk mengarahkan siswa dalam hal kreatifitas yang sering luput.

Ketuntasan aplikasi: ada cerita menarik ketika saya berhadapan dengan siswa yang membuat sebuah aplikasi pemesanan lapangan futsal online.

Siswa : (sambil mendemokan aplikasi) “Berikut ini adalah form pemesanan. User yang akan menyewa lapangan harus mengisi form disini.”

Penguji : “Tidak ada register/login? Jadi orang tidak dikenal bisa langsung pesan?”

Siswa : “Mmmm, iya.”

Penguji : “Oke silakan dilanjutkan.”

Siswa : (Masuk halaman admin) “Kemudian orang yang pesan tadi datanya masuk ke halaman admin.”

Penguji : “Kalau ada orang yang mau pesan di jam yang sama?”

Siswa : “Tidak bisa.”

Penguji : “Untuk pembayarannya bagaimana?”

Siswa : “Ya… dibayar di tempat.”

Penguji : “Kalau yang pesan tidak hadir di hari H?”

Siswa : (hening)

Penguji : “Kalau yang pesan gitu semua gimana hayo?”

Siswa : (hening)

Penguji : (pasang muka baik) “Kan seharusnya ada konfirmasi pembayaran, biar gak bangkrut usahanya.”

Siswa : (meringis)

Penguji : “Jadi aplikasi kamu gak tuntas dong, mmm dikasih nilai berapa yah…”

Siswa : (mewek)

Sedikit percakapan diatas bisa menjadi sedikit gambaran bagaimana membuat aplikasi seharusnya tuntas, yah lagi-lagi peran pembimbing untuk melakukan check terhadap aplikasi siswa sebelum datang hari akhir (tugas akhir maksudnya).

Untuk sementara itu saja pengamatan saya tentang pelaksanaan tugas akhir kemarin, inti dari permasalahan yang saya angkat sebetulnya adalah kritikan untuk pembimbing sekolah yang terkadang (mohon maaf) kurang kejam untuk masalah lolos-meloloskan laporan akhir siswa, sehingga siswa seolah menjadi objek penyiksaan penguji eksternal, yang padahal memang sebetulnya aplikasinya belum layak untuk dijadikan tugas akhir. Tetapi terkadang malah diloloskan dengan alasan kasih sayang yang tanpa pandang bulu (opini subjektif). Masih banyak curahat yang belum sempat tersampaikan, mungkin lain kali bakal lebih panjang lagi bahasannya.

Semoga SMK makin maju. Salam “SMK Sakti Mandraguna, gak cuma bisa-bisaan…”

Criteria Query, Hibernate Dan JPA 2.0 (JPA2 Part 1)

Salah satu tambahan terbesar dari spesifikasi JPA (Java Persistence API) versi 2.0 adalah criteria query. Dirilis pada Desember 2009, JPA 2.0 menyediakan API baru yang memungkinkan penggunaan criteria query, meskipun kita tahu pada framework ORM seperti Hibernate sudah terlebih dahulu menyediakan criteria query sejak versi 3.0. Hmm, bagaimanapun JPA adalah spesifikasi standard untuk Persistence yang mana dengan JPA kita bisa memilih JPA provider seperti Hibernate, EclipseLink, OpenJPA, DataNucleus, ataupun ObjectDB sesuka hati tanpa perlu mengganti banyak konfigurasi karena seluruh abstraksi ada di bawah package javax.persistence.*

Pada postingan kali ini saya akan mengulas tentang penggunaan Criteria Query pada JPA (dengan Hibernate sebagai persistence provider) dan Qriteria Query pada Hibernate (native).

Sedikit berbeda dengan JPA 1.0, walaupun diklaim sebagai vendor-independent, kita tidak akan menemukan javax.persistence:javax.persistence:2.0 pada Maven Central, melainkan kita harus mencarinya pada masing-masing ORM vendor. Sebagai contoh jika kita menggunakan hibernate maka artifact untuk JPA 2.0 adalah

1
2
3
4
5
6
7
<dependency>
  <groupid>org.hibernate.javax.persistence</groupid>
  <artifactid>hibernate-jpa-2.0-api</artifactid>
  <version>1.0.0.Final</version>
  <type>jar</type>
  <scope>compile</scope>
</dependency>

Oke marilah langsung saja kita menuju ke area perangnya, dimisalkan saya memiliki sebuah entity (karyawan).

1
2
3
4
5
6
7
8
9
@Entity
@Table(name = "pegawai")
public class Pegawai {
  private long id;
  private String nama;
  private String telepon;
  private String alamat;
  // getter dan setter
}

Selanjutnya mari membuat sebuah JPA Query untuk menangani sebuah pencarian berdasarkan nama atau alamat pegawai.

1
SELECT p FROM Pegawai WHERE p.nama LIKE :nama OR p.alamat LIKE :alamat

Criteria Query

Hibernate

Citeria query pada hibernate umunya cukup mudah, kita tinggal mendefinisikan class entity pada saat pembuatan criteria, kemudian memasukkan masing-masing ekspresi menggunakan class org.hibernate.Criterion.

1
2
3
4
5
6
7
public List<pegawai> getKaryawanByCriteriaH(String nama, String alamat) {
  Session session = sessionFactory.getCurrentSession();
  Criteria criteria = session.createCriteria(Pegawai.class);
  criteria.add(Restrictions.like("nama", nama));
  criteria.add(Restrictions.like("alamat", alamat));
  return criteria.list();
}

JPA

1
2
3
4
5
6
7
public List<Pegawai> getKaryawanByCriteria(String nama, String alamat) {
  CriteriaBuilder builder = entityManager.getCriteriaBuilder();
  CriteriaQuery<Pegawai> query = builder.createQuery(Pegawai.class);
  Root <Pegawai> root = query.from(Pegawai.class);
  query.where(builder.like(root.<String>get("nama"), nama), builder.like(root.<String>get("alamat"), alamat));
  return entityManager.createQuery(query).getResultList();
}

Sekilas tidak jauh berbeda citeria query pada Hibernate dengan JPA, akan tetapi sedikit yang terlihat jelas spesifikasi JPA sedikit lebih kompleks (baca: njelimet) dibandingkan criteria query pada Hibernate.

JPA Metamodel

Criteria Query pada JPA berbasiskan metamodel dari class yang telah terdaftar pada Persistence Unit. JPA 2 mendefinisikan typesafe Criteria API baru yang mengizinkan criteria query dibangun secara rapi/kuat. Penggunaan meta model pada JPA dan beberapa metode otomasi pembuatannya akan saya bahas pada postingan selanjutnya.