Saturday, December 20, 2014

Quartz Scheduler secara Programatic

Apa itu Quartz Scheduler ? Secara singkat merupakan librari Java yang open source untuk job scheduling yang dapat di-integrasi-kan mulai dari aplikasi Java stand-alone sederhana sampai sistem e-commerce yang besar.

Umumnya aplikasi Java menggunakan Quartz untuk mengatasi penjadwalan tugas pada aplikasi, seperti :
  • Tugas yang berjalan setiap 1 jam sekali
  • Tugas yang berjalan setiap pukul 07.00 setiap hari
  • Tugas yang berjalan setiap pukul 22.00 pada akhir bulan
Penjadwalan tersebut dilakukan menggunakan format seperti Cron Expression pada UNIX, lebih lengkap ada di-sini.

Adapun umumnya aplikasi Java akan membaca Cron Expression tersebut hanya pada saat pertama kali dijalankan.

Lalu bagaimana bila ingin melakukan penjadwalan proses yang bergantung kepada proses sebelumnya ? Misal proses B dijalankan 5 menit setelah proses A selesai.

Source Code

Untuk masalah tersebut dapat dipecahkan dengan melakukan penjadwalan menggunakan Quartz, berikut potongan kodenya.


//--------POTONGAN KODE-----------

Long startTime = currentTime + (5 * 60); //5 menit

String triggerKeyName = "TaskTriggerKey";
Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity(TriggerKey.triggerKey(triggerKeyName, "TaskTriggerGroup"))
 .withSchedule(SimpleScheduleBuilder
 .simpleSchedule()).startAt(new Date(startTime))
 .build();

JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("DATA_A", "ABCDEFG");
jobDataMap.put("TRIGGER_KEY", trigger.getKey().getName());

JobDetail job = JobBuilder.newJob(NextExecutedJob.class)
 .withIdentity("nextExecutedJob", "TaskTriggerGroup")
 .setJobData(jobDataMap)
 .build();

try {
 Date date = scheduler.scheduleJob(job, trigger);
 LOGGER.info("Will executed at " + date);
} catch (SchedulerException e) {
 e.printStackTrace();
}

//--------POTONGAN KODE-----------

Untuk dapat menjadwalkan secara dinamis, diperlukan obyek Trigger yang berguna untuk menentukan kapan tugas tersebut akan dijalankan.

Obyek jobDataMap berguna untuk menyimpan data-data supaya dapat dibaca pada class NextExecutedJob yang akan dijalankan nanti.

Obyek jobDetail merupakan representasi dari tugas yang akan dijalankan nanti, dan didaftarkan kepada obyek scheduler. 


//--------POTONGAN KODE-----------

public class NextExecutedJob extends QuartzJobBean {

    public NextExecutedJob() {}

    @Override
 protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

  String triggerKeyName = null;
  JobDataMap jobDataMap = context.getMergedJobDataMap();

  String dataA = (String) jobDataMap.get("DATA_A");
  triggerKeyName = (String) jobDataMap.get("TRIGGER_KEY");

  //do something here

  if(null != triggerKeyName) {
            TriggerKey triggerKey = new TriggerKey(triggerKeyName, "TaskTriggerGroup");
            try {
                scheduler.unscheduleJob(triggerKey);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
 }
     
}

//--------POTONGAN KODE-----------

Sedangkan pada class NextExecutedJob sebaiknya dilakukan penghapusan job yang tadi didaftarkan dari scheduler. Dengan tujuan menjamin bahwa job tersebut tidak dijalankan lagi oleh scheduler.

Ok, sekian tentang penggunaan Quartz Scheduler secara programatic. Semoga membantu. :)

Accessing Alfresco Repository Through Liferay Document Library


Pada kesempatan kali ini saya ingin berbagi langkah-langkah untuk mengintegrasikan Alfresco content management system dengan Liferay portal. Setelah integrasi ini, dokumen yang tersimpan di  Alfresco repository dapat diakses melalui Liferay portal. Pastikan user dari kedua platform ini harus menggunakan username yang sama agar dapat berhasil. Misalnya user yang dimiliki Okky Hendriansyah di Alfresco adalah okky, maka user okky juga harus ada di Liferay. Intragasi ini berhasil saya lakukan pada Alfresco Community Edition v5.0.a dan Liferay Community Edition v6.2.

Berikut adalah langkah-langkah yang perlu dilakukan dari sisi Alfresco:
  1. Startup Alfresco jika belum dilakukan.
  2. Login menjadi admin
  3. Create user baru misalnya okky.
  4.  Logout dan relogin sebagai okky.

Sedangkan dari sisi Liferay, yang perlu dilakukan adalah:
  1. Tambahkan 2 entry properties pada file $LIFERAY_HOME/portal-ext.properties. Buat file tersebut jika memang belum ada.
    # portal-ext.properties
    session.store.password=true
    company.security.auth.type=screenName
  2. Restart Liferay untuk mengaplikasikan perubahan.
  3. Login sebagai admin. Pastikan username dan password administrator yang digunakan untuk Liferay dan Alfresco sama.
  4. Buka Site yang akan diinteragsikan dengan Alfresco, misalnya site Nostratech.
  5. Pilih "Documents and Media".
  6. Tambahkan Repository baru.
  7. Pilih CMIS Repository (AtomPub) sebagai Repository Type dan masukkan AtomPub URL http://$ALFRESCO_HOSTNAME:8080/alfresco/cmisatom. Jangan lupa untuk mengubah $ALFRESCO_HOSTNAME menjadi IP address atau alamat dari Alfresco server.
  8. Jika berhasil akan ada Alfresco (sesuai nama repository) di menu bagian kiri.
  9. Create user yang akan dijadikan contoh, misalnya okky.  
  10. Logout admin dan relogin sebagai okky dan test create dokumen di Liferay.
  11. Konfirmasi bawah dokumen yang di-upload berhasil dari sisi Liferay.
  12. Periksa yang terjadi di Alfresco sebagai okky.
Selamat mencoba!

Friday, December 19, 2014

The Hostname Strategy


Dalam dunia jaringan komputer, setiap komputer yang terhubung dalam sebuah jaringan memiliki sebuah identitas yang unik berupa IP address atau berupa hostname. IP address adalah serangkaian segment angka desimal (atau heksadesimal pada IPv6) yang menunjukkan jaringan mana sebuah komputer terhubung. Contoh dari IP address misalnya 192.168.0.1 di mana 192.168.0 menunjukkan jaringan, dan 1 menunjukkan identitas komputer yang dimaksud. Sedangkan hostname atau machine name merupakan alias dari sebuah mesin komputer. [1]

Fully Qualified Domain Name (FQDN) adalah domain name yang lengkap untuk mereferensi sebuah komputer yang berada di Internet [2]. FQDN membutuhkan naming service seperti DNS untuk me-resolve hostname mapping ke IP address. Contoh dari FQDN misalnya dev.nostratech.com di mana dev merupakan machine name dan nostratech.com merupakan domain name tempat mesin dev tersebut terhubung. [2]

Ketika tahap development, umumnya kita hanya diberikan informasi IP address karena infrastruktur DNS belum/tidak ada pada development environment. Sehingga kita menggunakan IP address tersebut sebagai penanda identitas server address pada konfigurasi aplikasi. Ketika deployment ke production, barulah konfigurasi IP address tersebut diganti menjadi IP address production atau hostname yang sudah ditetapkan. 

Pada dasarnya alur kerja seperti ini tidak akan bermasalah, namun terkadang saya menemui aplikasi seperti Oracle Enterprise Manager 12c yang tidak mau di-install jika menggunakan IP address. Aplikasi tersebut mengharapkan FQDN sebagai server address yang ter-register. Masalah lain juga pernah saya temui ketika perlu membuat development environment yang merupakan clone dari production environment, di mana salah satu SOA composite deployment me-refer ke IP address dari production environment sedangkan development environment berada di beda jaringan dengan production. Bagaimana cara mengatasinya dengan kondisi yang terbatas seperti itu?
Satu hal yang mulai saya biasakan ketika membuat development environment adalah dengan membuat entry hostname di file /etc/hosts server. Jika memang DNS service belum tersedia di environment, saya gunakan hostname untuk server address pada konfigurasi aplikasi dan meng-update file /etc/hosts dengan IP address yang sesuai. Keuntungan dari metode ini adalah jika suatu ketika dari tim jaringan ada perubahan topologi atau mapping IP address, tidak ada perubahan yang harus dilakukan di sisi aplikasi. Satu-satunya perubahan yang perlu dilakukan adalah mapping hostname-IP address pada file /etc/hosts di masing-masing server.

Hostname sendiri bisa dibagi menjadi 2 tipe hostname, yaitu physical hostname dan virtual hostname. Physical hostname adalah hostname yang merupakan mapping dari physical IP address (koneksi kabel fisik) sebuah server, sedangkan virtual hostname adalah hostname yang merupakan mapping dari virtual IP address (software-based IP address) sebuah server. Saya mulai mengetahui adanya kedua tipe ini ketika saya mulai mempelajari dokumentasi Oracle. Pada dokumentasi tersebut nampak ada 4 physical hosts, yaitu SOAHOST1, SOAHOST2, BAMHOST1, dan BAMHOST2. Physical IP address pada dokumentasi adalah IP1, IP2, dan IP3; sementara VIP1, VIP2, VIP3, VIP4, dan VIP5 adalah virtual IP address-nya. Berikut adalah diagram yang saya capture pada dokumentasi Oracle tersebut: [3]
IP dan Virtual IP assignment pada dokumentasi Oracle

Setelah memperhatikan dan mulai mengikuti network plan dari Oracle, saya mulai membiasakan untuk melakukan strategi hostname berikutnya yaitu dengan menggunakan virtual hostname untuk server address yang dipanggil dalam operasi yang sifatnya internal atau transparan dari sisi pengguna. Misalnya, ketika ingin mengacu ke database server address yang memiliki physical hostname db1-dev.nostratech.com, maka gunakan virtual hostname appdb. Keuntungan dari strategi ini adalah konfigurasi yang sama dapat digunakan di environment yang berbeda tanpa harus mengubah hostname pada konfigurasi. Namun ada pengecualian seperti pada kasus Oracle Database RAC di mana harus menggunakan DNS service untuk me-register ke-3 FQDN milik RAC.

Ketika membuat disaster recovery site atau kloning dari production environment, dokumentasi Oracle menyarankan untuk menggunakan alias hostname pada mesin target. Misalnya, di production environment server address untuk database server adalah proddb1.nostratech.com, maka entry /etc/hosts yang diperlukan di production site dan disaster recovery site adalah sebagai berikut: [4]
# Production Site
192.168.1.100    proddb1.nostratech.com proddb1 dbnode1.nostratech.com dbnode1

# Disaster Recovery Site
192.168.100.100  proddb1.nostratech.com proddb1 stbydbnode1.nostratech.com stbydbnode1

# Development Site
192.168.99.100   proddb1.nostratech.com proddb1 devdbnode1.nostratech.com devdbnode1

# Site X Format
# IP_ADDRESS     ALIAS_WITH_DOMAIN ALIAS HOSTNAME_WITH_DOMAIN HOSTNAME

Jadi, kesimpulan dari strategi hostname yang bisa saya usulkan adalah:
  1. Jangan pernah menggunakan IP address dalam melakukan konfigurasi server address, kecuali jika memang aplikasi tersebut hanya dapat menggunakan IP address.
  2. Bedakan antara physical hostname dengan virtual hostname yang akan digunakan oleh aplikasi untuk lebih mendukung portabilitas konfigurasi.
  3. Manfaatkan file /etc/hosts di masing-masing server untuk server address yang sifatnya internal operation yang tidak perlu di-ekspose ke pengguna aplikasi, misalnya database server address, WebLogic virtual hostname, dan server address lainnya yang tidak perlu di-entry di DNS service.
  4. Gunakan DNS service hanya pada server address yang sifatnya harus diakses langsung dari client. Jika DNS service belum tersedia, manfaatkan kembali file /etc/hosts pada client dan server.
  5. Pastikan eksternal server address yang akan menjadi address yang diakses oleh client dalam bentuk FQDN.
  6. Gunakan alias hostname ketika ingin membuat disaster recovery site untuk meminimalkan konfigurasi yang perlu dilakukan pada kedua site (production dan disaster recovery site).
Happy weekend! :)

Daftar Pustaka:
[1] Massachusetts Institute of Technology Knowledge Base
[2] Indiana University Knowledge Base
[3] Oracle Fusion Middleware Enterprise Deployment Guide for Oracle SOA Suite
[4] Oracle Fusion Middleware Disaster Recovery Guide

Make sprite animation move in corona.

Pada postingan ini, saya akan menjelaskan cara membuat sprite animation di corona, dan cara membuat animasi tersebut dapat bergerak sesuai dengan keinginan kita. Sebelumnya akan saya jelaskan apakah Sprite animation itu.
Sprite animation adalah sebuah API dari corona yang membuat gambar kelihatan lebih hidup dengan cara menampilkan beberapa gambar dalam 1 detik, yang kita kenal juga sebagai fps (frame per second).

Pertama kita harus buat file baru, seperti yang sudah saya jelaskan cara membuat project baru pada bagian physics in corona. Saya akan melewatkan bagian ini dan langsung kebagian cara membuat Sprite Animation.

Sediakan gambar sprite animation terlebih dahulu. Jika anda tidak mempunyainya, anda dapat mendownloadnya disini. Saya akan memilih gambar lebah untuk dijadikan Sprite Animationnya. Jangan lupa untuk menyatukan gambar yang telah dibuat, saya menggunakan TexturePacker untuk menyatukan gambar spriteSheetnya.  Disini gambarnya saya simpan bernama gambar.png. Nanti gambar akan terbentuk seperti:


Gambar.lua

Saya memberi nama file tersebut "gambar.lua". Didalam gambar.lua, kita buat object bernama sheetInfo.


Didalam lua, array disebut juga tabel, dimana dapat menyimpan data didalamnya. Didalam sheet lua saya masukkan sheet yang berupa frame. Frame disini dimaksudkan ukuran dari tiap gambar yang akan ditampilkan.


Jika anda memiliki 10 buah gambar, tambahkan lagi gambar sesuai dengan kebutuhan dan jangan lupa ukuran width dan height jangan lebih besar dari sheetContentWidth. Karena sheetContentWeight adalah ukuran gambar yang akan ditampilkan, sedangkan width dan height adalah ukuran gambar sebenarnya. Pada tahap ini kita telah membuat beberapa gambar yang telah di simpan didalam tabel sheetInfo.

Selanjutnya kita beritahukan setiap gambar di tiap gambar yang telah kita buat dengan menggunakan frameIndex.

Saya mempunyai 16 gambar yang akan dimunculkan selama 1 detik. Ingat maksimum dari corona adalah 30 fps. Jika anda memasukkan lebih dari 30 fps, corona tetap menghitung sampai frameIndex ke 30.

Selanjutnya, kita tambahkan method getSheet dan getFrameIndex


Getsheet berfungsi untuk memeberitahukan memberikan aplikasi dari setiap gambar yang telah disatukan, dan getFrameIndex berfungsi untuk mendapatkan frameindex yang akan dimunculkan.

Main.lua

Sekarang saatnya membuat logic di main.lua. Sekarang simpan gambar.lua kedalam object gambar. Buat juga object yang akan menyimpan data gambar.png dan tiap tiap gambar diatur besar tiap gambar yang akan di tampilkan dari sheetInfo.sheet pada gambar.lua.  Pada newImageSheet mengizinkan anda untuk menyimpan banyak gambar hanya dengan sekali panggil newImageSheet.



Sekarang kita telah menyimpan setiap gambar dan disimpan kedalam imageSheet. Selanjutnya kita buat buat tabel bernama sequenceData, yang menyimpan sifat sifat dari tiap spriteSheet yang akan dibuat.


Ingat jangan lupa memberi name di setiap sifat spriteSheet yang akan dibuat jika ingin membuat spriteSheet kita lebih dinamis. Maksud dinamis disini, gambar dapat melakukan hal lain setelah selain terbang, dengan cara menambahkan kurung kurawal, bernama lain, contoh anda tambahkan name = "run" dengan gambar lain.
sheet berisikan gambar gambar yang telah kita simpan di object imageSheet.
Start adalah gambar pertama yang akan kita munculkan.
Count adalah sampai object berapa yang akan di munculkan, disini saya memiliki 16 gambar. Anda dapat melakukannya sesuai dengan kebutuhan anda. Jangan lupa, Corona hanya 30 dan 60 fps.
loopCount adalah berapa kali perulangan gambar yang akan dimunculkan. Agar membuat gambar looping terus menerus, ubah loopCount = 0.



Selanjutnya kita panggil fungsi newSprite, dimana newSprite akan menyatukan gambar dan menampilkan gambar dari kumpulan gambar yang telah dibuat dan tabel gambar yang akan dibuat.

Selanjutnya gunakan setSequence, yang berguna untuk memunculkan gambar yang akan di mulai, jika anda membuat run, anda dapat mengubahnya, otomatis gambar spriteSheetnya juga akan berubah. Sekarang anda sudah dapat menjalankan animasi sebanyak 16 gambar selama 1 detik. Untuk mensetting berapa banyak maksimum fps yang akan di gunakan anda dapat membuka config.lua. Saya memasang maksimum fps yang akan di tampilkan adalah 60 untuk membuat gambar terlihat lebih lembut.



Sekian dari posting blog saya, anda dapat download source code disini. Selamat mencoba.

BPEL Dynamic URL menggunakan Java Embeding

Pada kesempatan ini kita akan mencoba memanggil sebuah service dengan method get dengan URL dynamic yang kita dapat dari requerst pada BPEL dengan bantuan Java Embedding. Pada dasarnya BPEL memiliki componen berupa http binding, tetapi http tujuan harus di deklarasikan dan tidak bisa dinamis. Karena itulah kita menggunakan java embedding untuk memanggil http yang kita dapatkan dari request parameter.

Pertama kita buat new SOA project.

Kemudian kita buat sebuah synchronous BPEL proses.
Setelah membuat BPEL,akan tergenerated sebuah xsd yang berisi request dan response untuk BPEL yang barusan kita buat. Kita beri sedikit perubahan pada nama tag yang digunakan menjadi seperti di bawah ini. 

Kemudian kita tambahkan java embedding kedalam proses BPEL yang ada.





















Code java bisa langsung di tulis di dalam java embedding ataupun di buat sebagai jar dan di import sebagai library. Pada kesempatan kali ini kita akan menulis langsung code yang  akan di jalankan di dalam java embedding.

Call URL from Java Embedding


Note :  untuk mengassign variable dari java embedding kembali ke bpel proses. Variable harus terlebih dahulu di deklarasi sebelum memasuki java embedding, bisa dengan mengassign menggunakan string kosong.

Setelah itu untuk membuat XMLelement yang kita gunakan untuk mendapatkan data dari BPEL ke dalam Java Embedding,kita perlu menambahkan code berikut ke dalam source BPEL.
BPEL 1.1 :

  • <bpelx:exec import="oracle.xml.parser.v2.XMLElement"/?

BPEL 2.0 :
  • <import location="oracle.xml.parser.v2.XMLElement" importType="http://schemas.oracle.com/bpel/extension/java"/>

XML Parser for BPEL 1.0

Deploy BPEL  untuk dicoba, masukkan request URL seperti https://www.google.com

Request
Response

Sekian dan terima kasih.. 

Thursday, December 18, 2014

ADF - Shuttle Component

Pada kesempatan ini, saya akan membahas tentang Shuttle Component. Shuttle Component sendiri merupakan sebuah komponen untuk memilih lebih dari satu buah pilihan. Pada kesempatan ini, saya ingin mempraktekan cara menginsert value dari shuttle component namun value nya di pisahkan dengan tanda ";" . Untuk mendowload project bisa klik disini. Sebelum nya, saya akan menjelaskan sedikit arsitektur project yang akan saya buat. 

Di dalam project ini, saya menggunakan 2 buah table, table pertama menggunakan table department yang bisa di ambil dari database HR serta 1 lagi menggunakan table yang saya buat sendiri untuk menampung hasil insert dari shuttle. Table Department akan digunakan untuk dijadikan sebagain LOV untuk shuttle component, sedangkan table satu nya untuk menampung hasil insert data dan di tampilkan ke dalam table.

  • Berikut tampilan main.jspx yang terdiri dari table yang saya buat dan 1 buah button untuk membuka popup.

Tampilan main.jspx
  • Berikut tampilan popup untuk insert data, yang terdiri dari 1 buah shuttle component, 1 input text dan 1 buah button. Pada screen ini, kita diminta untuk memasukkan nama, serta nama department yang dimana department bisa dipilih lebih dari 1, jika sudah button insert berfungsi untuk memasukkan data ke dalam table yang sudah kita buat di main screen.

Tampilan Insert Data Pada Pop Up
  • Kita masukkan ActionListener pada button yang ada di dalam popup screen. Jika belum pernah membuat method nya bisa di buat.
ActionListener Pada Button Add
  • Untuk memasukkan Shuttle Component, kita bisa mendrag data control yang ingin kita buat shuttle ke dalam jspx, sebagai contoh saya akan membuat shuttle dari DepartmentView1. Kemudian pilih Multiple Selection dan pilih ADF Select Many Shuttle. Jika sudah, kita pilih Base Attribute nya menjadi DepartmentName & DisplayAttribute nya menjadi DepartmentName.
Cara Add Shuttle Component

Pilihan Ketika Add Shuttle Component

  • Berikut Sample Java Code nya.
 package com.demo.blog.bean;  
 import com.demo.blog.model.TableCreationVoImpl;  
 import com.demo.blog.model.TableCreationVoRowImpl;  
 import com.demo.blog.model.common.AppModule;  
 import javax.el.ELContext;  
 import javax.el.ExpressionFactory;  
 import javax.el.ValueExpression;  
 import javax.faces.application.Application;  
 import javax.faces.context.FacesContext;  
 import javax.faces.event.ActionEvent;  
 import oracle.adf.model.BindingContext;  
 import oracle.adf.model.binding.DCBindingContainer;  
 import oracle.adf.model.binding.DCDataControl;  
 import oracle.adf.model.binding.DCIteratorBinding;  
 import oracle.adf.view.rich.component.rich.input.RichInputText;  
 import oracle.binding.BindingContainer;  
 import oracle.jbo.Row;  
 import oracle.jbo.ViewObject;  
 import oracle.jbo.uicli.binding.JUCtrlListBinding;  
 public class Bean {  
   private final String TABLECREATION_ITERATOR = "TableCreationVo1Iterator";  
   private RichInputText nama;  
   public Bean() {  
   }  
   public BindingContainer getBindings() {  
     return oracle.adf.model.BindingContext.getCurrent().getCurrentBindingsEntry();  
   }  
   public void SaveAndClose(ActionEvent actionEvent) {  
     // Add event code here...  
     oracle.binding.BindingContainer bc = this.getBindings();  
     JUCtrlListBinding listBinding =  
       (JUCtrlListBinding)bc.get("DepartmentView1");  
     BindingContext bindingContext = BindingContext.getCurrent();  
     DCDataControl dc =  
       bindingContext.findDataControl("AppModuleDataControl");  
     AppModule appM = (AppModule)dc.getDataProvider();  
     String departmentVar = "";  
     Object[] str = listBinding.getSelectedValues();  
     if (str != null && str.length > 0) {  
       for (int i = 0; i < str.length; i++) {  
         if (i == 0) {  
           departmentVar = str[i].toString();  
         } else {  
           departmentVar = departmentVar + " ; " + str[i];  
         }  
       }  
       listBinding.clearSelectedIndices();  
     }  
     String name = getNama().getValue().toString();  
     AppModule appModule = getAppModuleDataControl();  
     TableCreationVoImpl vo =  
       (TableCreationVoImpl)this.getViewObjectByIterator(TABLECREATION_ITERATOR);  
     Row newRecord = vo.createRow();  
     newRecord.setAttribute(TableCreationVoRowImpl.DEPARTMENT,  
                 departmentVar);  
     newRecord.setAttribute(TableCreationVoRowImpl.NAME, name);  
     vo.insertRow(newRecord);  
   }  
   private ViewObject getViewObjectByIterator(String iteratorName) {  
     DCBindingContainer bindings2 =  
       (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();  
     DCIteratorBinding dcItteratorBindings =  
       bindings2.findIteratorBinding(iteratorName);  
     // Get an object representing the table and what may be selected within it  
     ViewObject vo = dcItteratorBindings.getViewObject();  
     return vo;  
   }  
   public static AppModule getAppModuleDataControl() {  
     FacesContext fc = FacesContext.getCurrentInstance();  
     Application app = fc.getApplication();  
     ExpressionFactory elFactory = app.getExpressionFactory();  
     ELContext elContext = fc.getELContext();  
     ValueExpression valueExp =  
       elFactory.createValueExpression(elContext, "#{data.AppModuleDataControl.dataProvider}",  
                       AppModule.class);  
     return (AppModule)valueExp.getValue(elContext);  
   }  
   public void setNama(RichInputText nama) {  
     this.nama = nama;  
   }  
   public RichInputText getNama() {  
     return nama;  
   }  
 }  
  • Berikut hasil nya jika main.jspx nya di run.
Tampilan Ketika Page Dijalankan Pertama Kali
Tampilan Ketika Button Insert Data Di Klik
Cara Isi Insert Data yang dilanjutkan dengan mengklik Add
Tampilan Table Setelah Data Di Add
Contoh Add data sebanyak yang di pilih
Tampilan Akhir Page
Semoga bermanfaat !
Terima Kasih.



ADF - Dynamic Region

Pada kesempatan ini saya ingin berbagi tentang ADF Dynamic Region. Apa sih Dynamic Region itu? Dynamic Region itu adalah sebuah region yang bisa berubah secara dinamis dari region 1 ke region lain nya berdasarkan kondisi tertentu. Sebagai contoh, saya akan membuat sebuah dynamic region yang terdiri dari 2 buah region yang bisa di switch dari region 1 ke region 2. Oke sekarang kita langsung masuk ke step by step nya.
  • Buat aplikasi ADF, jika sudah memberi nama bisa langsung di klik Finish. Expand folder View Controller, kemudian klik kanan di folder pageflow lalu pilih new. Buat ADF Task Flow, kemudian beri nama TaskFlowSatu. Buat 2 taskFlow lagi dan beri nama TaskFlowDua dan TaskFlowMain. TaskFlowSatu dan TaskFlowDua yang akan digabungkan kedalam TaskFlowMain.

  • Pada masing masing taskFlow buat sebuah View, drag and drop view tersebut ke dalam taskflow yang sudah dibuat, lalu double klik, kemudian beri nama view sesuai taskFlow nya, sebagai contoh saya akan memberi nama ViewTaskFlowSatu, ViewTaskFlowDua, ViewTaskFlowMain.

  • Buka ViewTaskFlowSatu yang tadi sudah kita buat, kemudian design seperti contoh gambar dibawah

  • Buka ViewTaskFlowDua yang tadi sudah kita buat, kemudian design seperti contoh gambar dibawah.

  • Buka ViewTaskFlowMain, kemudian tarik TaskFlowSatu ke dalam ViewTaskFlowMain, lalu akan muncul pilihan akan kita jadikan sebagai region atau dynamic region, pilih Dynamic Region.

  • Jika sebelum nya kita belum membuat managedbean nya, klik tanda tambah, kemudian isi sesuai gambar dibawah.

  • Buka TaskFlowMain, kemudian pilih overview. Klik pada bagian Managed Bean, pada bagian scope, ganti dari backingbean menjadi view.

  • Buka kembali ViewTaskFlowMain, kemudian klik binding pada bagian bawah, lalu edit taskFlow binding yang awalnya mengambil value dari backingBean menjadi viewScope.

  • Jika Sudah, tambahkan 2 buah button di dalam ViewTaskFlowMain. Kemudian cari component SetPropertyListener dan masukkan kedalam masing masing button yang sudah kita buat tadi. Sebelum nya buat String yg diberi nama currentTF pada java class yang sudah kita buat tadi di awal.


  • Pada bagian struktur file, klik region yang sudah kita buat tadi, kemudian buka property lalu pilih partial trigger kemudian edit. Pindahkan 2 button yang sudah kita buat ke kanan kemudian klik ok. 

  • Buat file JSP pada folder View Controller, kemudian drag and drop TaskFlowMain ke dalam file JSPX yang sudah kita buat.

  • Step terakhir, buka java class yang sudah kita buat tadi kemudian kita isi dengan contoh berikut :
 import oracle.adf.controller.TaskFlowId;  
 public class bean {  
   private String taskFlowId = "/WEB-INF/taskFlow1.xml#taskFlow1";  
   private String currentTF = "taskflow1";  
   private String taskFlow2 = "/WEB-INF/taskFlow2.xml#taskFlow2";  
   public bean() {  
   }  
   public TaskFlowId getDynamicTaskFlowId() {  
     if (this.getCurrentTF().equalsIgnoreCase("taskflow1"))  
     return TaskFlowId.parse(taskFlowId);  
     else   
       return TaskFlowId.parse(taskFlow2);  
   }  
   public void setCurrentTF(String currentTF) {  
     this.currentTF = currentTF;  
   }  
   public String getCurrentTF() {  
     return currentTF;  
   }  
 }  

  • Jika sudah run file jspx yang sudah kita buat tadi. Maka akan muncul seperti gambar dibawah, jika kita klik button taskFlowSatu, maka yang akan muncul tampilan dari taskFlowSatu, namun jika kita klik button TaskFlowDua, maka yang akan muncul tampilan dari TaskFlowDua.


Terima Kasih, semoga bermanfaat !
Untuk mendownload project bisa di klik disini