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