You may not necessarily know me for all the useful things I do. I tend to find nooks an crannies in JDeveloper 11g and ADF 11g that are no real use to people doing a real job. However, today I have got something to share that is actually useful. I know this as I ran into a demand for it at a customer I visited today.
In short, the situation was like this: we are creating a web application that needs to have several appearances – not very much alike. The basic functionality – data entry, data display, navigation options – is by and large the same. However, there are substantial differences in the look of these various appearances. And no – it is not just styling or skinning, though that is certainly part of it. What in one appearance maybe located on the top of the page may go right into the center of the page in another appearance. And what in one incarnation maybe a search area with three items, positioned in a horizontal group, all of them plain inputText items may in another incarnation be implemented with two input elements, one a group of radio buttons and a dropdown, positioned in a vertical layout.
The UI designers I was conferring with were at first not happy, when they inspected the HTML rendered by ADF 11g RichFaces. Far too many tables used to their liking. Using HTML table elements for creating the layout of the page is fairly rigid, somewhat old fashioned approach, they informed me. And I am aware of that fact. They prefer almost unstructured HTML that they can apply their CSS wizardry to. And of course they are quite right. However, JSF (or JSP or .NET libraries) are great for productive, declarative development with intricate dependencies on backend services – and unfortunately the world of Web Applications is not a perfect one.
To my relief – I have had some difficult conversations in the past – these UI designers were quite willing to be pragmatic about it and work with the output they were getting. In fact, they were even prepared to step out of their world of CSS & JavaScript only and come into JDeveloper. To work with the ADF skinning. And to discuss how we could make optimal use of ADF RichFaces to get ourselves the different appearances required in this application. With maximum reuse – it was not our intention to create every page once for every appearance we had to support. The basic set of input elements, data (control) bindings and navigation controls was the same across all appearances.
Dynamic Page Templates
We first turned to page templates, as they are responsible for much of the overall page layout (structure). Typically a template is used to defined a structure that can be applied to a large number of pages in an application. And that can be modified to achieve an application wide change in look & feel. However, we can use page templates for slightly different goal as well. Since the page template reference in a page is dynamic – can be specified using an EL expression – it can be set dynamically, context sensitive when running the application. So if the desired appearance can be read from some context variable, the page can switch to the desired template on the fly.
The requirements for this to make sense are of course that each template used has the same facets defined and uses the same parameters/attributes. Furthermore, if the pageTemplates have their own PageDefinitions, all of the should be refreshed in the executables section of the page definitions for the pages that use the templates.
In this example, I have created to page templates, both with a single facet (facet1). The templates are nothing as wildly spectacular of courseas the ones we create in the project I mentioned above. But they serve to prove the point.
I have created a single JSF page – untitled1.jspx – that has a reference to the template it is based on. Note that the viewId is not a static reference but an EL expression:
<af:pageTemplate id="t1" viewId="#{bean.template1?'/templateDef1.jspx':'/templateDef2.jspx'}">
The bean referred to has three boolean properties, one of which is called template1. When set to true, templateDef1.jspx should be applied to the page and when set to false the other template – templateDef2.jspx – should be invoked to provide the page appearance.
Though I tried I have not been able to have the template change take effect in a PPR request – perhaps that is slightly pushing it. But changing the checkbox bound to the boolean property and submitting the form has the effect of switching the style of appearance:
<af:group> <af:selectBooleanCheckbox id="templateSelector" text="Yes or No?" value="#{bean.template1}" label="Template 1?" autoSubmit="true"/> <af:spacer width="15"/> <af:commandButton text="Confirm Template Choice"/> </af:group>
The next two screenshots show the same page, with two different templates applied. I’ll grant you, they look horrible. All I try to do here is demonstrate how two appearances of the same page can be achieved by dynamically switching the template.
Uncheck the first chedckbox and press the button to get this – same page, different template:
Note: the templates are both defined with two facets into which the pages can ‘plug their content’:
<af:pageTemplateDef var="attrs"> <af:panelHeader text="Template number one" messageType="info" inlineStyle="background-color:Olive;"> <f:facet name="legend"> <af:facetRef facetName="facet2"/> </f:facet> <f:facet name="info"> <af:image shortDesc="AMIS logo" source="http://www.amis.nl/gfx/img_amis_logo.gif"/> </f:facet> <af:spacer height="50"/> <af:panelBox text="Fancy page specific stuff" inlineStyle="background-color:Silver;" background="medium"> <f:facet name="toolbar"/> <af:facetRef facetName="facet1"/> </af:panelBox> </af:panelHeader> <af:xmlContent> <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component"> <display-name>templateDef2</display-name> <facet> <facet-name>facet1</facet-name> </facet> <facet> <facet-name>facet2</facet-name> </facet> </component> </af:xmlContent> </af:pageTemplateDef>
Dynamic Page Fragments
Page Fragments also turn out to be able to play another role that what seems to be their primary purpose. First and foremost, Page Fragments allow us to break large, complex pages into smaller, more manageable (also Subversionable) pieces. A close second benefit of using page fragments is the ability to reuse those fragments in more than one page. Today, with the request for multiple appearances of what basically is the same page, a third role emerged for the page fragment: they provide a means to conditionally – context and appearance sensitively – include pieces of content in a page or not.
Page Fragments are for all intents and purposes normal JSF pages, except for the fact that their file extension is .jsff and their parent elements are not f:view and af:document. A page fragment is included with a jsp:include tag:
<jsp:include page="/untitled1.jsff"/>
However, such an include can easily be wrapped in a container, such as panelGroupLayout, whose render attribute is dynamically set using an EL expression:
<af:panelGroupLayout rendered="#{bean.showF1}"> <jsp:include page="/untitled1.jsff"/> </af:panelGroupLayout>
In this snippet, the live inclusion of fragment /untitled1.jsff depends on the showF1 boolean property on the bean. In the page shown in the screenshot below, the two checkboxes govern the boolean properties showF1 and showF2 that specify whether or not the two fragments are included:
<af:panelGroupLayout id="pgl" partialTriggers="sb1 sb2"> <af:panelGroupLayout rendered="#{bean.showF1}"> <jsp:include flush="true" page="/untitled1.jsff"/> </af:panelGroupLayout> <af:panelGroupLayout rendered="#{bean.showF2}"> <jsp:include flush="true" page="/untitled2.jsff"/> </af:panelGroupLayout> </af:panelGroupLayout>
The checkboxes themselves are bound to the bean properties, fire autoSubmit and are responsed to by the panelGroupLayout that wraps the two page fragment includes:
<af:selectBooleanCheckbox id="sb1" value="#{bean.showF1}" label="Show Fragment 1?" autoSubmit="true"/> <af:selectBooleanCheckbox id="sb2" value="#{bean.showF2}" label="Show Fragment 2?" autoSubmit="true"/>
Whatever is inside the page fragments does not really matter all that much. Note however that the page fragments are included (merged or mashed) into the page and rely on the ADF PageDefinition (binding container) for the page that absorbs them. They can be consumed by many pages.
The two templates and two fragments that can both be included or not lead to eight different appearances – all of the equally ugly. Let’s look at three of them. And remember: you are looking the same page in all three cases. They have two different templates applied and pick one of two fragments:
Resources
Download JDeveloper 11g Application for this article: ADFPageTemplate.zip (18 kb).
Hoi Eric,
Thanks for your reaction. I realize that the number of templates could start to grow dramatically, depending primarily on the number of layout-flavors. It is not something I would recommend lightly. However, the situation discussed is one where preferably the layout is applied from the outside to whatever HTML is rendered by the application. However, the HTML rendered by many JSP/JSF component based Web Apps is fairly horrible when it comes to outside-in application of styling. Since the components render HTML without much or even any mutual understanding, they all render pretty much self contained HTML which basically boils down to a lot of HTML tables being used. So style manipulation from the outside is a tough one.
Skinning will help fiddle with colors, fonts, decoration etc. but most of it is in-situ: it does not really change the position, ordering or structure of the pages. To achieve the latter, more dramatic action is required, of which the template based approach described above is an example. I would still hope that even under the different ‘flavors’ the number of ‘page patterns’ is limited. So each layout flavor comes with just one to five or so page designs/structures for various types of pages (search, results, edit, master-detail,…). So the number of templates should be much smaller than the number of pages since each page falls into one of only a few layout-categories.
Dynamically manipulating the template itself is an interesting option – although that seems to merely relocate the issue: handling multiple variants of a template, only now in run-time code instead of design time templates. I am not sure that makes things easier. It does sound a lot like what Customization should be able to do for us by the way. MDS can hold various editions of any XML file, presumably including templates. So that should be a way to implement the ‘apply appropriate customization at run time’. I have not tried out to manipulate the template itself – it feels more difficult than maintaining several templates manually.
With MDS based customization you by and large create multiple flavors of a single XML file, leaving the application of the appropriate file to the run time MDS framework. You create the various flavors more or less in the same way as you would create the original file. Not sure whether the XSLT based approach would be easier for non-ADF skilled designers. To manipulate the template – either in the visual editor or through XSLT – you still need to understand the basic ADF layout (container) components. You do not manipulate XHTML that is produced by the template but the template – an ADF page – itself.
best regards, Lucas
Lucas, Interesting stuff! However, I think the original purpose of page templates is basically to ensure some (layout) consistancy across pages within an application. So in general you will have just a few templates for your application(s). For example one template per type of screen. I think the way you use the template mechanism for dynamic, runtime manipulation of (individual) pages can be very usefull. But you can end up with a lot of templates. (Even more templates than pages if you want total flexibility in the layout manipulation of each and every individual page.) A request for a new layout variant means building (by a ADF-skilled developer) and deploying a new ADF page template, which might be cumbersome in the end. Did you investigate possibilities to dynamically manipulate the content of a template.jsfx at runtime by applying xslt stylesheet on it, just before the template is applied to the page that is rendered? If that is possible, one template can do the job. With regard to your example, that template should contain just the facets. (As you stated the facets are the same for your template1 and template2). And the components that make tne distinction between template1 and template2 should be added dynamically to the template.jspx by the xslt(s). Such an approach has some similarities with the MDS customization mechanism, I think? And an xslt-based approach may be easier to adopt by non-ADF-skilled designers? Really interested in your thoughts and experiences on this.