Spring Profile Dan Auto Reconfiguration Dari Cloud Foundry


Saya mengalami sebuah dilema karena fitur auto reconfiguration Cloud Foundry tidak bekerja di aplikasi Spring saya.  Pada saat saya men-deploy aplikasi ke server Cloud Foundry, harusnya nilai seperti username, password, dan nama database pada bean data source akan secara otomatis berubah sesuai dengan yang ada di server Cloud Foundry (yup! saya tidak ingin tahu user atau password di server yang merupakan kombinasi angka & huruf!).  Tapi yang terjadi masalah kesalahan NullPointerException.

Sementara, bila saya mengubah nilai username, password, nama database, dan URL di bean data source agar sesuai dengan yang ada di server Cloud Foundry, maka saya tidak bisa lagi menguji aplikasi di komputer lokal karena database di komputer lokal memiliki nama user, password, nama database, dan URL yang berbeda!!

Okay, pilihan terakhirnya adalah setiap kali saya men-deploy, saya harus mengedit bean data source agar nilainya sesuai dengan database MySQL yang ada di server Cloud Foundry.  Begitu selesai men-deploy, saya harus mengembalikan nilai agar sesuai dengan database MySQL yang ada di komputer lokal!  Wew, ini akan sangat merepotkan, serasa hidup di dunia primitif.  Pada dasarnya, saya adalah seorang yang malas dan ingin cepat, jadi apakah tidak ada pilihan lain yang bisa mempermudah hidup saya?

Berikut ini adalah garis besar file konfigurasi Spring saya:

<beans ...>
  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emf" />
  </bean>

  <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="jpaProperties">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
       <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property packagesToScan="com.snake.aplikasi.domain" />
    <property name="jpaProperties" ref="jpaProperties" />
  </bean>

  <bean id="parentJpaProperties" abstract="true" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
     <property name="properties">
          <!-- 
           ...
           Berisi JPA properties yang berlaku untuk semua jenis deployment.
           ...
          -->
     </property>
  </bean>

  <bean profile="dev,production">
     <!-- Memakai Flyway untuk migrasi perubahan database secara otomatis -->
     <bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate">
         <property name="dataSource" ref="dataSource" />
     </bean>

     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
         <!--
           ...
           Berisi URL, username, dan password untuk database di komputer lokal (development) dan production
           ...
         -->
     </bean>

     <!-- Berisi konfigurasi JPA untuk database di development maupun production -->
     <bean id="jpaProperties" parent="parentJpaProperties" depends-on="flyway">
        <property name="properties">
           <props merge="true">
               <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
           </props>
        </property>
     </bean>
  </bean>

  <bean profile="test">
      <!-- Selama pengujian, tidak memakai database MySQL tetapi memakai database embedded H2 -->
      <jdbc:embedded-database id="dataSource" type="H2" />

      <bean id="jpaProperties" parent="parentJpaProperties">
          <!-- 
             ...
             Berisi konfigurasi JPA khusus untuk database pengujian (database embedded H2)
             ...
           -->    
      </bean>
  </bean>
</beans>

Saya memakai profiles untuk membagi konfigurasi ke dalam 3 profile, yaitu dev, production, dan test.  Khusus untuk bagian database ini, saya menyamakan antara dev dan production (sama-sama memakai database MySQL server!).  Sementara bila JUnit dijalankan untuk pengujian, maka yang aktif adalah profil test sehingga database yang dipakai bukan MySQL melainkan sebuah database embedded H2.

Saya berharap bahwa profil yang aktif pada saat aplikasi telah di-deploy di Cloud Foundry adalah profil production, lalu fitur auto reconfiguration akan secara otomatis akan merubah bean data source saya sesuai dengan user, password dan URL database MySQL di server.   Tapi hal ini tidak terjadi!

Tunggu dulu… Bagaimana saya bisa yakin bahwa profil production akan aktif  di Cloud Foundry nanti?  Atau dengan kata lain, apa profil yang akan aktif bila saya tidak menentukannya?

Setelah melakukan penelusuran dokumentasi Cloud Foundry, akhirnya saya menemukan bahwa profil yang akan aktif secara otomatis pada saat aplikasi di-deploy di Cloud Foundry adalah profil cloud.   Pantas saja!  Sekarang, saya menambahkan pilihan profil baru seperti berikut ini:

<beans profile="dev,production,cloud">
   ...
</beans>

Tapi ini belum menyelesaikan masalah.  Kesalahan tetap muncul!

Akhirnya setelah melakukan penelusuran lebih lanjut, saya menemukan bahwa masalahnya terletak di hierarki bean jpaProperties dan bean parentJpaProperties yang saya pisah (dimana parentJpaProperties berlaku untuk semua profil).  Sepertinya, fitur auto reconfiguration dari Cloud Foundry tidak dapat membaca hierarki seperti ini dengan baik.

Solusi yang saya tempuh adalah dengan menyatukan kedua bean tersebut, sehingga definisi bean saya akan terlihat seperti:

<beans ...>
  <bean id="transactionManager">
    <property name="entityManagerFactory" ref="emf" />
  </bean>

  <bean id="emf" depends-on="jpaProperties">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
       <bean />
    </property>
    <property packagesToScan="com.snake.aplikasi.domain" />
    <property name="jpaProperties" ref="jpaProperties" />
  </bean>

  <bean profile="dev,production,cloud">
     <!-- Memakai Flyway untuk migrasi perubahan database secara otomatis -->
     <bean id="flyway" init-method="migrate">
         <property name="dataSource" ref="dataSource" />
     </bean>

     <bean id="dataSource">
         <!--
           ...
           Berisi URL, username, dan password untuk database di komputer lokal (development) dan production
           ...
         -->
     </bean>

     <!-- Berisi konfigurasi JPA untuk database di development maupun production -->
     <bean id="jpaProperties" depends-on="flyway">
        <property name="properties">
           <props>
               <!-- Semua prop yang sebelumnya ada di parentJpaProperties diletakkan di sini -->
               <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
           </props>
        </property>
     </bean>
  </bean>

  <bean profile="test">
      <!-- Selama pengujian, tidak memakai database MySQL tetapi memakai database embedded H2 -->
      <jdbc:embedded-database id="dataSource" type="H2" />

      <bean id="jpaProperties">
          <!-- 
             ...
             Berisi konfigurasi JPA khusus untuk database pengujian (database embedded H2),
             termasuk semua prop yang sebelumnya ada di parentJpaProperties.
             ...
           -->    
      </bean>
  </bean>
</beans>

Akhirnya fitur auto-reconfiguration dari Cloud Foundry bisa bekerja seperti seharusnya, dan keinginan saya untuk melakukan deploy ke Cloud Foundry dengan hanya menekan satu tombol di Spring Tool Suite bisa terwujud.

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: