Archive

Archive for the ‘NyanyianKode’ Category

Konfirmasi dialog popup di richfaces

September 9, 2009 urangbiase 3 comments

Kali ini saya mendapat tugas membuat konfirmasi dialog popup, yang menampilkan message tertentu..seperti “Are you sure..?” dilengkapi dengan tombol “Yes” atau “No”. Kebetulan teknologi web komponen yang dipakai kali ini adalah richfaces. Agar reusable, saya buat konfirmasi dialog popup tersebut sebagai komponen. Untuk itu dipakek lah teknologi facelets yang bisa bisa mendefine komponen dengan mudah. Dan kebetulan lagi, richfaces dan facelets tersebut sudah ada dan terkonfigurasi dalam JBoss Seam Framework, framework yang sedang saya gunakan sekarang. Untuk instalasi dan konfigurasi richfaces dan facelets, silahkan merujuk ke situs offi-sial-nya.

Langsung saja ke code nya y, daripada berpanjang lebar g jelas (talk is cheap, show me the code, Linus – 2000).

  • Buat satu page popup dialog konfirmasi. Kita beri nama confirmation.xhtml, kira-kira begini isinya:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    &ltui:component xmlns="http://www.w3.org/1999/xhtml"
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:a4j="http://richfaces.org/a4j"
       xmlns:rich="http://richfaces.org/rich"
       xmlns:f="http://java.sun.com/jsf/core"
       xmlns:ui="http://java.sun.com/jsf/facelets">
    
    <a4j:jsFunction name="#{submitName}" action="#{resolver.resolveMethodExpression(actionBean)}" reRender="#{listName}"/>
    
    <rich:modalPanel id="#{modalPanelId}" width="250" height="150">
       <f:facet name="header">#{messages['common.Confirmation']}</f:facet>
       <h:panelGrid>
          <h:panelGrid columns="2">
             <h:graphicImage value="/img/msginfo.png" />
             <h:outputText value="#{textMessage}" style="FONT-SIZE: large;" />
          </h:panelGrid>
          <h:panelGroup>
             <rich:spacer height="20px" />
    		 <input type="button"
    		 value="OK"
    		 onclick="#{rich:component(modalPanelId)}.hide();#{rich:component('wait')}.show();
                                 #{submitName}();return false;" />
    		 <input type="button" value="Cancel" onclick="#{rich:component(modalPanelId)}.hide();return false" />
          </h:panelGroup>
       </h:panelGrid>
    </rich:modalPanel>
    </ui:component>
                
  • Konfirmasi dialog akan menjalankan action tertentu jika jawaban dari user meng”iya”kan. Nah action tersebut kita jadikan parameter agar konfirmasi dialog yang kita pasang dapat memiliki action yang berbeda satu sama lain. Untuk keperluan ini maka kita buat backing bean Resolver. Resolver ini berfungsi me-resolve ekspresi EL berupa action atau method dari backing bean yang dijadikan parameter. Langkah berikutnya adalah membuat bean resolver tersebut. Berikut kodenya:
    /* Resolver.java */
    import org.jboss.seam.ScopeType;
    import org.jboss.seam.annotations.Name;
    import org.jboss.seam.annotations.Scope;
    import org.jboss.seam.core.Expressions;
    import org.jboss.seam.core.Expressions.MethodExpression;
    
    @Name("resolver")
    @Scope(ScopeType.APPLICATION)
    public class Resolver {
    	public Object resolveMethodExpression(String elStr) {
    		MethodExpression resolvedEl = Expressions.instance().createMethodExpression("#{" + elStr + "}");
    		if (resolvedEl != null) {
    			resolvedEl.invoke();
    		}
    		return resolvedEl;
    	}
    }
           

    Resolver mempunyai scope “application” karena bean ini akan digunakan berulang kali selama konfirmasi popup dialog digunakan. Sebagai catatan, Resolver diatas spesifik ke seam, karena menggunakan method yang dimiliki oleh seam.

  • Berikutnya tinggal membuat file definisi taglib atas komponen konfirmasi popup dialog dan mendefinisikan file taglib tersebut dalam web.xml.
                <!--- confirmation-taglib.xml --->
                <?xml version="1.0"?>
    <!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "facelet-taglib_1_0.dtd">
    <facelet-taglib>
       <namespace>http://urangbiase.wordpress.com/ui</namespace>
    	<tag>
    		<tag-name>confirm</tag-name>
    		<source>confirmation.xhtml</source>
    	</tag>
    </facelet-taglib>
           
                 <!--- web.xml --->
                 <context-param>
                     <param-name>facelets.LIBRARIES</param-name>
                     <param-value>/WEB-INF/confirmation-taglib.xml</param-value>
                 </context-param>
            
  • Selesai sudah komponen konfirmasi popup dialog yang kita buat. Berikutnya adalah implementasi dari komponen yang telah kita buat.

    <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <ui:composition xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:f="http://java.sun.com/jsf/core"
       -------------cutted text-----------8<
        xmlns:urang="http://urangbiase.wordpress.com/ui">
        -------------cutted text-----------8<
        <a4j:form>
    	&lturang:confirm actionBean="transportationList.removeSelected()" modalPanelId="removeSelectedTransportation"
    				   listName="transportationList" textMessage="Are you sure remove selected row?"
    				   submitName="submitRemoveSelectedTransportation"/>
        -------------cutted text-----------8<
        <a4j:commandLink id="comLinkRemoveSelected">
               <h:graphicImage value="/img/trash.gif" />
        </a4j:commandLink>
       <rich:componentControl attachTo="comLinkRemoveSelected"
               for="#{removeSelectedConfirmation}"
               event="onclick"
               operation="show"/>
       <rich:toolTip value="#{messages['common.RemoveSelected']}" for="comLinkRemoveSelected2"/>
       </a4j:form>
    </ui:composition>
    

    Dan inilah hasil tangkapan layar dari konfirmasi dialog popup.

    popupdialog

    Demikianlah, semoga bermanfaat. Kritik, saran dan THR amat dinantikan :) .

    PS: tulisan ini dibuat ketika belum dapat kucuran THR.

    Categories: NyanyianKode, seam

    Klausa equals String

    April 25, 2009 urangbiase Leave a comment

    Untuk membandingkan dua String, biasa nya saya menggunakan cara ini:

        String str = "SangPemimpi";
        if (str.equals("SangPemimpi")) {
            // do something
        }

    Cara itu sudah benar, namun ada best-practicenya:

        if ("SangPemimpi".equals(str)) {
            // do something
        }
    

    Dimana letak perbedaanya? Cara yang pertama sangat riskan, bisa terkena NPE (NullPointerException) jika variabel str bernilai null. Sedangkan cara kedua, meskipun str bernilai null tidak akan terjadi NPE.

    Sekian, semoga bermanfaat

    Categories: NyanyianKode

    Menambahkan service bisnis ADF-BC

    March 16, 2009 urangbiase Leave a comment

    Kawan, beberapa waktu yang lalu, aku mendapat “wejangan” dari seniorku tentang MVC di Oracle Application Development Framework (ADF). Karena aku orangnya perlupa, aku tuliskan di blog ini, syukur2 bisa bermanfaat bagi orang lain;).

    Oracle ADF itu dibagi tiga bagian; ADF Business Component, ADF Binding Container, ADF Faces.

    1. ADF Business Component (ADF-BC), adalah layer model. Layer model berhubungan dengan bisnis; EntityObject (EO) persisten data object dari database (table), ViewObject (VO) representasi dari data akses atau singkat cerita VO ini adalah query. EO dan VO bekerja sama untuk melakukan operasi baca-tulis. Dan yang terakhir adalah ApplicationModule (AM) yang menampung VO, EO. Melalui AM inilah kita dapat mengakses VO, EO ataupun service-service yang berkaitan dengan level bisnis.
    2. ADF Binding Container, bisa dikatakan bekerja di layer controller, menga-abstraksikan layer model yang digunakan. Sehingga controller (backing bean, pageDef) dapat dengan bebas menggunakan layer model tanpa peduli framework model apa yang digunakan.
    3. ADF Faces, berada di layer view. ADF Faces adalah extend/penambahan dari JavaServer Faces.

    Nah sekarang sudah agak keliatan “petanya”, jangan sekali-kali code bisnis ditaruh di controller. Kalau mau menambahkan/menyediakan proses bisnis, taruhlah pada tempatnya, di level model (AM). Sebenarnya AM (dan AMImpl) berisi dengan daftar (getter) service-service dan ViewObject yang dimilikinya, jadi sebaiknya code bisnis dipisah dari AM agar AM tidak kotor (dengan bloat code dari bisnis process).

    Buat satu class yang nantinya class tersebut berisi code bisnis yang akan kita tambahkan (selanjutnya class ini kita sebut service bisnis). Relasi antara class AMImpl dengan class service bisnis adalah “HAS-A”.
    Sebagai contoh, kita memiliki ParameterAMImpl sebagai class AMImpl dan CopyAgreement sebagai class bisnis. Pada class AM (ParameterAMImpl):

    /**
     * ParameterAMImpl.java
     */
    public class ParameterAMImpl extends ApplicationModuleImpl implements ParameterAM {
        private CopyAgreement copyAgreement;
    
        public ParameterAMImpl() {
            copyAgreement = new CopyAgreement(this);
        }
    
        -----cutted-text---8<
        public void copyAgreement(Number sourceAgrId, Number destAgrId,
                                  int type, Long tenantId) {
            copyAgreement.doCopyAgreement(sourceAgrId, destAgrId, type, tenantId);
        }
        -----cutted-text---8<
    }

    Pada class bisnis (CopyAgreement.java):

    /**
     * CopyAgreement.java
     */
     public class CopyAgreement {
        private ParameterAMImpl parameterAMImpl;
    
        public CopyAgreement(ParameterAMImpl parameterAMImpl) {
            this.parameterAMImpl = parameterAMImpl;
        }
    
        public void doCopyAgreement(Number sourceAgrId, Number destAgrId, int type,
                                  Long tenantId) {
            switch (type) {
            case GlobalConstants.COPY_AGREEMENT.DEALER_MAP:
                copyDealerMap(sourceAgrId, destAgrId, tenantId);
                break;
            -----cutted-text---8<
            }
        }
    -----cutted-text---8<
    }

    Nah, untuk menggunakan method action bisnis yang sudah didefinisikan di AM tersebut, si-client (controller) tinggal mendapatkan dari pageDefs, tidak lupa parameter-parameternya juga di-set. Sebagai contoh:

        public void returnCopyAgreement(ReturnEvent event) {
            Number sourceAgreementId = (Number)event.getReturnValue();
            if (sourceAgreementId == null)
                return;
    
            Long tmpDestAgrId = Long.parseLong(JSFUtil.getProcessObj("AgreementId").toString());
            Number destAgreementId = new Number(tmpDestAgrId);
    
            OperationBinding opBind = getBindings().getOperationBinding("copyAgreement");
            opBind.getParamsMap().put("sourceAgrId", sourceAgreementId);
            opBind.getParamsMap().put("destAgrId", destAgreementId);
            opBind.getParamsMap().put("type", GlobalConstants.COPY_AGREEMENT.UPLOAD_FILES);
            opBind.getParamsMap().put("tenantId", CommonUtils.getTenantId());
            opBind.execute();
            -----cutted-text---8<
        }

    Sekian kawan, semoga bermanfaat. Kritik dan sarannya amat dinantikan. Merdeka !!!.

    Categories: NyanyianKode

    Popup-dialog ADF

    January 19, 2009 urangbiase 2 comments

    Baru-baru ini saya mendapat tugas membuat popup postalcode, popup tersebut akan digunakan oleh page lain. Popup tersebut mengembalikan informasi tentang postalcode; kodepos (postalcode), kelurahan (district01), kecamatan (district02), area (district03), kabupaten/kodya (subprovince), provinsi (province) dan negara (country).

    Dengan berbekal guide ADF yang entah kapan tau saya download, saya mulai petualangan ini.

    Berikut ini langkah-langkah yang dilakukan:
    0. Berdoa (mandatory)
    1. Ambil segelas air putih, minum 1/4 nya (optional)
    2. Buat page popup seperti membuat page biasa.
    3. Tambahkan navigasi di faces-config.xml dari page awal ke page popup, diawali dengan <code>dialog:</code>.

    ---------cutted-text---------8<
     <navigation-rule>
        <from-view-id>/pages/mda/insurancecompany/EditInsuranceCompany.jspx</from-view-id>
        <navigation-case>
          <from-outcome>dialog:popupPostalCode</from-outcome>
          <to-view-id>/pages/mda/postalcode/SelectPostalCode.jspx</to-view-id>
        </navigation-case>
    ---------cutted-text---------8<
    

    4. Di commandButton atau commandLink yang memunculkan page popup tersebut, tambahkan action yang menuju ke page popup, dengan beberapa property yang ditambahkan/diset; <code>partialSubmit, useWindow, windowWidth, </code> dan listener (property returnListener) jika ingin meng-handle nilai return dari popup. Selengkapnya:

    <h:outputLabel value="#{bindings.InsCompZip.label}" styleClass="w150"/>
                    <h:panelGrid columns="2">
                        <af:inputText value="#{bindings.InsCompZip.inputValue}" disabled="true"/>
                        <af:commandLink action="dialog:popupPostalCode"
                                partialSubmit="true" useWindow="true" windowWidth="400"
                                returnListener="#{EditInsuranceCompany.returnSelectPostalCode}"
                                id="selectPostalCodeLink" shortDesc="Select Postal Code">
                            <af:objectImage source="/css/images/ico-ddetailupload.gif"/>
                        </af:commandLink>
                    </h:panelGrid>
    

    5. Minum air putih 1/4 gelas (optional)
    6. Langkah berikutnya adalah menyimpan nilai/data yang dihasilkan dari popup. Sebelumnya af:table perlu di-binding ke backing bean, mengapa? agar nantinya kita dapat mengambil row/postalcode mana yang dipilih.

    <!-- SelectPostalCode.jspx -->
    <af:table binding="#{selectPostalCode.table}" ... >
    ---------cutted-text---------8<
    <f:facet name="selection">
                  <af:tableSelectOne text="Select"/>
                </f:facet>
    </af:table>
    

    dan di backing bean:

        private CoreTable table;
        public void setTable(CoreTable table) {
            this.table = table;
        }
    
        public CoreTable getTable() {
            return table;
        }
    

    Saat apakah nilai return popup tersebut di-set? tentunya ketika user sudah memutuskan row/postalcode mana yang dipilihnya, dengan memilih salah satu row pada table dan mengklik tombol submit.

             <h:panelGrid columns="1" styleClass="divbutton">
                    <h:panelGrid columns="2">
                        <af:commandButton text="Submit" action="#{selectPostalCode.doSubmit}"/>
                        <af:commandButton text="#{res['form.cancelBtn']}">
                            <af:returnActionListener/>
                        </af:commandButton>
                    </h:panelGrid>
              </h:panelGrid>
    

    Di backing-bean pada method doSubmit():

        public String doSubmit() {
            Set<Key> keys = table.getSelectionState().getKeySet();
            if (keys == null)
                return null;
    
            Iterator itr = keys.iterator();
    
            PostalCodeLOVRowImpl vr = (PostalCodeLOVRowImpl)vo.getRow(selectedKey);
    
            String postalCode = (String)vr.getAttribute(PostalCodeLOVRowImpl.POSTALCODE);
            String district01 = (String)vr.getAttribute(PostalCodeLOVRowImpl.DISTRICT01);
            String district02 = (String)vr.getAttribute(PostalCodeLOVRowImpl.DISTRICT02);
            ---------cutted-text---------8<
            Map map = new HashMap();
            map.put("postalCode", postalCode);
            map.put("district01", district01);
            map.put("district02", district02);
            ---------cutted-text---------8<
            AdfFacesContext.getCurrentInstance().returnFromDialog(map, null);
            return null;
       }
    

    7. Langkah berikutnya, adalah mengambil nilai return dari popup tersebut. Hal ini dilakukan di <code>returnListener</code> yang telah didefinisikan pada point 4.

        public void returnSelectPostalCode(ReturnEvent event) {
            Map map = (Map)event.getReturnValue();
    
            if (map != null) {
                String postalCode = (String)map.get("postalCode");
                String district01 = (String)map.get("district01");
                String district02 = (String)map.get("district02");
                String district03 = (String)map.get("district03");
    
                ADFUtil.findAttributeBinding(getBindings(), "InsCompZip").setInputValue(postalCode);
                ADFUtil.findAttributeBinding(getBindings(), "InsCompArea").setInputValue(district03);
                ---------cutted-text---------8<
               AdfFacesContext.getCurrentInstance().addPartialTarget(panelPage1);
            }
        }
    

    Dalam kasus popup postalcode ini, setelah memilih postalcode, UserInterface komponen yang berisi postalcode dan data-data terkait butuh diupdate sesuai dengan postalcode yang dipilih. UI-UI tersebut di-binding satu-persatu dan di-set sebagai partialTarget, terasa merepotkan memang. Ada cara yang lebih singkat, yakni cukup mem-binding komponen UI grouping (semisal panelGroup, panelPage) dan UI-UI komponen yang berpengaruh terhadap hasil dari popup tersebut diletakkan kedalam UI grouping yang digunakan.

    <af:panelPage binding="#{EditInsuranceCompany.panelPage1}"
                            id="panelPage1" partialTriggers="selectPostalCodeLink">
    ---------cutted-text---------8<
    <h:outputLabel value="#{bindings.InsCompZip.label}" styleClass="w150"/>
    <h:outputLabel value="#{bindings.InsCompArea.label}"
                                   id="outputLabel12" styleClass="w150"/>
    ---------cutted-text---------8<
    </af:panelPage>
    

    8. Duduk dengan tenang, minum air putih 1/4 gelas lalu ambil rokok sebatang, rokok boleh milik sendiri atau minta kepada teman, tp janganlah mencuri. Dapat rokoknya, lalu nyalakan. Selesai rokok-an, teguk air yang tersisa hingga habis (optional).

    9. Ucaplah syukur (mandatory).

    Semoga bermanfaat ^^.

    Categories: NyanyianKode Tags: ,

    Rollback pada ViewObject

    January 13, 2009 urangbiase 2 comments

    Biasanya ketika melakukan proses “cancel” atau batal, saya memanggil action “Rollback”. Untuk page yang cuma terdiri dari satu level master-detail, si-”Rollback” ini cukup menyelesaikan masalah, dia akan me-”Rollback” semua aksi yang tidak jadi kita lakukan, ex: setCurrentRowWithKey, Create.

    Nah, lalu bagaimana untuk page master-detail yang terdiri dari lebih dari satu level misalkan A->B->C->D?. Misalkan di page C atau D kita membatalkan aksi atau proses yang akan dilakukan, dalam kasus ini kita tidak bisa menggunakan “Rollback”. Jika kita masih tetap menggunakan “Rollback”, rowKeyStr yang sudah di-set pada page sebelumnya akan kembali ke row pertama. Hal ini wajar, karena “Rollback” adalah action dari ApplicationModule, dan ketika itu dipanggil maka semua perubahan yang belum di-”Commit” akan dibatalkan.

    Solusinya adalah mengabaikan perubahan hanya pada ViewObject dari page tersebut.

        public String doCancel() {
            DCIteratorBinding itBd =
            ADFUtil.findIterator(getBindings(),"SubProvinceView1Iterator");
            ViewObjectImpl vo = (ViewObjectImpl) itBd.getViewObject();
            ViewRowImpl row = (ViewRowImpl)vo.getCurrentRow();
    
            if((row != null) && (row.getEntity(0).getEntityState()==EntityImpl.STATUS_NEW)) {
                // new operation
                row.refresh( Row.REFRESH_UNDO_CHANGES | Row.REFRESH_FORGET_NEW_ROWS);
            }
            else {
                // edit operation
                row.refresh(Row.REFRESH_WITH_DB_FORGET_CHANGES);
            }
    
            return null;
        }
    

    Semoga bermanfaat ^^.

    Sumber: http://abakalidis.blogspot.com/2008/05/oracle-adf-view-object-with.html

    Categories: NyanyianKode Tags: ,