Pages

Monday, June 16, 2008

ADF Faces templating in 10.1.3

Today I attended a presentation of Peter Koletzke at ODTUG, where he explains that jsf templating is possible in jdeveloper 10.1.3, so let's give it a try. Steve Muench wrote a nice article in the oracle magazine over how you can do it in 11G. In 10.1.3 this is called regions and JHeadstart is using this for branding, menu tabs etc. In this blog I will show you the basics how it works. The First step is to know what to template in your application. In my case I want to template the header of the page and the menu buttons. We need to make a new file called region-metadata.xml and put this in the web-inf folder. In this file we create templates entries.

<?xml version="1.0" encoding="windows-1252"?>
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
<component>
<component-type>nl.ordina.jsf.templating.Header</component-type>
<component-class>oracle.adf.view.faces.component.UIXRegion</component-class>
<component-extension>
<region-jsp-ui-def>/regions/header.jspx</region-jsp-ui-def>
</component-extension>
</component>
<component>
<component-type>nl.ordina.jsf.templating.Menu</component-type>
<component-class>oracle.adf.view.faces.component.UIXRegion</component-class>
<attribute>
<attribute-name>name</attribute-name>
<attribute-class>java.lang.String</attribute-class>
<default-value>empty</default-value>
<attribute-extension>
<required>false</required>
</attribute-extension>
</attribute>
<component-extension>
<region-jsp-ui-def>/regions/menu.jspx</region-jsp-ui-def>
</component-extension>
</component>
</faces-config>
The things you should know, give an unique value to the component-type element of the template component.
This is important because your need this value to reference it in the jsf page. What is the path to region jsf page, this is defined in the region-jsp-ui-def and do I need to pass variables from the.Now we can create the menu template jsf page

<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:af="http://xmlns.oracle.com/adf/faces">
<jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
<af:regionDef var="menu">
<af:menuBar>
<af:commandMenuItem text="#{menu.name}" action="start" />
</af:menuBar>
</af:regionDef>
</jsp:root>

In the template page we have to define the regionDef component and by using the attribute var we can reference the template variables defined in the region-metadata.xml. In my case I can use #{menu.name} to get value of the main page.

<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces">
<jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
<jsp:directive.page contentType="text/html;charset=windows-1252"/>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"/>
<title>main</title>
</head>
<body>
<af:messages/>
<h:form>
<af:panelPage title="Mainpage">
<f:facet name="menuGlobal">
<af:region id="menu" regionType="nl.ordina.jsf.templating.Menu">
<af:attribute name="name" value="MainPage"/>
</af:region>
</f:facet>
<f:facet name="branding">
<af:region id="header" regionType="nl.ordina.jsf.templating.Header"/>
</f:facet>
<af:outputText value="bodytext"/>
</af:panelPage>
</h:form>
</body>
</html>
</f:view>
</jsp:root>

In the main page we have to use a region component to reference the template page. The value of the regionType attribute must be the same as the region-metadata.xml. Because this template has also an attribute, we have to define an child element with the name attribute. Make sure if you using a template variable then you need create the region component inside a panel component else the variables are empty. You are now ready to run the main page

16 comments:

  1. Hi Edwin,

    Yes it is possible to do templating using regions in 10.1.3 but as I skimmed through OTN forum I am afraid it will be difficult to migrate such project to 11g.

    Branislav

    ReplyDelete
  2. Hi bjanko,

    Ok first thing it will be a small year for you can use jdeveloper 11g in production. They just bought bea so it can take longer then a year.

    I think it is not so difficult to move your regions to a jsf page template. If you don't use regions now I think you lose more time now and have a lot of frustation then the time you need to convert the region in jdev 11g.

    I hope it helps

    ReplyDelete
  3. Is there a way to use data bindings in the regions within a template. I tried using a data control table within the#
    region and got "Access Denied". A bit of research led me to a solution wherein I need to pass the "#{binding}" as value
    to the region from my parent template.

    However , this approach will lead to having all the bindings which I am going to use in my regions, duplicated
    in my parent template. Definitely sounds like a crude way of doing it.

    Any good suggestions on how to bind data to the components in regions.

    ReplyDelete
  4. Hi Shishir,

    you can do this.

    In the mainpage you have a pagedef with a next button.
    <action id="Next" requiresUpdateModel="true" Action="10" IterBinding="DeptView1Iterator"/>


    here region-metadata.xml where I pass the operationbinding
    <faces-config xmlns="http://java.sun.com/JSF/Configuration">
    <component>
    <component-type>nl.ordina.jsf.templating.Header</component-type>
    <component-class>oracle.adf.view.faces.component.UIXRegion</component-class>
    <attribute>
    <attribute-name>nextBinding</attribute-name>
    <attribute-class>oracle.jbo.uicli.binding.JUCtrlActionBinding</attribute-class>
    </attribute>
    <component-extension>
    <region-jsp-ui-def>/regions/header.jspx</region-jsp-ui-def>
    </component-extension>
    </component>

    Pass the binding to the region in the main page
    <af:region id="header" regionType="nl.ordina.jsf.templating.Header">
    <af:attribute name="nextBinding" value="#{bindings.Next}"/>
    </af:region>

    Now in the header region let's add a button.
    <af:regionDef var="attrs">
    <af:objectImage source="/images/logo_ordina_oranje.gif"/>
    <af:commandLink actionListener="#{attrs.nextBinding.execute}"
    immediate="true" text="Next">
    <af:resetActionListener/>
    </af:commandLink>
    </af:regionDef>

    thanks Edwin

    ReplyDelete
  5. Hi Edwin,

    Thanks for the response. However as I mentioned I don't want to pass the whole bindings from main page to the region, because my regions are full fledged pages with lots of data bindings.

    Besides I have more than one regions on the main page which I am contextually changing based on certain conditions.

    So in the whole, I am not comfortable having everything repeated in my main page for every binding am going to use in my regions.

    I might not have understood your example correctly, so if you don't mind explaining what exactly is happening in it, it would be helpful.

    AFAIK, you are trying to pass an operation binding, whereas am trying to work with data bindings in the region within the main page.

    -Shishir

    ReplyDelete
  6. Hi, Can you post a small example what you like to work.

    You can pass an iterator too.

    Let me know and I will take a look
    thanks Edwin

    ReplyDelete
  7. Well, to say in short, am trying to make full fledged jsf pages within regions. In order to do that I need to have access to data bindings within my regions (something which is available out of the box in normal jspx pages).

    Now the problem I see with regions is that if I use the data control drag and drop feature, I get the "Accesss denied" for those bindings. I figured out that unless I add that binding to my container page(i.e. main page), and pass that binding to my regions, I will not be able to use that binding in that region.

    But, that is what I feel is a very bad approach. Because I will eventually have to drag and drop the data control bindings on my main page, then set it's render property to 'false' (since I don't want the components on the main page but in the regions instead) and then go ahead and use those bindings inside my regions.

    I am looking for an alternative good way of doing this.

    Hope that makes it more clear.

    Thanks,
    Shishir

    ReplyDelete
  8. Ok, Now I understand your issue.

    probably you already know this that you don't have to drag from the datacontrol to the page. You can open the pagedef and add the value and operation bindings etc.
    In this case you don't have any code in the main page.

    But you may need to have 1 binding active in the main page else the pagedef is not initialized.

    thanks Edwin

    ReplyDelete
  9. Hai Edwin,


    This is exactly what i need now. I'm really confusing about how we can automaticly add company logo as header to every panelpage component.

    But sadly im new to ADF + JSF, so far i read the JSF / ADF ebook but i can't understand your article since ADF doesn't officially support in JDev 10.1.3.3 so rarely ebook cover this region things.

    Can you explain to me more detail and spesific please Edwin.

    Im really appreciate if you would help me.

    PS : Maybe we can talk by mail / yahoo messenger. Just drop me mail to harry.christian@yahoo.com or ym id harry.christian

    ReplyDelete
  10. Hi Harry,

    This is what you should do

    create a logo jsf page with a image component

    <?xml version='1.0' encoding='windows-1252'?>
    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
    xmlns:af="http://xmlns.oracle.com/adf/faces">
    <jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
    doctype-system="http://www.w3.org/TR/html4/loose.dtd"
    doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
    <af:regionDef var="logo">
    <af:image ddffgfgg/>
    </af:regionDef>
    </jsp:root>


    make a reference in the region-metadata.xml

    <?xml version="1.0" encoding="windows-1252"?>
    <faces-config xmlns="http://java.sun.com/JSF/Configuration">
    <component>
    <component-type>nl.ordina.jsf.templating.logo</component-type>
    <component-class>oracle.adf.view.faces.component.UIXRegion</component-class>
    <component-extension>
    <region-jsp-ui-def>/regions/logl.jspx</region-jsp-ui-def>
    </component-extension>
    </component>
    </faces-config>

    and in every page add the region to the panelpage

    <af:panelPage title="Mainpage">
    <f:facet name="branding">
    <af:region id="logo" regionType="nl.ordina.jsf.templating.logo"/>
    </f:facet>
    <af:outputText value="bodytext"/>
    </af:panelPage>

    that's all

    ReplyDelete
  11. Edwin thanks for response. Im now can running simple application with region.

    But i'm now having the same problem with Shishir. I need data control to put inside the region.

    Based on conversation between you and Shishir, im still don't get it.

    ReplyDelete
  12. Hi Harry,

    Can you send me a small testcase and I'll give it a try.

    biemond at gmail dot com

    ReplyDelete
  13. Hi Harry,

    you can not drag in jdev 10.1.3 something from the data control to a region. a region does not have a pagedef. 11g can have its own pagedef .

    So need to pass the operating or valubinding as a parameter to the region.

    ReplyDelete
  14. Hi,

    Because we're using 10.1.3 to develop an ADF Web application and want to have a template to use a centralised definition of things such as copyright information, etc. we've made use of the Region approach documented here and the original author.

    The main problem we're having is as been mentioned already. That is creating datacontrol-bound tables, etc. in the content region of the pages, but getting the Access Denied error.

    I'd like to know more about how to pass the Iterator from the initial page to the region template so that it can then be used by the region "content" page.

    To clarify:
    WK8025 (Initial page) contains a region which references a main template page and passes a contentRegion and attempts to pass the Iterator as an attribute. Is the iterator passed as below:

    #{bindings.LoggedInUserIterator}

    In the region-metadata.xml file there are entries to define the main template page and the content region page that is later injected

    There is an attribute named mainIterator, which uses the class:

    oracle.jbo.RowSetIterator

    Corresponding to this there is a MainTemplate.jspx page and a WK8025R.jspx page.

    MainTemplate.jspx, besides all the desired formatting, contains a region that is populated for the particular page being accessed and uses the following to inject the content region as in the examples:

    #{regionBean.contentRegion}

    In this example, this is WK8025R.jspx, which is the "contents" to display in the Page.

    WK8025R.jspx contains the datacontrol-bound table to display. I've tried the following to access the Iterator being passed, but it still displays Access Denied. I'm trying to reference the Iterator which I believe is passed using:

    #{attrs.mainIterator.

    Where attrs is the regionDef var value.

    Any suggestions on what I'm doing wrong in passing the Iterator? I'm obviously not got this working correctly.

    For the record the Iterator is defined in the WK8025_PageDef.xml file. I'm trying to use the attrs.mainIterator reference to retrieve it, but it seems wrong.

    Gene

    ReplyDelete
  15. Hi,

    you can not use oracle.jbo classes you have to use the JU... classes.

    Ok, here we go.

    first we have the region-metadata.xml

    <faces-config xmlns="http://java.sun.com/JSF/Configuration">
    <component>
    <component-type>nl.ordina.jsf.templating.Header</component-type>
    <component-class>oracle.adf.view.faces.component.UIXRegion</component-class>
    <attribute>
    <attribute-name>nextBinding</attribute-name>
    <attribute-class>oracle.jbo.uicli.binding.JUCtrlActionBinding</attribute-class>
    </attribute>
    <attribute>
    <attribute-name>iteratorBinding</attribute-name>
    <attribute-class>oracle.jbo.uicli.binding.JUIteratorBinding</attribute-class>
    </attribute>
    <attribute>
    <attribute-name>attributeBinding</attribute-name>
    <attribute-class>oracle.jbo.uicli.binding.JUCtrlValueBinding</attribute-class>
    </attribute>
    <component-extension>
    <region-jsp-ui-def>/regions/header.jspx</region-jsp-ui-def>
    </component-extension>
    </component>

    then we got the jsf page

    <af:region id="header" regionType="nl.ordina.jsf.templating.Header">
    <af:attribute name="nextBinding" value="#{bindings.Next}"/>
    <af:attribute name="iteratorBinding" value="#{bindings.DeptView1Iterator}"/>
    <af:attribute name="attributeBinding" value="#{bindings.Deptno}"/>
    </af:region>


    and at last the region

    <?xml version='1.0' encoding='windows-1252'?>
    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
    xmlns:af="http://xmlns.oracle.com/adf/faces">
    <jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
    doctype-system="http://www.w3.org/TR/html4/loose.dtd"
    doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
    <af:regionDef var="attrs">
    <af:commandLink actionListener="#{attrs.nextBinding.execute}"
    immediate="true" text="Next">
    <af:resetActionListener/>
    </af:commandLink>
    <af:inputText value="#{attrs.iteratorBinding.currentRowIndexInRange}" label="CurrentRow"/>
    <af:outputText value="#{attrs.attributeBinding}"/>
    </af:regionDef>
    </jsp:root>

    hope this helps.

    thanks Edwin

    ReplyDelete
  16. Thanks very much. Your example on passing the Iterator, Attribute and Action bindings has been very useful, and I've finally got the regions working containing data controls.

    I was having some problems with the "upside down" injection in the original example of templating I saw and tried. But after going back to the drawing board, I didn't need to do that, and the controls work when put inside the regions.

    Gene

    ReplyDelete