<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Practical Wizardry</title>
	<atom:link href="http://wizardry.bungrudi.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://wizardry.bungrudi.com</link>
	<description>Small, simple, useful magic for everyday use</description>
	<lastBuildDate>Mon, 15 Aug 2011 01:45:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Kuis: Berapa Harganya?</title>
		<link>http://wizardry.bungrudi.com/archives/kuis-berapa-harganya/</link>
		<comments>http://wizardry.bungrudi.com/archives/kuis-berapa-harganya/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 02:31:36 +0000</pubDate>
		<dc:creator>Rudi Adianto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://wizardry.bungrudi.com/?p=128</guid>
		<description><![CDATA[Beberapa barang di supermarket mempunyai harga yang sederhana, misalnya sebotol air mineral harganya Rp. 2500. Tetapi ada juga yang mempunyai pricing yang rumit, misalnya: kaos kaki 3 pasang seharga Rp. 10.000 (jadi berapa harganya kalau kita membeli 4 atau 5?) daging ayam Rp. 9.999 per pon (jadi berapa harga untuk 4 ons?) minuman kaleng promo [...]]]></description>
			<content:encoded><![CDATA[<p>Beberapa barang di supermarket mempunyai harga yang sederhana, misalnya sebotol air mineral harganya Rp. 2500. Tetapi ada juga yang mempunyai <em>pricing</em> yang rumit, misalnya:</p>
<ul>
<li>kaos kaki 3 pasang seharga Rp. 10.000 (jadi berapa harganya kalau kita membeli 4 atau 5?)</li>
<li>daging ayam Rp. 9.999 per pon (jadi berapa harga untuk 4 ons?)</li>
<li>minuman kaleng promo beli 2 dapat 3 (apakah kaleng yang ke-3 ada harganya?)</li>
</ul>
<p>Buatlah domain model yang merepresentasikan uang dan harga yang cukup fleksibel untuk mengakomodasi skenario diatas dan skenario-skenario <em>pricing </em>lain yang mungkin muncul kemudian.</p>
<p>Jawaban boleh dalam bentuk <em>class diagram </em>atau code dalam bahasa pemrograman OOP, dan harus disertai dengan penjelasan singkat.</p>
<p><em>Have fun !</em></p>
]]></content:encoded>
			<wfw:commentRss>http://wizardry.bungrudi.com/archives/kuis-berapa-harganya/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kuis: Devide et Impera</title>
		<link>http://wizardry.bungrudi.com/archives/kuis-devide-et-impera/</link>
		<comments>http://wizardry.bungrudi.com/archives/kuis-devide-et-impera/#comments</comments>
		<pubDate>Mon, 02 Aug 2010 15:04:14 +0000</pubDate>
		<dc:creator>Rudi Adianto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://wizardry.bungrudi.com/?p=115</guid>
		<description><![CDATA[Misalkan X adalah sebuah array integer yang isinya diurutkan menurut besarnya, misal: [1,3,12,17,21,50,71,121,461,888,1121,1141,1821,3345]. Salah satu cara tercepat untuk mencari lokasi sebuah bilangan N adalah sebagai berikut: Ambil bilangan yang berada di tengah array sebagai O. Bila O sama dengan N, maka kita telah menemukan lokasi bilangan yang kita cari dan pencarian dihentikan. Bila tidak maka [...]]]></description>
			<content:encoded><![CDATA[<p>Misalkan X adalah sebuah array integer yang isinya diurutkan menurut besarnya, misal: [1,3,12,17,21,50,71,121,461,888,1121,1141,1821,3345].</p>
<p>Salah satu cara tercepat untuk mencari lokasi sebuah bilangan N adalah sebagai berikut:</p>
<ol>
<li>Ambil bilangan yang berada di tengah array sebagai O. Bila O sama dengan N, maka kita telah menemukan lokasi bilangan yang kita cari dan pencarian dihentikan. Bila tidak maka langkah ke 2.</li>
<li>Operasi nomor 1 telah membagi X menjadi 2 sub array. Pilih 1 dari 2 array tersebut dimana N berada didalamnya, lalu lakukan langkah 1 terhadap array tersebut.</li>
</ol>
<p>Buatlah sebuah prosedur yang mengimplementasikan algoritma diatas dalam dua bentuk:</p>
<ol>
<li>menggunakan fungsi rekursif.</li>
<li> menggunakan loop.</li>
</ol>
<p>Code boleh dalam <em>pseudo code</em> atau dalam bahasa pemrograman imperatif (C, C++, Java, PHP, Ruby atau sejenisnya).</p>
<p><em>Have fun&#8230;</em> <img src='http://wizardry.bungrudi.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://wizardry.bungrudi.com/archives/kuis-devide-et-impera/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kuis: menjelajahi pohon</title>
		<link>http://wizardry.bungrudi.com/archives/kuis-menjelajahi-pohon/</link>
		<comments>http://wizardry.bungrudi.com/archives/kuis-menjelajahi-pohon/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 01:30:21 +0000</pubDate>
		<dc:creator>Rudi Adianto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://wizardry.bungrudi.com/?p=104</guid>
		<description><![CDATA[Perhatikan struktur data berikut ini, public class Wadah { public String Id; public Set&#60;Wadah&#62; anakAnak; } Struktur data tersebut dirangkai sedemikian rupa hingga membentuk rangkaian hirarkis seperti ilustrasi ini. Setiap kotak dalam ilustrasi tersebut adalah sebuah instance dari kelas Wadah. Tuliskan code (boleh pseudo code) yang akan menjelajahi hirarki tersebut sehingga seluruh wadah terjelajahi, dengan [...]]]></description>
			<content:encoded><![CDATA[<p>Perhatikan struktur data berikut ini,</p>
<pre class="java" name="code">public class Wadah {
   public String Id;
   public Set&lt;Wadah&gt; anakAnak;
}</pre>
<p>Struktur data tersebut dirangkai sedemikian rupa hingga membentuk rangkaian hirarkis seperti ilustrasi <a href="http://bungrudi.com/files/treef.jpg" target="_blank">ini</a>. Setiap kotak dalam ilustrasi tersebut adalah sebuah <em>instance</em> dari kelas <em>Wadah</em>.</p>
<p>Tuliskan code (boleh pseudo code) yang akan menjelajahi hirarki tersebut sehingga seluruh wadah terjelajahi, dengan aturan sebagai berikut:</p>
<ul>
<li>Untuk setiap wadah print di layar field &#8220;Id&#8221;-nya.</li>
<li>Untuk setiap wadah yang tidak punya anak, print di layar &#8220;tidak punya anak.&#8221;</li>
</ul>
<p><em>Have fun..</em> <img src='http://wizardry.bungrudi.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://wizardry.bungrudi.com/archives/kuis-menjelajahi-pohon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Konfigurasi aplikasi SEAM untuk multiple deployment dalam 1 server</title>
		<link>http://wizardry.bungrudi.com/archives/konfigurasi-aplikasi-seam-untuk-multiple-deployment-dalam-1-server/</link>
		<comments>http://wizardry.bungrudi.com/archives/konfigurasi-aplikasi-seam-untuk-multiple-deployment-dalam-1-server/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 07:20:43 +0000</pubDate>
		<dc:creator>Rudi Adianto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://wizardry.bungrudi.com/?p=95</guid>
		<description><![CDATA[Objective: aplikasi SEAM yang sama dapat di deploy sebagai 2 (atau lebih) aplikasi dalam satu application server yang sama. How? Gunakan ant build script ini untuk menggantikan build script asli dari seam gen. Yang perlu Anda ketahui dari script ini adalah property &#60;property name=&#8221;application.name&#8221; value=&#8221;aps2&#8243;/&#62;. Disinilah Anda menentukan nama aplikasi yang akan membedakan satu deployment [...]]]></description>
			<content:encoded><![CDATA[<p>Objective: aplikasi SEAM yang sama dapat di deploy sebagai 2 (atau lebih) aplikasi dalam satu application server yang sama.</p>
<p>How?</p>
<ol>
<li>Gunakan ant build script <a title="build.xml" href="http://wizardry.bungrudi.com/files/build.xml">ini</a> untuk menggantikan build script asli dari seam gen. Yang perlu Anda ketahui dari script ini adalah property &lt;property name=&#8221;application.name&#8221; value=&#8221;aps2&#8243;/&gt;. Disinilah Anda menentukan nama aplikasi yang akan membedakan satu deployment dengan yang lainnya.</li>
<li>Buka file application.xml, ubah semua kata-kata &#8220;namaProject&#8221; (dimana namaProject adalah nama project yang anda tentukan ketika membuat sebuah project baru melalui seam-gen) menjadi @APPNAME@. Contoh lengkapnya menjadi seperti file <a title="application.xml" href="http://wizardry.bungrudi.com/files/application.xml">ini</a>.</li>
<li>Lakukan langkah diatas untuk file-file berikut ini: jboss-app.xml, components.xml, namaProject-dev-ds.xml, namaProject-prod-ds.xm, components-dev.properties, components-prod.properties</li>
<li>Lakukan langkah diatas untuk persistence-dev.xml dan persistence-prod.xml, dan persistence-test.xml, tapi tinggalkan &lt;persistence-unit name=&#8221;namaProject&#8221;&gt; seperti aslinya.</li>
</ol>
<p>Untuk me-deploy aplikasi dengan nama yang berbeda,</p>
<ol>
<li>ubah property &#8220;application.name&#8221; di build.xml,</li>
<li>jalankan target &#8220;clean&#8221;</li>
<li>jalankan deploy/explode</li>
</ol>
<p>Kunci dari trik ini adalah fitur <a title="filterset di Ant" href="http://ant.apache.org/manual/CoreTypes/filterset.html">filterset</a> dari Ant.</p>
]]></content:encoded>
			<wfw:commentRss>http://wizardry.bungrudi.com/archives/konfigurasi-aplikasi-seam-untuk-multiple-deployment-dalam-1-server/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Apa itu &#8220;LazyInitializationException&#8221; dan Cara Mencegahnya</title>
		<link>http://wizardry.bungrudi.com/archives/apa-itu-lazyinitializationexception-dan-cara-mencegahnya/</link>
		<comments>http://wizardry.bungrudi.com/archives/apa-itu-lazyinitializationexception-dan-cara-mencegahnya/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 08:32:44 +0000</pubDate>
		<dc:creator>Rudi Adianto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://wizardry.bungrudi.com/?p=74</guid>
		<description><![CDATA[Umpamakan skenario berikut ini. Ada dua entity yang mempunyai relasi parent-child dan multiplicity one-to-many. Entity Order mempunyai beberapa OrderItem. Order 1 &#8212;-&#62; 0..* OrderItem Class untuk entity Order kira-kira seperti berikut. @Entity @Table(name = "table_order") public class Order implements java.io.Serializable { private Long id; private List&#60;OrderItem&#62; orderItems; @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "id", unique [...]]]></description>
			<content:encoded><![CDATA[<p>Umpamakan skenario berikut ini. Ada dua <em>entity</em> yang mempunyai relasi <em>parent-child</em> dan <em>multiplicity one-to-many</em>. Entity Order mempunyai beberapa OrderItem.</p>
<p>Order  1 &#8212;-&gt; 0..*  OrderItem</p>
<p>Class untuk entity Order kira-kira seperti berikut.</p>
<pre class="java" name="code">@Entity
@Table(name = "table_order")
public class Order implements java.io.Serializable {

	private Long id;

        private List&lt;OrderItem&gt; orderItems;

        @Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "id", unique = true, nullable = false)
	public Long getId() {
		return this.id;
	}

	public void setId(Long id) {
		this.id = id;
	}

        public List&lt;OrderItem&gt; getOrderItems() {
                return orderItems;
        }

        public void setOrderItems(List&lt;OrderItem&gt; orders) {
                orderItems = orders;
        }
}</pre>
<p>Relasi dari Order ke OrderItem diwakili oleh property &#8220;orderItems&#8221; yang merupakan sebuah <a href="http://java.sun.com/docs/books/tutorial/collections/index.html"><em>Collection</em></a>. Pada saat aplikasi dijalankan, <em>code </em>berikut bisa jadi akan melemparkan <em>LazyInitializationException</em>.</p>
<pre class="java" name="code">order.getOrderItems().get(0);</pre>
<p>Atau bisa juga <em>code </em>berikut ini.</p>
<pre class="java" name="code">for(OrderItem item:order.getOrderItems()) {
  // do something..
}</pre>
<p>Kedua <em>code</em> diatas melakukan hal yang sama: mengakses relasi dari sebuah objek entity.</p>
<p>Jadi kenapa Anda mendapatkan <em>LazyInitializationException</em>?</p>
<p>Ada kalanya relasi dari sebuah entity melibatkan ribuan baris data. Dalam kasus kita, misalkan ada beberapa Order yang memiliki OrderItem sebanyak lebih dari 100 ribu. Ini tentu akan mempengaruhi <em>loading</em> <em>time</em>, dan akan sia-sia kalau kita tidak menggunakan data dari relasi tersebut. Hibernate mempunyai cara untuk menyelesaikan hal ini.</p>
<p>Secara default, relasi dari sebuah entity adalah <em>lazy </em>(kecuali kita menyatakan sebaliknya. Ini disebut <em>fetching strategy</em>. Untuk konfigurasi dan cara-cara untuk setting <em>fetching strategy</em>/<em>eagerness</em> silakan lihat disini dan <a href="http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/">disini</a>). Artinya, relasi tersebut tidak akan di <em>load</em> (tidak disertakan dalam query) pada saat entity induk di<em>load</em> dari database. Relasi tersebut akan diinisiasi pada saat dibutuhkan (pada saat diakses pertama kali)<em> </em>. Pada contoh kasus kita, pada saat order di load pertama kali,berarti hanya Order saja yang di<em>load</em>, sedangkan OrderItem tidak akan di load sampai kita mengakses relasi tersebut (misal order.getOrderItems().get(0) ).</p>
<p>Cara Hibernate melakukan hal tersebut adalah seperti berikut. Umpamakan <em>code </em>berikut ini.</p>
<pre class="java" name="code">Order order = getOrder();
order.getId();
order.getOrderItems().get(0);</pre>
<p>Pada saat <em>runtime</em>, objek entity yang ditunjuk oleh suatu <em>reference</em> (variable) bisa jadi bukan kelas asli dari objek tersebut, tetapi suatu kelas turunan yang disebut <em>proxy</em>. Jadi dalam kasus kita, variable &#8220;order&#8221; sebenarnya menunjuk ke suatu objek yang <em>class</em>nya bukan  &#8220;Order&#8221;, tetapi &#8220;OrderProxy&#8221; (bukan nama class sebenarnya, hanya untuk ilustrasi). OrderProxy ini kebanyakan hanya mendelegasikan pemanggilan method ke objek yang asli. Kecuali untuk method yang mengembalikan suatu relasi yang sifatnya <em>lazy</em>. (&#8230;bingung&#8230;? tahan sebentar..)</p>
<p>Pada keadaan normal (dimana kita tidak menggunakan Hibernate dan tidak ada <em>proxy</em> yang terlibat), <em>code</em> diatas skemanya adalah seperti dalam diagram berikut (dimulai dari <em>line</em> 2).</p>
<p><img class="alignnone size-full wp-image-83" title="seq-no-proxy" src="http://wizardry.bungrudi.com/wp-content/uploads/2009/09/seq-no-proxy.jpg" alt="seq-no-proxy" width="303" height="189" /></p>
<p>Sedangkan bila kita menggunakan Hibernate, maka skemanya akan jadi &#8220;sedikit&#8221; lebih rumit.</p>
<p><img class="alignnone size-full wp-image-86" title="seq-proxy" src="http://wizardry.bungrudi.com/wp-content/uploads/2009/09/seq-proxy.jpg" alt="seq-proxy" width="695" height="385" /></p>
<p>(Disclaimer: beberapa nama kelas diatas bukan nama yang sesungguhnya. Nama-nama tersebut adalah karangan penulis sekedar untuk menyederhanakan ilustrasi)</p>
<p>Sekarang ada sebuah <em>proxy</em> diantara <em>current thread</em> dan object Order. <em>Proxy </em>tersebut akan mencegat semua pemanggilan method. Bila method tersebut tidak melibatkan akses ke relasi yang <em>lazy</em>, maka pemanggilan method tersebut akan diteruskan ke objek Order yang asli. Bila suatu pemanggilan method melibatkan akses ke suatu relasi yang sifatnya <em>lazy</em>, maka prosedur untuk inisiasi relasi tersebut akan dilakukan. Didalam prosedur tersebut salah satunya adalah melakukan <em>query </em>ke database (untuk me<em>load</em> OrderItem). Untuk melakukan ini, maka Hibernate berusaha mendapatkan referensi ke <em>persistence context</em> (EntityManager) yang bertanggung jawab terhadap EntityTersebut (gampangnya, EntityManager yang me<em>load</em> entity tersebut). Prosedur tersebut ditandai dengan warna merah pada diagram diatas. Bila <em>persistence context</em> yang terkait dengan entity tersebut telah berakhir (atau tidak dapat dijangkau), maka Hibernate tidak dapat melakukan query ke database, dan pada akhirnya gagal untuk melakukan inisiasi relasi yang <em>lazy</em> diatas. Pada saat inilah Anda akan mendapatkan <em>LazyInitializationException</em>.</p>
<p>Entity yang tidak mempunyai <em>persistence context</em> (tidak ter<em>manage</em>) ini disebut dengan istilah <em>detached entity</em>.</p>
<p>Jadi bagaimana cara mencegahnya?</p>
<p>Yang harus Anda lakukan adalah mengaitkan <em>detached</em> <em>entity </em>kepada suatu <em>persistence context</em>. Jika Anda menggunakan Hibernate API, salah satu dari <em>line</em> dibawah ini dapat digunakan.</p>
<pre class="java" name="code">session.update(order); // gunakan bila Anda sekaligus hendak mengupdate
session.merge(order); // gunakan bila Anda sekaligus hendak mengupdate, tapi hati2 karena optimistic locking tidak akan bekerja jika Anda menggunakan fungsi ini
session.lock(order,LockType.NONE); // ini cara yang paling benar</pre>
<p>Bila Anda menggunakan JPA, lakukan seperti berikut.</p>
<pre class="java" name="code">order = entityManager.merge(order);</pre>
<p>Perhatikan bahwa kita perlu menampung nilai kembalian dari merge(), karena fungsi tersebut membuat sebuah objek baru di heap. Objek yang lama akan tetap dalam keadaan <em>detached</em>.</p>
<p>Semoga bermanfaat.</p>
]]></content:encoded>
			<wfw:commentRss>http://wizardry.bungrudi.com/archives/apa-itu-lazyinitializationexception-dan-cara-mencegahnya/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SEAM &amp; JSF: validasi application-level</title>
		<link>http://wizardry.bungrudi.com/archives/seam-jsf-validasi-application-level/</link>
		<comments>http://wizardry.bungrudi.com/archives/seam-jsf-validasi-application-level/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 08:13:57 +0000</pubDate>
		<dc:creator>Rudi Adianto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[JSF]]></category>
		<category><![CDATA[SEAM]]></category>

		<guid isPermaLink="false">http://wizardry.bungrudi.com/?p=60</guid>
		<description><![CDATA[Objektif Ada dua macam validasi di JSF, field-level dan application-level. (lihat disini). Artikel ini akan memuat contoh untuk melakukan validasi application-level di SEAM dan JSF. Sebagai contoh adalah sebuah halaman dengan 2 field, jumlahSatu dan jumlahDua, masing-masing di bind ke property sebuah bean. Validasi yang dilakukan adalah &#8220;bila jumlahSatu &#60; 10, maka jumlahDua harus &#62; [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Objektif</strong></p>
<p>Ada dua macam validasi di JSF, <em>field-level</em> dan <em>application-level</em>. (lihat <a href="http://www.ibm.com/developerworks/library/j-jsf3/">disini</a>). Artikel ini akan memuat contoh untuk melakukan validasi <em>application-level </em>di SEAM dan JSF.</p>
<p>Sebagai contoh adalah sebuah halaman dengan 2 field, jumlahSatu dan jumlahDua, masing-masing di <em>bind</em> ke property sebuah bean. Validasi yang dilakukan adalah &#8220;bila jumlahSatu &lt; 10, maka jumlahDua harus &gt; 10.&#8221;</p>
<p>SEAM SDK yang digunakan adalah versi 2.1.1.GA. Konfigurasi SEAM yang digunakan default dari seam-gen.</p>
<p><strong>Implementasi</strong></p>
<p>Bean yang akan dijadikan penampung value adalah berikut ini.</p>
<pre class="java" name="code">public class OrderItem implements Serializable {
  private BigDecimal jumlahSatu;
  private BigDecimal jumlahDua;

  public void setJumlahSatu(BigDecimal jml) {
    jumlahSatu = jml;
  }

  public BigDecimal getJumlahSatu() {
    return jumlahSatu;
  }

  public void setJumlahDua(BigDecimal jml) {
    jumlahDua = jml;
  }

  public BigDecimal getJumlahdua() {
    return jumlahDua;
  }
}</pre>
<p>Kita memerlukan satu komponen SEAM khusus untuk menempatkan <em>backing bean</em> dari komponen-komponen yang akan kita validasi.</p>
<pre class="java" name="code">@Name("penampungKomponen")
@Scope(ScopeType.EVENT)
public class PenampungKomponen implements Serializable {
  private UIInput tfJumlahSatu;
  private UIInput tfJumlahDua;

  public void setTfJumlahSatu(UIInput tf) {
    tfJumlahSatu = tf;
  }

  public UIInput getTfJumlahSatu() {
    return tfJumlahSatu;
  }

  public void setTfJumlahDua(UIInput tf) {
    tfJumlahDua = tf;
  }

  public UIInput getTfJumlahDua() {
    return tfJumlahDua;
  }
}</pre>
<p>Kenapa kita membutuhkan penampung khusus seperti diatas? Karena kita tidak bisa mem-<em>bind</em> komponen JSF ke komponen SEAM yang <em>scope</em>nya selain EVENT.</p>
<p>Halaman JSF yang harus dibuat adalah seperti ini.</p>
<pre class="xml" name="code">&lt;!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;ui:composition xmlns="http://www.w3.org/1999/xhtml"
 xmlns:s="http://jboss.com/products/seam/taglib"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:a="http://richfaces.org/a4j"
 xmlns:rich="http://richfaces.org/rich"
 template="layout/template.xhtml"&gt;

&lt;ui:define name="body"&gt;

 &lt;h:form id="purchaseOrder" styleClass="edit"&gt;
   &lt;h:inputText id="tfJumlahSatu"
     required="true"
     size="50"
     maxlength="50"
     binding="#{penampungKomponen.jumlahSatu}"
     value="#{orderAction.item.jumlahSatu}"/&gt;
   &lt;s:message styleClass="errors"/&gt;
   &lt;br/&gt;
   &lt;h:inputText id="tfJumlahDua"
     required="true"
     size="50"
     maxlength="50"
     binding="#{penampungKomponen.jumlahDua}"
     value="#{orderAction.item.jumlahDua}"/&gt;
   &lt;s:message styleClass="errors"/&gt;
   &lt;br/&gt;
   &lt;h:commandButton id="save"
     value="Save"
     action="#{orderAction.doAction}"/&gt;
   &lt;/h:form&gt;
&lt;/ui:define&gt;
&lt;/ui:composition&gt;</pre>
<p>Perhatikan di line 21 dan 29 terdapat komponen untuk menampilkan <em>message</em> yang berkaitan dengan komponen input sebelumnya.</p>
<p>Berikut ini adalah komponen SEAM dimana terdapat <em>action</em> dan validasi.</p>
<pre class="java" name="code">@Name("orderAction")
@Scope(ScopeType.SESSION)
public class OrderAction implements Serializable {
  @In(create=true) PenampungKomponen penampungKomponen;
  @In FacesMessages facesMessages;

  private OrderItem item;

  public void doAction {
    if(item.getJumlahSatu().compareTo(new BigDecimal(10)) &lt; 0 &amp;&amp;
       item.getJumlahDua().compareTo(new BigDecimal(10)) &lt; 0) {

       facesMessages.addToControlFromResourceBundle(penampungKomponen.getTfJumlahSatu().getId(), "validation.kurangDariSepuluh", item.getJumlahSatu());
       penampungKomponen.getJumlahSatu().setValid(false);
    }
    else {
       // berhasil
    }
  }

  public void setItem(OrderItem itm) {
    item = itm;
  }

  public OrderItem getItem() {
    return item;
  }
}</pre>
<p>Perhatikan di line 13, kita membuat suatu <em>message</em> dan dikaitkan dengan suatu komponen JSF tertentu. Ini akan membuat <em>message </em>tersebut muncul disampingnya (karena di halaman JSF diatas kita menempatkan &lt;s:message/&gt; disamping &lt;h:inputText/&gt;). Kemudian di line 14 kita menandai bahwa komponen tersebut memiliki nilai yang tidak valid. Lalu apa yang akan muncul di layar?</p>
<p>Bagian terakhir adalah file messages_en.properties. Tambahkan entry berikut ini didalamnya.</p>
<pre name="code">validation.kurangDariSepuluh=Bila jumlahSatu bernilai #0, maka jumlahDua harus &gt; 10</pre>
<p>Selamat mencoba.</p>
]]></content:encoded>
			<wfw:commentRss>http://wizardry.bungrudi.com/archives/seam-jsf-validasi-application-level/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SEAM 2.1.x dengan Multi Database</title>
		<link>http://wizardry.bungrudi.com/archives/seam-2-1-x-dengan-multi-database/</link>
		<comments>http://wizardry.bungrudi.com/archives/seam-2-1-x-dengan-multi-database/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 04:17:21 +0000</pubDate>
		<dc:creator>Rudi Adianto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[SEAM]]></category>
		<category><![CDATA[transaction]]></category>
		<category><![CDATA[XA transaction]]></category>

		<guid isPermaLink="false">http://wizardry.bungrudi.com/?p=13</guid>
		<description><![CDATA[Yak, tepat. Bagaimana caranya mengkonfigurasi aplikasi SEAM 2.1.x supaya bisa menggunakan lebih dari satu database? Inilah menu hari ini.]]></description>
			<content:encoded><![CDATA[<p><strong>Objektif</strong></p>
<p>Use case yang saya dapatkan adalah seperti berikut ini. Sebuah aplikasi dibangun dengan model <a href="http://en.wikipedia.org/wiki/Software_as_a_service">SaaS</a>. Setiap klien akan punya database sendiri. Berdasarkan kebutuhan tersebut, maka kira-kira nantinya akan terdapat sekitar 50 database dengan struktur (table-tablenya) yang sama persis. Karena database yang digunakan tergantung login credential, maka database mana yang akan digunakan ditentukan pada saat user login.</p>
<p>Kasusnya jadi tambah menarik karena ada kebutuhan transaksi antar database. Jadi, sebuah transaksi bisa melibatkan posting data ke dua koneksi database yang berbeda. Misalkan, sebuah transaksi bisnis melibatkan perpindahan dana antar klien, yang artinya akun klien A harus didebet dan akun klien B harus dikredit. Akun klien A dan klien berada di database yang berbeda, tapi transaksi tersebut harus diselesaikan sebagai satu kesatuan.</p>
<p><strong>Solusi</strong></p>
<p>(Sebelum Anda baca terlalu jauh, perhatikan bahwa solusi ini spesifik untuk Hibernate 3.x, JPA atau non-JPA)</p>
<p>Dalam melakukan akses data, komponen yang kita buat tidak berhubungan langsung dengan JDBC API. Komponen-komponen tersebut berinteraksi dengan satu lapisan abstraksi yang biasa disebut <a href="http://en.wikipedia.org/wiki/Object-relational_mapping"><em>Object Relational Mapping</em></a> (ORM).  Bila kita menuruti spek standar JEE 5 (setting standar SEAM menggunakan ini) yang sering disebut dengan JPA, maka interface yang kita gunakan untuk akses data adalah <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnbqw.html">EntityManager</a>. Bila kita menggunakan Hibernate, maka interface yang kita gunakan adalah <a href="https://www.hibernate.org/42.html">Session</a>.</p>
<p><strong><img class="alignnone size-full wp-image-17" title="data-access-1" src="http://wizardry.bungrudi.com/wp-content/uploads/2009/09/data-access-1.jpg" alt="data-access-1" width="382" height="97" /></strong></p>
<p>Sebuah aplikasi SEAM hasil generate dari seam-gen, pada kondisi default, mempunyai konfigurasi seperti diagram diatas. Komponen-komponen yang kita buat (atau hasil generate dari seam-gen) berinteraksi dengan sebuah EntityManager, yang mana EntityManager tersebut menggunakan sebuah koneksi database. (AWAS: ini adalah penyederhanaan. Buat Anda yang punya pemahaman mendalam tentang JEE tentu tahu jika yang saya bicarakan disini adalah dalam konteks suatu <em>persistence context</em>. EntityManager yang kedua juga berarti ada <em>persistence unit</em> yang kedua. Untuk keterangan lihat <a href="http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/architecture.html">disini</a>).</p>
<p>Jadi, bagaimana caranya supaya kita bisa menggunakan beberapa koneksi database yang berbeda, dan menentukan koneksi mana yang dipakai pada saat tertentu? Triknya adalah <span style="text-decoration: underline;">dengan mengimplementasi interface <a href="https://www.hibernate.org/hib_docs/v3/api/org/hibernate/connection/ConnectionProvider.html">org.hibernate.connection.ConnectionProvider</a></span>. ConnectionProvider digunakan oleh Hibernate untuk mendapatkan koneksi database ketika sebuah session baru dibuat. (saya mempelajari trik ini dari <a href="http://www.javalobby.org/java/forums/t18406.html">sini</a>).</p>
<p>Jadi, pada intinya kita sediakan beberapa koneksi database, dan kita sediakan pula implementasi ConnectionProvider yang akan memilih salah satu dari koneksi tersebut berdasarkan user yang sedang login. Diagram diatas seharusnya berubah menjadi seperti berikut ini.<br />
<img title="data-access-2" src="http://wizardry.bungrudi.com/wp-content/uploads/2009/09/data-access-2.jpg" alt="data-access-2" width="382" height="97" /></p>
<p>Masalah lain yang harus diselesaikan adalah, kasus ini melibatkan transaksi antar database. Jadi dalam <span style="text-decoration: underline;">satu transaksi bisa melibatkan lebih dari satu koneksi database</span>. Kita akan melakukannya dengan menambahkan satu lagi EntityManager kedalam aplikasi.  EntityManager kedua ini akan membungkus koneksi database kedua yang juga harus berpartisipasi dalam transaksi tersebut. Diagram diatas akan berubah lagi menjadi seperti berikut ini.</p>
<p><img class="alignnone size-full wp-image-25" title="data-access-3" src="http://wizardry.bungrudi.com/wp-content/uploads/2009/09/data-access-3.jpg" alt="data-access-3" width="382" height="97" /></p>
<p>Lalu bagaimana dengan transaksi database? Dalam kasus ini, dua atau lebih koneksi database harus berpartisipasi dalam sebuah transaksi yang sama. Tidak ada masalah&#8230; Kita hanya harus merubah tipe koneksi, dari yang tadinya &#8220;local-transaction&#8221; menjadi &#8220;<span style="text-decoration: underline;">xa-transaction</span>&#8220;. (bagi yang ingin tahu lebih banyak tentang apa itu <em>local-transaction </em>dan <em>xa-transaction</em>, silakan baca <a href="http://www.theserverside.com/discussions/thread.tss?thread_id=21385#95308">ini</a>, <a href="http://www.infoq.com/minibooks/JTDS">ini</a>, dan lihat <a href="http://www.infoq.com/presentations/native-transactions-java-spring">video ini</a>).</p>
<p>Ok, selanjutnya tinggal bagian mudahnya.. implementasi <img src='http://wizardry.bungrudi.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Implementasi</strong></p>
<p>Definisikan koneksi-koneksi database yang akan digunakan kedalam file xxx-ds.xml. Semua koneksi tersebut <strong>boleh</strong> berada di lebih dari satu file.</p>
<pre class="xml" name="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;

&lt;!DOCTYPE datasources
 PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
 "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd"&gt;

&lt;datasources&gt;
 &lt;xa-datasource&gt;
   &lt;jndi-name&gt;SALES_APPDatasource&lt;/jndi-name&gt;
   &lt;xa-datasource-class&gt;com.mysql.jdbc.jdbc2.optional.MysqlXADataSource&lt;/xa-datasource-class&gt;
   &lt;xa-datasource-property name="URL"&gt;jdbc:mysql://localhost:3306/sales_app&lt;/xa-datasource-property&gt;
   &lt;user-name&gt;root&lt;/user-name&gt;
   &lt;transaction-isolation&gt;TRANSACTION_READ_COMMITTED&lt;/transaction-isolation&gt;
   &lt;track-connection-by-tx /&gt;
   &lt;max-pool-size&gt;5&lt;/max-pool-size&gt;
   &lt;min-pool-size&gt;1&lt;/min-pool-size&gt;
   &lt;blocking-timeout-millis&gt;2000&lt;/blocking-timeout-millis&gt;
   &lt;idle-timeout-minutes&gt;2&lt;/idle-timeout-minutes&gt;
   &lt;no-tx-separate-pools/&gt;
   &lt;exception-sorter-class-name&gt;
       org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
   &lt;/exception-sorter-class-name&gt;
 &lt;/xa-datasource&gt;

 &lt;xa-datasource&gt;
   &lt;jndi-name&gt;SALES_APPDatasource2&lt;/jndi-name&gt;
   &lt;xa-datasource-class&gt;com.mysql.jdbc.jdbc2.optional.MysqlXADataSource&lt;/xa-datasource-class&gt;
   &lt;xa-datasource-property name="URL"&gt;jdbc:mysql://localhost:3306/sales_app2&lt;/xa-datasource-property&gt;
   &lt;user-name&gt;root&lt;/user-name&gt;
   &lt;transaction-isolation&gt;TRANSACTION_READ_COMMITTED&lt;/transaction-isolation&gt;
   &lt;track-connection-by-tx /&gt;
   &lt;max-pool-size&gt;5&lt;/max-pool-size&gt;
   &lt;min-pool-size&gt;1&lt;/min-pool-size&gt;
   &lt;blocking-timeout-millis&gt;2000&lt;/blocking-timeout-millis&gt;
   &lt;idle-timeout-minutes&gt;2&lt;/idle-timeout-minutes&gt;
   &lt;no-tx-separate-pools/&gt;
   &lt;exception-sorter-class-name&gt;
     org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
   &lt;/exception-sorter-class-name&gt;
 &lt;/xa-datasource&gt;

 &lt;xa-datasource&gt;
   &lt;jndi-name&gt;SALES_APPDatasource3&lt;/jndi-name&gt;
   &lt;xa-datasource-class&gt;com.mysql.jdbc.jdbc2.optional.MysqlXADataSource&lt;/xa-datasource-class&gt;
   &lt;xa-datasource-property name="URL"&gt;jdbc:mysql://localhost:3306/sales_app3&lt;/xa-datasource-property&gt;
   &lt;user-name&gt;root&lt;/user-name&gt;
   &lt;transaction-isolation&gt;TRANSACTION_READ_COMMITTED&lt;/transaction-isolation&gt;
   &lt;track-connection-by-tx /&gt;
   &lt;max-pool-size&gt;5&lt;/max-pool-size&gt;
   &lt;min-pool-size&gt;1&lt;/min-pool-size&gt;
   &lt;blocking-timeout-millis&gt;2000&lt;/blocking-timeout-millis&gt;
   &lt;idle-timeout-minutes&gt;2&lt;/idle-timeout-minutes&gt;
   &lt;no-tx-separate-pools/&gt;
   &lt;exception-sorter-class-name&gt;
     org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
   &lt;/exception-sorter-class-name&gt;
 &lt;/xa-datasource&gt;
&lt;/datasources&gt;</pre>
<p>Perhatikan bahwa <em>driver class</em> untuk XA berbeda dengan <em>driver</em> untuk koneksi <em>local transaction</em>. Silakan cari nama <em>XA driver class </em>yang untuk RDBMS yang Anda cari di <a href="http://www.google.com">google</a> <img src='http://wizardry.bungrudi.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Khusus untuk database MySQL yang saya gunakan ketika membuat prototype, property max-pool-size, min-pool-size, dan no-tx-separate-pools harus disertakan (kenapa? belum tau <img src='http://wizardry.bungrudi.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ). Untuk keterangan mengenai property-property tersebut silakan lihat <a href="http://www.jboss.org/community/wiki/ConfigDataSources">disini</a>.</p>
<p>Selanjutnya, tambahkan konfigurasi untuk <em>persistence unit</em> di components.xml dan persistence.xml. Disini kita akan menggunakan 2 <em>persistence unit</em> yang berbeda karena sebuah transaksi paling banyak akan menyertakan 2 koenksi database yang berbeda pula. Jika koneksi database yang diperlukan sebanyak 5 maka kita memerlukan 5 <em>persistence unit</em> yang berbeda.</p>
<pre class="xml" name="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
 version="1.0"&gt;

 &lt;persistence-unit name="SALES_APP"&gt;
   &lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;
   &lt;jta-data-source&gt;java:/SALES_APPDatasource3&lt;/jta-data-source&gt;
   &lt;properties&gt;
     &lt;property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/&gt;
     &lt;property name="hibernate.hbm2ddl.auto" value="update"/&gt;
     &lt;property name="hibernate.show_sql" value="true"/&gt;
     &lt;property name="hibernate.format_sql" value="true"/&gt;
     &lt;property name="hibernate.connection.provider_class" value="com.rudi.framework.MyConnectionProvider" /&gt;
     &lt;property name="jboss.entity.manager.factory.jndi.name" value="java:/SALES_APPEntityManagerFactory"/&gt;
     &lt;property name="mfin.datasource.name" value="dataSourceName"/&gt;
 &lt;/properties&gt;
 &lt;/persistence-unit&gt;
   &lt;persistence-unit name="SALES_APP2"&gt;
   &lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;
   &lt;jta-data-source&gt;java:/SALES_APPDatasource3&lt;/jta-data-source&gt;
   &lt;properties&gt;
     &lt;property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/&gt;
     &lt;property name="hibernate.hbm2ddl.auto" value="update"/&gt;
     &lt;property name="hibernate.show_sql" value="true"/&gt;
     &lt;property name="hibernate.format_sql" value="true"/&gt;
     &lt;property name="hibernate.connection.provider_class" value="com.rudi.framework.MyConnectionProvider" /&gt;
     &lt;property name="jboss.entity.manager.factory.jndi.name" value="java:/SALES_APP2EntityManagerFactory"/&gt;
     &lt;property name="mfin.datasource.name" value="dataSourceName2"/&gt;
   &lt;/properties&gt;
 &lt;/persistence-unit&gt;
&lt;/persistence&gt;</pre>
<p>Perhatikan line 15 dan 28. Disitu ditentukan bahwa EntityManager yang akan dihasilkan nantinya (melalui EntityManagerFactory) akan menggunakan ConnectionProvider buatan sendiri.</p>
<p>Perhatikan juga line 17 dan 30. Anda dapat menentukan property karangan sendiri untuk digunakan oleh ConnectionProvider nantinya.</p>
<p>Di file components.xml, tambahkan satu lagi managed-persistence-context, seperti di bawah ini.</p>
<pre class="xml" name="code">&lt;persistence:managed-persistence-context name="entityManager"
 auto-create="true"
 persistence-unit-jndi-name="java:/SALES_APPEntityManagerFactory"/&gt;

 &lt;persistence:managed-persistence-context name="entityManager2"
 auto-create="true"
 persistence-unit-jndi-name="java:/SALES_APP2EntityManagerFactory"/&gt;</pre>
<p>Selanjutnya, buat implementasi dari ConnectionProvider, seperti contoh berikut:</p>
<pre class="java" name="code">package org.rudi.framework;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.hibernate.HibernateException;
import org.hibernate.connection.ConnectionProvider;
import org.jboss.seam.contexts.Contexts;

public class MyConnectionProvider implements ConnectionProvider {
	private InitialContext ctx;

    private String dataSourceNameDefault = "SALES_APPDatasource2";

    public static final String DS_KEY = "rudi.datasource.name";

    private String dataSourceKey;

    public void configure(Properties props) throws HibernateException
    {
        try
        {
            ctx = new InitialContext(props);
            dataSourceKey = props.getProperty(DS_KEY);

        } catch (NamingException e)
        {
            throw new HibernateException(e.getMessage());
        }
    }

    public Connection getConnection() throws SQLException
    {

        try
        {
            if (Contexts.getSessionContext() != null)
            {
                String dataSourceName = (String)Contexts.getSessionContext().get(dataSourceKey);
                javax.sql.DataSource ds = (javax.sql.DataSource)ctx.lookup("java:/" + dataSourceName);
                System.out.println("&gt;&gt;&gt;returning "+dataSourceName);
                return ds.getConnection();
            }
            else
            {
                javax.sql.DataSource ds = (javax.sql.DataSource)ctx.lookup("java:/" + dataSourceNameDefault);
                System.out.println("&gt;&gt;&gt;returning default: "+dataSourceNameDefault);
                return ds.getConnection();
            }
        } catch (NamingException e)
        {
            throw new SQLException(e.getMessage());
        }

    }

    public void closeConnection(Connection conn) throws SQLException
    {
        if (conn != null)
        {
            conn.close();
        }
    }

    public void close()
    {
    }

    @Override
    public boolean supportsAggressiveRelease()
    {
        return false;
    }

}</pre>
<p>Perhatikan <em>line </em>43-44, disitulah inti dari class tersebut.</p>
<pre>javax.sql.DataSource ds = (javax.sql.DataSource)ctx.lookup("java:/" + dataSourceName);</pre>
<p>Line diatas adalah untuk mendapatkan sebuah <em>DataSource</em> yang di <em>bind</em> dengan alamat JNDI sesuai dengan String variable dataSourceName. Variable dataSourceName sendiri didapatkan dari nilai yang disimpan di session context, dengan line berikut ini.</p>
<pre>String dataSourceName = (String)Contexts.getSessionContext().get(dataSourceKey);</pre>
<p>Di line 28, kita mengakses property <em>custom</em> yang dijelaskan sebelum ini (lihat penjelasan tentang persistence.xml diatas). <em>Value</em> dari <em>property</em> tersebut digunakan di line 43 sebagai key untuk mendapatkan nama <em>dataSource</em> dari session.</p>
<p>Sampai disini, Anda mungkin sudah sangat bosan baca blog ini. Saya sarankan untuk relaks sejenak, nyalakan sebatang rokok atau buka situs <a href="http://tolololpedia.wikia.com/wiki/Halaman_Utama">ini</a>. Jika Anda merasa sudah siap, silakan dilanjutkan lagi.</p>
<p>Kemudian, di komponen yang digunakan untuk otentikasi (default hasil generate dari seam-gen adalah class <em>Authenticator</em>) kita tentukan koneksi database mana yang akan digunakan pada saat seorang user login.</p>
<pre class="java" name="code">package com.rudi.action;

import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.log.Log;
import org.jboss.seam.security.Credentials;
import org.jboss.seam.security.Identity;

import com.rudi.CONSTANT;

@Name("authenticator")
public class Authenticator {
	@Logger
	private Log log;

	@In
	Identity identity;
	@In
	Credentials credentials;

	public boolean authenticate() {
		log.info("authenticating {0}", credentials.getUsername());
		if ("admin".equals(credentials.getUsername())) {
			identity.addRole("admin");
			Contexts.getSessionContext().set(CONSTANT.DS1_KEY, "SALES_APPDatasource");
			Contexts.getSessionContext().set(CONSTANT.DS2_KEY, "SALES_APPDatasource2");
			return true;
		}else if("admin2".equals(credentials.getUsername())) {
			identity.addRole("admin");
			Contexts.getSessionContext().set(CONSTANT.DS1_KEY, "SALES_APPDatasource2");
			Contexts.getSessionContext().set(CONSTANT.DS2_KEY, "SALES_APPDatasource3");
			return true;
		}else if("admin3".equals(credentials.getUsername())) {
			identity.addRole("admin");
			Contexts.getSessionContext().set(CONSTANT.DS1_KEY, "SALES_APPDatasource3");
			Contexts.getSessionContext().set(CONSTANT.DS2_KEY, "SALES_APPDatasource");
			return true;
		}
		return false;
	}
}</pre>
<p>Kelas diatas hanya sebagai contoh. Perhatikan bahwa untuk setiap user (admin, admin2, admin3), kita memasukkan suatu nilai String ke session. Nilai string tersebut adalah alamat JNDI dari dua koneksi database yang diperlukan.</p>
<p>Berikut adalah ilustrasi mengenai <em>code</em> yang diperlukan di prosedur yang akan menggunakan transaksi antar database.</p>
<pre class="java" name="code">@Name("transferAction")
public class TransferAction implements Serializable {
  @In EntityManager entityManager;
  @In EntityManager entityManager2;

  public void transferAntarBank(Long idAkunBank1,Long idAkunBank2, BigDecimal jumlah) {
    Transaction.instance().enlist(entityManager);
    Transaction.instance().enlist(entityManager2);
    Akun akunBank1 = entityManager.find(Akun.class, idAkunBank1);
    Akun akunBank2 = entityManager2.find(Akun.class, idAkunBank2);
    akunBank1.debet(jumlah);
    akunBank2.kredit(jumlah);

    entityManager.flush();
    entityManager2.flush();
  }

}</pre>
<p>Di line 7 dan 8, kita men<em>cantol</em>kan kedua entityManager kepada <em>Transaction</em> yang sedang berjalan saat itu. Jika kita menggunakan <em>managed persistence context</em> (seperti contoh yang saya buat ini), SEAM secara otomatis akan memulai sebuah transaksi di fase JSF <em>apply request</em> dan di<em>commit</em> (atau <em>rollback</em>) setelah <em>invokeAction</em>, dan satu transaksi lagi pada saat <em>render response</em>. Untuk keterangan tentang <em>SEAM managed persistence context</em> lihat <a href="http://docs.jboss.org/seam/2.1.2/reference/en-US/html/persistence.html#persistence.seam-managed-transactions">disini</a>. Untuk keterangan tentang fase-fase request di aplikasi JSF lihat <a href="http://www.ibm.com/developerworks/library/j-jsf2/">disini</a>.<br />
Selanjutnya&#8230; selesai (akhirnya&#8230;!!!). Secara prinsip, itu saja yang perlu diketahui. Selamat mencoba. <img src='http://wizardry.bungrudi.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://wizardry.bungrudi.com/archives/seam-2-1-x-dengan-multi-database/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Mengaktifkan SSL di JBoss 4.2.x</title>
		<link>http://wizardry.bungrudi.com/archives/mengaktifkan-ssl-di-jboss-4-2-x/</link>
		<comments>http://wizardry.bungrudi.com/archives/mengaktifkan-ssl-di-jboss-4-2-x/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 05:42:44 +0000</pubDate>
		<dc:creator>Rudi Adianto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[JBoss AS 4.2.1]]></category>
		<category><![CDATA[SSL]]></category>

		<guid isPermaLink="false">http://wizardry.bungrudi.com/?p=3</guid>
		<description><![CDATA[Hampir semua langkah sudah dituliskan dengan benar disini. Hanya ada beberapa hal yang perlu ditambahkan agar bisa jalan dengan benar di JBoss AS 4.2.x. Selengkapnya adalah sbb. Kita akan menggunakan &#8216;self signed certificate&#8217;, atau bahasa mudahnya &#8216;sertifikat yang diterbitkan sendiri&#8217;. Jadi jalankan perintah berikut ini: keytool -genkey -alias tomcat -keyalg RSA Keytool adalah command line [...]]]></description>
			<content:encoded><![CDATA[<p>Hampir semua langkah sudah dituliskan dengan benar <a href="http://i-proving.ca/space/Technologies/JBoss/Configuring+JBoss+SSL">disini</a>. Hanya ada beberapa hal yang perlu ditambahkan agar bisa jalan dengan benar di JBoss AS 4.2.x. Selengkapnya adalah sbb.</p>
<ol>
<li>Kita akan menggunakan &#8216;self signed certificate&#8217;, atau bahasa mudahnya &#8216;sertifikat yang diterbitkan sendiri&#8217;. Jadi jalankan perintah berikut ini:
<pre>keytool -genkey -alias tomcat -keyalg RSA</pre>
<p>Keytool adalah command line tool yang ada di folder instalasi JDK. Perintah diatas pada dasarnya melakukan 2 hal:</p>
<ul>
<li> membuat &#8216;key&#8217; baru</li>
<li>membuat &#8216;keystore&#8217; baru, untuk menyimpan key yang baru saja dibuat</li>
</ul>
<p>Akan ada beberapa input yang harus diberikan pada keytool, isikan sesuai konteks.</p>
<p><img class="alignnone size-full wp-image-6" title="create_ssl_key_and_keystore" src="http://wizardry.bungrudi.com/wp-content/uploads/2009/08/create_ssl_key_and_keystore.JPG" alt="create_ssl_key_and_keystore" width="829" height="638" /></p>
<p>Akan ada dua permintaan input untuk password. Yang pertama adalah untuk &#8216;key&#8217;, dan yang kedua adalah untuk &#8216;keystore&#8217;.</li>
<li>File &#8216;keystore&#8217; yang telah dibuat akan ditempatkan berada di path C:/Document and Settings/rudi/.keystore. Pindahkan ini ke tempat lain yang path-nya tidak mengandung spasi. Di PC lokal saya memindahkan ke D:/JBoss-4.2.1/server/default/conf/ , dan nama file diubah menjadi &#8216;ess.keystore&#8217;.</li>
<li>Buka file D:/JBoss-4.2.1/server/default/deploy/jboss-web.deployer/server.xml, cari line yang mirip dengan code xml berikut dan gantikan:
<pre>&lt;Connector port="8443" address="${jboss.bind.address}"
 maxThreads="100" strategy="ms" maxHttpHeaderSize="8192"
 emptySessionPath="true"
 scheme="https" secure="true" clientAuth="false"
 keystoreFile="${jboss.server.home.dir}/conf/ess.keystore"
 keystorePass="eazyway" sslProtocol="TLS"  protocol="HTTP/1.1" SSLEnabled="true"/&gt;</pre>
<p>Pastikan bahwa code diatas tidak berada dalam blok html comment (&lt;!&#8211;   &#8211;&gt;).</li>
<li>Nyalakan server. Coba test ke http://localhost:8443/. Jika page default JBoss AS muncul, berarti konfigurasi sudah benar, dan aplikasi yang terinstall bisa diakses melalui SSL.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://wizardry.bungrudi.com/archives/mengaktifkan-ssl-di-jboss-4-2-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

