Partial Facelets Adoption

December 11, 2006

So you have committed to JSF, but have already completed a large majority of your project before hearing about Facelets (or perhaps before it was even released). Since Facelets promises to solve the painful mismatch between JSF and JSP, you would like to take advantage of it. "But how?" you ask, because it is certainly not reasonable to think that you are going to rewrite all of your JSP files over night. Thanks to a lesser known option in Facelets, facelets.VIEW_MAPPINGS, it is possible to partially adopt Facelets by migrating only handful of pages at a time. The facelets.VIEW_MAPPING option tells Facelets which page requests the FaceletViewHandler should process. All the non-matching page requests will be passed up the chain to the default JSF view handler (JspViewHandler).

Assuming you have already gone through the required steps to setup Facelets, the only additional step is to define the pages that you would like Facelets to handle. However, before doing this step, it is necessary to revert the configuration of the javax.faces.DEFAULT_SUFFIX option back to its default value (.jsp), rather than the value that the Facelets documentation recommends (.xhtml). Since Facelets will not handle all requests, the default suffix must be appropriate for the default JSF view handler to interpret.

<context-param>
  <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
  <param-value>.jsp</param-value> <!-- .jspx for XML syntax -->
</context-param>

The list of pages that Facelets will handle is configured using the facelets.VIEW_MAPPING option in web.xml. The mappings are specified as a semicolon (;) delimitted list of resources. The resources can either be a file extension (such as *.xhtml) or a resource prefix (followed by an asterisk). The resource prefix style allows for matching either a subset of pages (such as /user/*) or just a single page (such as /login.jsp*). Because of the way that Facelets does prefix matching, it is necessary to include the trailing asterisk, even when matching against a single page.

Let's assume for a moment, that you are creating a new module for managing users. All the pages are placed in the "/user/" folder at the root of the web context. In that folder we may have pages such as "list.jsp", "detail.jsp", "edit.jsp" and so on. To configure Facelets to process only the pages in this folder and the login page (/login.jsp), while allowing the default JSF view handler to deal with any other page in the web application, you will need to add the following context-param definition to your web.xml file:

<context-param>
  <param-name>facelets.VIEW_MAPPINGS</param-name>
  <param-value>/login.jsp*;/user/*</param-value>
</context-param>

This first example assumes that the same file extension is being used for both Facelets views and non-Facelets views. Another way to integrate Facelets is to use a different file extension (such as .xhtml) than what is used by the non-Facelets views. That way, it is easy to distinguish which files are handled by Facelets, and which ones are not. The configuration for that setup is a bit simpler.

<context-param>
  <param-name>facelets.VIEW_MAPPINGS</param-name>
  <param-value>*.xhtml</param-value>
</context-param>

Of course, it is also possible to use a combination of the two approaches. It depends on how you would like to name your pages.

Now you are ready to take the plunge into Facelets without having to burn the midnight oil in order to migrate the entire application at once! And believe me, once you start using Facelets, you will want to thank somebody.

Posted at 01:01 AM in Java | Permalink Icon Permalink | Comment Icon Comments (4)

Facelets Tag Completion in Eclipse

December 09, 2006

For those of you who use the Eclipse Web Tools Project (WTP) to develop JSF applications with Facelets, you are likely familiar with the lack of tag library support when editing Facelets compositions. By default, Facelets expects pages to use the *.xhtml file extension, which is the XML variant of HTML. There are two discernible problems with this configuration. For one, Eclipse does not recognize files of this type as pertaining to JSF. As a result, Eclipse does not offer tag completion or validation for the libraries registered in the XML namespaces. The second issue is that these pages contain more than just XHTML content. While it may be possible to get away with masking the signature of most tags using the "jsfc" attribute, it turns out to be more trouble than it is worth.

The solution that I came up with, and one that Rick Hightower recommends in his latest round of JSF tutorials, is to use the XML variant of JSP in your Facelets pages. Since the tag completion in Eclipse WTP is built to support JSPX, and all that Facelets requires is a valid XML page, it is a match made in heaven!

<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  version="2.0">
  <ui:composition>
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <title>Page Title</title>
      </head>
      <body>
        <h:outputText value="#{backingBean.property}"/>
      </body>
    </html>
  </ui:composition>
</jsp:root>

Facelets is none the wiser that the XML being used is rooted as JSP. The declarations appearing in the XML namespaces now provide Eclipse with what it needs to offer tag library support while dually informing Facelets which components to load. The only requirement is to ensure that the corresponding TLD file for each tag library is located on the classpath. Even though Facelets does not require TLDs, Eclipse needs them to load the tag libraries definitions, as it does not understand the tag configurations used by Facelets.

If you are going to use this trick, be sure to override the default suffix used by Facelets in the web.xml file.

<context-param>
  <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
  <param-value>.jspx</param-value>
</context-param>

UPDATE: In order to get tag completion, you need to include the Facelets TLD in your WEB-INF/tlds folder. The Facelets TLD is not bundled in the Facelets JAR.

Posted at 11:03 PM in Java | Permalink Icon Permalink | Comment Icon Comments (15)