Wednesday, July 6, 2016

Customization on Declative component in oracle ADF

Hi All,

Today i will be explaining about how customization work on ADF DC component. This is not a new topic however i will go beyond already present information and i will explain something more and new.It is pretty straight forward and there are a lot of posts and information are present on internet world therefore i am not going to write anything about DC.

The post is basically consist of three main section.The first section is customizing declarative component , the second section is customizing declarative component child element and third section is just a prove that we should always used jspx, jsff  and jsf for Facelets extension file, In 12c we can defined declarative component with xhtml extension {Facelets }.

Section 1-Customization on Declarative component :

i-I have created on declarative component which have only one output text component. Code is below.

<?xml version='1.0' encoding='UTF-8'?>
<af:componentDef xmlns:af="http://xmlns.oracle.com/adf/faces/rich" var="attrs"
                 componentVar="dcComp" definition="private"
                 xmlns:afc="http://xmlns.oracle.com/adf/faces/rich/component">
    <af:xmlContent>
        <afc:component>
            <afc:description/>
            <afc:display-name>JSFDC</afc:display-name>
            <afc:attribute>
                <afc:attribute-name>backGroundColor</afc:attribute-name>
                <afc:attribute-class>java.lang.String</afc:attribute-class>
            </afc:attribute>
            <afc:attribute>
                <afc:attribute-name>visible</afc:attribute-name>
                <afc:attribute-class>java.lang.Boolean</afc:attribute-class>
                <afc:default-value>true</afc:default-value>
            </afc:attribute>
            <afc:component-extension>
                <afc:component-tag-namespace>dc.component</afc:component-tag-namespace>
                <afc:component-taglib-uri>http://adfwithejb.blogspot.com</afc:component-taglib-uri>
            </afc:component-extension>
        </afc:component>
    </af:xmlContent>
    <af:panelGroupLayout id="dc_pgl1" inlineStyle="#{attrs.backGroundColor}"
                         visible="#{attrs.visible}">
        <af:outputText value="I Am inside Declarative component" id="dc_ot1"/>
    </af:panelGroupLayout>
</af:componentDef>

ii-Then, i have used this component inside one page , i have used this component twice on same page and code is below.

<f:view xmlns:af="http://xmlns.oracle.com/adf/faces/rich" xmlns:dc="http://adfwithejb.blogspot.com" xmlns:f="http://java.sun.com/jsf/core">
    <af:document id="d1" title="Testing.jsf">
        <af:form id="f1">
            <af:panelstretchlayout id="psl1">
                <f:facet name="start">
                <f:facet name="end">
                <f:facet name="top">
                    <af:toolbar id="t1">
                        <af:button actionlistener="#{backingBeanScope.SampleBackingBean.onClickMDS}" id="b1" text="Save">
                    </af:button></af:toolbar>
                </f:facet>
                <f:facet name="bottom">
                <f:facet name="center">
                    <af:panelsplitter binding="#{backingBeanScope.SampleBackingBean.panelSplitterBinding}" id="ps1">
                        <f:facet name="first">
                            <dc:jsfdc binding="#{backingBeanScope.SampleBackingBean.dcSampleBinding}" id="dcs1">
                        </dc:jsfdc></f:facet>
                        <f:facet name="second">
                            <dc:jsfdc id="dcs2">
                        </dc:jsfdc></f:facet>
                    </af:panelsplitter>
                </f:facet>
            </f:facet></f:facet></f:facet></af:panelstretchlayout>
        </af:form>
    </af:document>
</f:view>

iii- On the same page there is one command button which save visible property into MDS repository programmatically.

    public void onClickMDS( ActionEvent actionEvent )
    {
        MDSUtils.persistComponentAttribute( dcSampleBinding , "visible", false );
        AdfFacesContext.getCurrentInstance().addPartialTarget( panelSplitterBinding );
    }

The above code are pretty straight forward. Below is the generated XML document.
<?xml version = '1.0'?>
<mds:customization version="12.2.1_20151011.0031" xmlns:mds="http://xmlns.oracle.com/mds" motype_local_name="view" motype_nsuri="http://java.sun.com/jsf/core">
   <mds:modify element="dcs1">
      <mds:attribute name="visible" value="false"/>
   </mds:modify>
</mds:customization>

So the conclusion of customization declarative component inside page is same as customization of any adf component.

Section  2: Customizing any Child of declarative component :

This section is little tricky but also straight forward. The main point is that the customization on child component of the declarative component is different than customization on any adf component. Customization on normal component will persist against the same page.I have used the same declarative component and now instead of persisting on declarative component, now i am trying to persist it's first child. Now i want to change background color of the panel group layout. Therefore updating inlineStyle property.

        public void onClickMDS(ActionEvent actionEvent) {
        List<UIComponent> children = dcSampleBinding.getChildren(); // getting the child list from declarative component binding
        //MDSUtils.persistComponentAttribute( dcSampleBinding , "visible", false );  //This is for declative declarative
        MDSUtils.persistComponentAttribute(children.get(0), "inlineStyle", "background-color:InfoBackground;");  //saving for child component.
        AdfFacesContext.getCurrentInstance().addPartialTarget(panelSplitterBinding);
    }

If you observer above code , now i am persisting customization for child component of declarative component. The location of generated XML file is against the declarative component not the component where we used this.


And generated file location is  system12.2.1.0.42.151011.0031\o.mds.ide.deploy.base\adrs\DCCustomizationSample\AutoGeneratedMar\mds_adrs_writedir\component\mdssys\cust\user\testuser 

Which if you observe,this location it is same where the declarative component is created folder name is component.

Below is XML file code.

<?xml version = '1.0' encoding = 'UTF-8'?>
<mds:customization version="12.2.1_20151011.0031" xmlns:mds="http://xmlns.oracle.com/mds" motype_local_name="componentDef" motype_nsuri="http://xmlns.oracle.com/adf/faces/rich">
   <mds:modify element="dc_pgl1">
      <mds:attribute name="inlineStyle" value="background-color:InfoBackground;"/>
   </mds:modify>
</mds:customization>

If you pay close attention on above code, the customization is save against id dc_pgl1 which is id of panel group layout. But the disadvantage of this is this customization will applicable whole application. Since i have used this component twice on same page we can see this apply on both page.



Perhaps you are thinking this is not right and definitely there is some way to solve this problem. And yes you are right we can solve this issue via creating one new attribute for declarative component and refer this property where we need.

In this case i have created one new attribute called backGroundColor for declarative component and referring this to panel group layout like inlineStyle="#{attrs.backGroundColor}". So when you have this kind of requirement please exposed via declarative component property.

Section 3: In this section , i would like to explain the file extension also used for customization. And below information is mentioned on Oracle site.
https://docs.oracle.com/middleware/1212/adf/ADFFD/customize.htm#ADFFD19642

MDS requires that pages be XML-based to be customized. Therefore, customizations are not allowed on .jsp files; use .jspx files instead.
Additionally, facelets files must have a .jsf extension to be customizable. MDS uses this extension to recognize it as a Facelets file.

I have tried to see how and what error we get if we do not follow above guide like. I have created one declarative component which .xtml extension. and try to persist one property.




And if you are try to save this , you will get below error.

<oracle.adf.view> <MDSDocumentChangeManager> <addDocumentChangeWithOutcome> <Attempt to persist a DocumentChange failed : >
oracle.mds.exception.MDSRuntimeException: MDS-02401: The operation ModifyAttribute on the panelGroupLayout node is not allowed.  
oracle.mds.exception.MDSRuntimeException: MDS-02406: Customization of /component/DCXHTML.xhtml#(xmlns(af=http://xmlns.oracle.com/adf/faces/rich))/af:componentDef/af:panelGroupLayout/@visible is not allowed because it is not explicitly allowed by any type definition nor any extended metadata entry.
    at oracle.mds.core.ChangeHandler.handleChangeEvent(ChangeHandler.java:543)
    at oracle.mds.internal.model.event.ChangeEventDispatcherUtil.dispatchEvent(ChangeEventDispatcherUtil.java:191)
    at oracle.mds.internal.model.event.dom.DOMMutationEventAdapter.handleEvent(DOMMutationEventAdapter.java:507)
    at oracle.xml.parser.v2.XMLNode.dispatchEvent(XMLNode.java:1394)
    at oracle.xml.parser.v2.XMLNode.dispatchEvent(XMLNode.java:1435)
    at oracle.xml.parser.v2.XMLNode.fireDOMMutationEvent(XMLNode.java:3962)
    at oracle.xml.parser.v2.XMLAttr.setNodeValue(XMLAttr.java:668)
    at oracle.xml.parser.v2.XMLElement.xdkAddAttr(XMLElement.java:3483)
    at oracle.xml.parser.v2.XMLElement.setAttribute(XMLElement.java:1143)
    at org.apache.myfaces.trinidad.change.AttributeDocumentChange.changeDocument(AttributeDocumentChange.java:83)
    at oracle.adf.view.rich.change.MDSDocumentChangeManager._applyChanges(MDSDocumentChangeManager.java:307)
    at oracle.adf.view.rich.change.MDSDocumentChangeManager._addDocumentChangeImpl(MDSDocumentChangeManager.java:271)
    at oracle.adf.view.rich.change.MDSDocumentChangeManager.addDocumentChangeWithOutcome(MDSDocumentChangeManager.java:177)
    at dc.view.beans.MDSUtils.persistComponentAttribute(MDSUtils.java:25)
    at dc.view.beans.SampleBackingBean.onClickMDSSecond(SampleBackingBean.java:45)


"is not allowed because it is not explicitly allowed by any type definition nor any extended metadata entry."

Just for your information i have change log to finest for 
MDSDocumentChangeManager class.




Please is code.

https://github.com/prateekazam/DCCustomizationSample