Tuesday, November 8, 2011

Self InclusiveTemplating in JSF 2.0

Page template is a nice feature in JSF 2.0. Combined with EL 2.2, it is so powerful that you can do self inclusive templating in a production environment. Here is an example:

1) client file - index.xhtml:

    <ui:composition xmlns="http://www.w3.org/1999/xhtml"
         xmlns:ui="http://java.sun.com/jsf/facelets"
         xmlns:f="http://java.sun.com/jsf/core"
         xmlns:h="http://java.sun.com/jsf/html"
        
template="/templates/template.xhtml">

      
<ui:define name="title">Page Title</ui:define> 

       <ui:define name="body">Page Body</ui:define>
   </ui:composition>



Here it is using the template.xhtml as the template, then define 2 elements "title" and "body" to pass to template.xhtml.

2) template file - template.xhtml:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
 

<h:head>
 <title><ui:insert name="title">Title</ui:insert></title>
 <ui:include src="/templates/header.xhtml"/> 

</h:head>
 

<h:body>
  <div id="col2" class="clearfix">

   <div id="col2a">
    <ui:insert name="body">Body</ui:insert>
    <ui:include src="/templates/footer.xhtml"/>
   </div>
 
   <div id="col2b">
    <div id="nav-container">
     <ul id="nav-main">
       <ui:include src="/templates/submenu.xhtml">
        <ui:param name="submenu" value="#{sessionSupport.menuService.getSubMenu(currentSectionUrl)}" />
        <ui:param name="level" value="1" />
      </ui:include>
     </ul>
    </div>
   </div>

  </div>
</h:body>
 

</html>


The two "ui:insert" are the place-holders for page title and body, which are provided from the client file (index.xhtml); "ui:include" pieces are convenient to include a few html snippets to make the code clean and neat. Among them submenu.xhtml is the most interesting one.


3) self inclusive snippet file - submenu.xhml:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:c="http://java.sun.com/jsp/jstl/core">
 

<c:set var="url" value="#{sessionSupport.breadCrumbs[level+1].url}"/>
<c:set var="requestURI" value="#{sessionSupport.requestURI}" />

<c:forEach items="#{submenu}" var="menuItem" varStatus="status">

<c:choose>
<c:when test="#{sessionSupport.menuService.isSelf(menuItem, requestURI)}">
 <li class="active"><a href="#{menuItem.url}">#{menuItem.name}</a>
   <ul>
    <ui:include src="/templates/submenu.xhtml">
    <ui:param name="submenu" value="#{sessionSupport.getSubMenu(
url
)}"/>
    <ui:param name="level" value="#{level+1}" />
    </ui:include>
   </ul>
  </li>
</c:when>
<c:otherwise>
  <li><a href="#{menuItem.url}">#{menuItem.name}</a></li>
</c:otherwise>
</c:choose>
</c:forEach>


</ui:composition>



The code loops through the menu items at the current level and then calls itself, passing the sub-menu of the next level as a parameter, and then goes on and on, until it walks through the whole tree structure.

Setting up JSF 2.0 and EL 2.2 on Glassfish v2

I am migrating our JSF 1.1 application to JSF 2. Since we are still running Glassfish 2.1.1, I can't use the latest version of JSF (2.1.3), which targets Servlet 3.0 containers like Glassfish v3. So I settled with JSF 2.0. One of the nice features of JSF 2.0 is the build-in page templating support, which is a big help to clean up those messy jsp files.

While setting up the templates, I found that we need to pass parameters to methods in the jsf/xhtml file. But this is NOT supported by default in Glassfish 2.1.1. Comes EL 2.2 for the rescue.

It is kind of easy to set up JSF 2.0 and EL 2.2 on Glassfish v2:

1) Add el-impl-2.2.jar in your project pom.xml (assuming you use maven), which will install two jar files (el-impl-2.2.jar and el-api-2.2.jar) in your WEB-INF/lib after build:

    <dependency>
      <groupId>org.glassfish.web</groupId>
      <artifactId>el-impl</artifactId>
      <version>2.2</version>
    </dependency>

2) Copy el-impl-2.2.jar and el-api-2.2.jar to %Glassfish_Home%/lib/

3) Download jsf 2.0 from http://javaserverfaces.java.net/, then copy jsf-impl.jar and jsf-api.jar to %Glassfish_Home%/lib/

4) Add "classpath prefix" in glassfish domain configuration file domain.xml (or you can use the Admin console: Application Server -> JVM Settings -> Path Settings -> Classpath Prefix):

<java-config classpath-prefix="${com.sun.aas.installRoot}/lib/jsf-api.jar${path.separator}${com.sun.aas.installRoot}/lib/el-api-2.2.jar"
...


You are all set to roll!