X

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

Guest Author


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 href="//cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/f4a5b21d-66fa-4885-92bf-c4e81c06d916/File/07575ad4168eba5ee04207bd3b0c2af9/totd202_contracts_source.zip">downloaded
here. This will run on GlassFish build 72 + href="https://maven.java.net/content/groups/public/org/glassfish/javax.faces/2.2.0-SNAPSHOT/">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!


Join the discussion

Comments ( 1 )
  • guest Thursday, August 29, 2013

    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.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.