Resource Library Contracts in JSF2.2 (TOTD #202)


JavaServer Faces 2 introduced Facelets as the default View Declaration Language. Facelets allows to create templates using XHTML and CSS that can be then used to provide a consistent look-and-feel across different pages of an application. JSF 2.2 defines Resource Library Contracts that allow facelet templates to be applied to an entire application in a reusable and interchangeable manner.

This Tip Of The Day (TOTD) will explain how you can leverage them in your web application.

The complete source code for this sample can be downloaded here. This will run on GlassFish build 72 + latest JSF 2.2.0 SNAPSHOT copied over "glassfish3/glassfish/modules/javax.faces.jar" file.

Consider the following WAR file:
index.xhtml
user/index.xhtml
contracts/blue/layout.css
contracts/blue/template.xhtml
contracts/red
contracts/red/layout.css
contracts/red/template.xhtml
WEB-INF/faces-config.xml

The application also has two pages - "index.xhtml" and "user/index.xhtml". All contracts reside in the "contracts" directory of the WAR. All templates and resources for a contract are in their own directory. For example, the structure above has two defined contracts "blue" and "red". Each contract has a "template.xhtml" and a CSS. Each template is called as "declared template". The "template.xhtml" has <ui:insert> tags called as "declared insertion points". CSS and other resources bundled in the directory are "declared resources". The "declared template", "declared insertion points", and "declared resources" together make the definition of the resource library contract. A template client needs to know the value of all three in order to use the contract.

In our case, templates have similar "ui:insert" sections and template clients will accordingly have "ui:define" sections. The difference will primarily be in the CSS. "index.xhtml" will refer to the template as:

<ui:composition template="/template.xhtml">
<ui:define name="content">
. . .
</ui:define>
</ui:composition>

The usage of the contracts is defined in "faces-config.xml" as:

<application>
<resource-library-contracts>
<contract-mapping>
<url-pattern>/user/*</url-pattern>
<contracts>blue</contracts>
</contract-mapping>
<contract-mapping>
<url-pattern>*</url-pattern>
<contracts>red</contracts>
</contract-mapping>
</resource-library-contracts>
</application>
A contract is applied based upon the URL pattern invoked. Based upon the configuration specified here, "red" contract will be applied to "faces/index.xhtml" and "red" contract will be applied to "faces/user/index.xhtml".

The template of the page can be changed dynamically as well. For example consider "index.xhtml" is updated as:

<f:view contracts="#{contractsBean.contract}">
<ui:composition template="/template.xhtml">

<ui:define name="content">
<a href="#{facesContext.externalContext.requestContextPath}/faces/user/index.xhtml">Go to</a> other contract
<p/>
Look at WEB-INF/faces-config.xml for contract configuration.
<p/><p/>
Choose a template:<br/>
<h:form>
<h:selectOneRadio value="#{contractsBean.contract}" layout="pageDirection" required="true">
<f:selectItem itemValue="red" itemLabel="red"/>
<f:selectItem itemValue="blue" itemLabel="blue"/>
</h:selectOneRadio>
<h:commandButton value="Apply" action="index" />
</h:form>
</ui:define>

</ui:composition>
</f:view>
The "ui:composition" is included in "f:view". An additional "contracts" attribute can bind to an EL. The value of this EL is populated from the radio button in the newly added form. Now you can choose a radio button, click on the "Apply" button and the new template will be applied to the page. The bean is very trivial:

@Named
@SessionScoped
public class ContractsBean implements Serializable {

String contract = "red";

public String getContract() {
return contract;
}

public void setContract(String contract) {
this.contract = contract;
}
}

This is a very powerful feature. Imagine providing different look-and-feel for your website and letting the user choose them, fun eh ?

Contracts may be packaged as a JAR file. Such a JAR file maybe bundled in "WEB-INF/lib" directory. Read section 2.7 for more details about the packaging requirement and a marker file that identifies the JAR to contain a contract.

In the specification ...
  • Section 10.1.3 provide background on the feature.
  • Section 2.7 provide formal definition of the feature.
  • Section 11.4.2.1 defines how the contracts are identified during application startup.
Create templates as JAR files and reuse them across different applications, enjoy!

Comments:

I'm investigating use of this feature in a new application. The challenge is that the templates are built into the .WAR file (either directly or as .jar files). We need to be able to release a single .war for all customers that does not contain the templates of other customers. The customer provides their various themes/contracts on the filesystem to make our application look & feel like it is part of their corporate website. I'm going to investigate creating a custom resource resolver that can integrate with the new contracts functionality so I can just redirect /contracts to a directory on the filesystem.

Does the JSF expert group think that building a custom .war file for each and every customer is desirable or acceptable? I do not.

Posted by guest on August 29, 2013 at 01:17 PM PDT #

Post a Comment:
Comments are closed for this entry.
About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today