Facelets fits JSF like a glove

Finally, a view technology made just for JSF!

Trying to combine JSF and JSP is like trying to shoehorn a foot into a glove: it's possible, but it's really just a stopgap measure until something better comes along. In this article, JSF enthusiast Rick Hightower introduces you to what he likes best about Facelets: easy HTML-style templating and reusable composition components.

Share:

Richard Hightower (rhightower@arc-mind.com), Developer, ArcMind Inc.

Rick Hightower serves as chief technology officer for ArcMind Inc, a training company the specializes in JSF, Spring and Hibernate. He is coauthor of the popular book Java Tools for Extreme Programming, about applying extreme programming to J2EE development, and coauthor of Professional Struts.



21 February 2006

Also available in Chinese Japanese

While working on a Java™Server Faces (JSF) project recently, I had the pleasure of using Facelets for the first time. What I most liked about Facelets was that it let me create reusable composition components. Being able to take a page (like a JSP) and turn it into a component has been a real boon to my JSF development ever since. My conclusion? If you're not using Facelets, you're not getting the most you can out of JSF.

The mismatch between JSF and JavaServer Pages technology is a serious problem in JSF development. The issue is how to integrate JSP's dynamic content into JSF's component-based model. JSP is singularly focused on generating dynamic output, whereas JSF requires JSP to coordinate building a component model. The disjunct occurs because that task is beyond the original intention of JSP.

Most JSF developers simply learn to navigate such problems on an ad-hoc basis, but that's kind of like duct-taping a pillow to a hammer so it won't hurt coming down on your head. Facelets is a much more comprehensive solution: a templating language that is geared toward the JSF component model.

Facelets has several compelling features:

  • Templating (like Tiles)
  • Composition components
  • Custom logic tags
  • Expression functions
  • Designer-friendly page development
  • Creating component libraries

These features are far more related -- and integrated -- than you might think. In this article, I discuss the first two: templating and composition components. I use a Web application example based on one I developed for my JSF for nonbelievers series, updating it to use Facelets views rather than Tiles. You should download the example code before reading further. You'll also need to install Facelets if you want to follow along with the discussion.

.

Overview of Facelets

One of the biggest mistakes you can make is to assume that Facelets is merely a replacement for Tiles. Facelets is much more than that: it's a new way of thinking about JSF.

Choose your markup

Although most developers use Facelets with XHTML, the framework is actually markup agnostic: it's compatible with XUL (XULFaces) and Kito Mann has used it to render the RSS feeds for JSF Central.

JSP is a templating language that produces a servlet. The body of the JSP becomes the equivalent of a servlet's doGet() and doPost() methods (that is, it becomes the jspService() method). The JSF custom tags (such as f:view and h:form) are just calls to the JSF components to render themselves in their current state. The life cycle of the JSF component model is independent from the life cycle of the JSP-produced servlet. That independence is where the confusion comes in.

Unlike JSP, Facelets is a templating language built from the ground up with the JSF component life cycle in mind. With Facelets, you produce templates that build a component tree, not a servlet. This allows for greater reuse because you can compose components out of a composition of other components.

Facelets obviates the need to write custom tags to use JSF components. Facelets uses JSF custom components natively. Very little special coding is needed to bridge JSF and Facelets: all you have to do is declare the JSF components in a Facelet tag library file. You can use JSF components directly within the Facelets templating language without any additional development.

The Facelets template framework

Facelets is similar to Tapestry (see Resources) in that it provides a template framework geared toward component construction. For those of us who come from a JSP background, however, Facelets seems a lot friendlier than Tapestry. It lets you work with JSTL-style tags and a JSTL/JSF/JSP-style expression language that you're already familiar with. The greatly reduced learning curve means you can jump into development much more quickly.

Facelets and Tapestry

Facelets is similar enough to Tapestry to draw comparison. In fact, Tapestry was well ahead of its time when it first came out, and Facelets does draw on some of its ideas. But it would be a mistake to simply think of Facelets as a JSF version of Tapestry. The two technologies are different. To learn more about Tapestry, see Brett McLaughlin's two-part series, "In tune with Tapestry."

Facelets allows you to define component assemblies that can be included directly into a page or can easily be added to a Facelet tag library. It's actually amazing how quickly you can define custom tags (composition components and tags similar to JSP custom tags) in Facelets. With these component assemblies, Facelets also allows you to define site templates (and smaller templates). This is very similar to working with Tiles but minus the definition files. You can also use Facelets inside of a custom JSF component because the Facelets API provides an interface that is easy to integrate with.

From Tiles to Facelets

As I mentioned, the example Web application I use here is based on one I created for my JSF for nonbelievers series. It's a create, read, update, and delete (CRUD) listing that manages inventory for an online CD store. It includes a form that lets the users enter a new CD into the system and a list of radio buttons that lets them select a music category. When the user selects a category, you fire off some JavaScript to post the form immediately back to the server. The application also includes a CD listing from which the the user can sort CDs by title or artist. Figure 1 is a UML diagram of the application classes:

Figure 1. Class diagram for the online CD store example
Example application classes

Figure 2 gives you a look at the store's CD listing page:

Figure 2. The online CD store's listing page
CD Listing

Whereas the original application got its view support from Tiles, I'll build this one using Facelets. I'll start by replacing the Tiles support in the example with Facelets, then jump into writing composition components. Before I get into any of that, though, you'll need to have Facelets installed.

Installing Facelets

The steps to install Facelets are easy to follow. Note that I'm assuming you've already downloaded and installed the example application.

  1. Download the Facelets distribution and unzip it.
  2. Copy the jsf-facelets.jar into your WEB-INF/lib directory (when the application is deployed, it must end up in WEB-INF/lib directory).
  3. Add the Facelet init parameter(s) to the web.xml file.
  4. Add the FaceletViewHandler to the faces-config.xml file.

Steps 1 and 2 are basic. I'll cover the other two in detail.

Adding init parameters

This step assumes you already have a working JSF application (such as the online CD store example) installed and you are editing an existing web.xml page by adding the following parameter:

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

This tells JSF to assume a prefix of xhtml, which the Facelet’s renderer can interpret.

Facelets has many parameters, so see Resources for a complete listing. If you're having problems with the example, refer to the DEVELOPMENT init parameter, which is good for debugging. Setting the REFRESH_PERIOD parameter to low is also helpful during development.

Adding the FaceletViewHandler

For Facelets templates to take effect, you need to tell JSF about the Facelets view handler. A JSF ViewHandler is a plug-in that handles the Render Response and Restore View phases of the JSF request-processing life cycle for different response-generation technologies, including Facelets. (Anyone who believes JSF isn't extensible is misinformed!) You plug Facelets into JSF by adding the following view handler to faces-config.xml:

  <application>
    <locale-config>
      <default-locale>en</default-locale>
    </locale-config>
	<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
  </application>

Templating with Facelets

I'll walk you through the Facelets templating framework first, because it's relatively easy to understand. The steps to create and use a Facelets template are as follows:

  1. Create a layout.xhtml page.
  2. Import the use of Facelets by defining the Facelet's namespace.
  3. Use ui:insert tag to define logical areas of the page.
  4. Use plain text and ui:include tags to define reasonable defaults.

I'll walk through these steps one by one, using the online CD store's Listing page as my layout example.

Step 1. Create a layout.xhtml page

The layout.xhtml page is just a normal XHTML text file that uses the following doctype declaration:

<!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">
</html>

No further detail required!

Step 2. Define the Facelets' namespace

To use Facelets tags for templating, you need to import them using the XML namespace as follows:

<!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:ui="http://java.sun.com/jsf/facelets">
...

Notice the definition of the ui namespace.

Step 3. Use ui:insert tag to define logical areas of the page

Next, you define logical areas of your layout like title, header, navigation, content, and more. Here's an example of how you could define a title:

<!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:ui="http://java.sun.com/jsf/facelets">
<head>
  <title><ui:insert name="title">Default title</ui:insert></title>
  <link rel="stylesheet" type="text/css" href="./css/main.css"/>
</head>
...

Notice the use of the ui:insert tag to define the title's logical area. The text "Default title" inside of the ui:insert element defines what the text is if the user of the template does not pass the title. You could also write the above as follows:

<title>#{title}</title>

Step 4. Use plain text and ui:includes to define defaults

You can pass more than plain text as default. For example, study the following code fragment from layout.xhtml:

<div id="header">
    <ui:insert name="header">
    	<ui:include src="header.xhtml"/>
    </ui:insert>
</div>

Here I've used the ui:insert tag to define the logical area and the ui:include tag to insert the default. By default, the page using the layout uses the contents of header.xhtml as the header text, but because the header is a logical area defined by ui:insert, the page using this template can also pass a different header. For an application with a front end (e.g., a catalog with a shopping cart) and backend administration (such as for adding a new product), the backend site could have different links in the header or navigation. The ui:include tag makes it easy to swap out the default header with a new header.

Listing 1 shows the complete code for the example application's Listing page, list.xhtml:

Listing 1. The complete list.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:ui="http://java.sun.com/jsf/facelets">
<head>
  <title><ui:insert name="title">Default title</ui:insert></title>
  <link rel="stylesheet" type="text/css" href="./css/main.css"/>
</head>

<body>

<div id="header">
    <ui:insert name="header">
    	<ui:include src="header.xhtml"/>
    </ui:insert>
</div>


<div id="left">
  <ui:insert name="navigation" >
    <ui:include src="navigation.xhtml"/>
  </ui:insert>
</div>


<div id="center">
  <br />
  <span class="titleText"> <ui:insert name="title" /> </span>
  <hr />
  <ui:insert name="content">
  	<div>
    <ui:include src="content.xhtml"/>  
    </div>
  </ui:insert>
</div>

<div id="right">
  <ui:insert name="news">
    <ui:include src="news.xhtml"/>
  </ui:insert>
</div>

<div id="footer">
  <ui:insert name="footer">
    <ui:include src="footer.xhtml"/>  
  </ui:insert>
</div>

</body>

</html>

Now that you know how to define a layout, I'll show you how to use it!


Using a Facelets template

To invoke a template, you use the ui:composition tag. To pass arguments to the template, you use the ui:define tags, which are subelements of the ui:composition tag. In Listing 2, I've called the layout page for the online CD store example:

Listing 2. Calling the layout page
<!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:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">


<ui:composition template="/WEB-INF/layout/layout.xhtml">
  <ui:define name="title">CD form</ui:define>
  <ui:define name="content">

	<!-- use the form tag to set up this form -->
	<h:form id="cdForm">

		...
		...
...

	</h:form>
  </ui:define>
</ui:composition>
</html>

Notice the inclusion of the following namespaces in the above call:

  • xmlns:h="http://java.sun.com/jsf/html"
  • xmlns:f="http://java.sun.com/jsf/core"

With Facelets, you don't rely on the JSF tag libraries, so to use the core and HTML JSF components, you must import them through the above namespaces.

The use of the html tag might seem odd. After all, the layout page shown in Listing 2 is invoking a template that already has an html tag; so does that mean you'll get two html tags? As it happens, everything that is on the outside of the ui:composition tag is ignored, so all the html tag does is make the HTML fragment viewable by HTML editors. It doesn't impact on run-time behavior.

Location is everything

When the page invokes the layout template, it just needs to specify the location of the template, as shown here:

<ui:composition template="/WEB-INF/layout/layout.xhtml">

This tag invokes the template shown in Listing 1, so all I need to do is pass the parameters to the template. Then, inside the composition flag, I can pass simple text like the title:

  <ui:define name="title">CD form</ui:define>

or an entire component tree:

  <ui:define name="content">

	<!-- use the form tag to setup this form -->
	<h:form id="cdForm">

		...
		...
...

	</h:form>
  </ui:define>

Notice that of the many logical areas I could have defined and passed, the cdForm.xhtml only passes two: content and title.

Tiles versus Facelets

Three examples ship with this article: the first uses Tiles, the second uses Facelets, and the third uses composition components. I've included the Tiles example so that you can compare and contrast different approaches to templating in the two frameworks. Give it a shot and see what you think!

Composition components

If you used Facelets only to define and use templates, you might be a bit disappointed. Although Facelets templating is full-featured and rich, it doesn't have as many features as a framework like Tiles, which is good for defining defaults, hierarchies of related templates, and such.

Templating isn't where Facelets really shines, though: Facelets puts its best foot forward with composition components. (Interestingly, composition components also lend some benefits to Facelets templating; for example, you can leave out f:verbatim tags and miscellaneous h:outputText tags in Facelets because everything is treated as a component in a component tree. More on this later.)

For the remainder of the article, I'll focus on the steps involved in creating and using composition components. Before I do that, though, let's make sure you have a clear picture of what makes these handy little code snips so great.

Breaking the DRY principle

Have you ever written code that looks like the fragment shown in Listing 3?

Listing 3. Life before composition components
<h:dataTable id="items" value="#{CDManagerBean.cds}" var="cd"
	rowClasses="oddRow, evenRow" headerClass="tableHeader">

<!--  Title -->
<h:column>
	<f:facet name="header">
		<h:panelGroup>
			<h:outputText value="Title" />
				
                 <f:verbatim>[</f:verbatim>

			<h:commandLink styleClass="smallLink"
                              action="#{CDManagerBean.sort}">
				<h:outputText id="ascTitle" value="asc" />
				<f:param name="by" value="title"/>
				<f:param name="order" value="asc"/>
			</h:commandLink>

			<h:outputText value="," />
			<!-- Sort descending -->
			<h:commandLink styleClass="smallLink"
                         action="#{CDManagerBean.sort}">
				<h:outputText id="decTitle" value="dec" />
				<f:param name="by" value="title"/>
				<f:param name="order" value="dec"/>
			</h:commandLink>
			     <f:verbatim>]</f:verbatim>
		</h:panelGroup>
	</f:facet>

	<h:outputText value="#{cd.title}" />
</h:column>

<!--  Artist -->
<h:column>
	<f:facet name="header">
		<h:panelGroup>
			<h:outputText value="Artist" />
			   <f:verbatim>[</f:verbatim>

		      <h:commandLink styleClass="smallLink"
                           action="#{CDManagerBean.sort}">
			     <h:outputText id="ascArtist" value="asc" />
				<f:param name="by" value="artist"/>
				<f:param name="order" value="asc"/>
			   </h:commandLink>

			<h:outputText value="," />
					<!-- Sort descending -->
			<h:commandLink styleClass="smallLink"
  				           action="#{CDManagerBean.sort}">
				<h:outputText id="decArtist" value="dec" />
				<f:param name="by" value="artist"/>
				<f:param name="order" value="dec"/>
			</h:commandLink>
			     <f:verbatim>]</f:verbatim>
		</h:panelGroup>
	</f:facet>
	<h:outputText value="#{cd.artist}" />
</h:column>

This code from listing.xhtml generates column headers and sort-ascending and sort-descending links for the example application's Listing page. Notice how I had to duplicate the code in multiple places to output multiple columns. (You'll also note in the above example that I switch between ${..} and #{..}; this might be confusing, but they do the same thing!)

All that repeated code to render the Title and Artist columns breaks the DRY principle -- that is, don't repeat yourself. And what's wrong with that, you say? Well, imagine if you had an average of 5 columns in your listings and 20 different listings in the application. Using the approach in Listing 3, you would have to repeat the same 35 lines of code 100 times for a combined total of 3,500 lines of code! Maintaining all that code would be a pain, but what if you ever decided to change the presentation of the listing or (gasp!) add a generic way to do list filtering? Far, far too much work.

Now compare Listing 3 with this one:

Listing 4. A new way to create fields
<h:dataTable id="items" value="#{CDManagerBean.cds}" var="cd"
		rowClasses="oddRow, evenRow" headerClass="tableHeader">
			
 <a:column entity="${cd}" fieldName="title" backingBean="${CDManagerBean}"/>
 <a:column entity="${cd}" fieldName="artist" backingBean="${CDManagerBean}"/>

Looks like I've replaced 70 or more lines of code with just 4! As you've guessed, the a:column is a composition component. It's easy to define a component like this one in Facelets, as you can see in Listing 5:

Listing 5. column.xhtml renders a column with a sort link
<!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:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:z="http://www.qualcomm.com/jsf/core"
      xmlns:c="http://java.sun.com/jstl/core"
      xmlns:fn="http://java.sun.com/jsp/jstl/functions">

THIS TEXT WILL BE REMOVED
<ui:composition>
	<!--  The label attribute is optional. Generate it if it is missing. -->
	<c:if test="${empty label}">
	    <c:set var="label" value="${fieldName}" />
	</c:if>

	<!--  The sort attribute is optional. Set it to true if it is missing. -->
	<c:if test="${empty sort}">
	    <c:set var="sort" value="${true}" />
	</c:if>

	<h:column>
	  <f:facet name="header">
	    <h:panelGroup>
	      ${label} 
	      <c:if test="${sort}">
	          [
	        <h:commandLink styleClass="smallLink"
	      action="#{backingBean.sort}">
	          <h:outputText value="asc" />
	          <f:param name="by" 
              value="${fieldName}"/>
	          <f:param name="order" value="asc"/>
	        </h:commandLink>
					,
	        <!-- Sort descending -->
	        <h:commandLink styleClass="smallLink"
              action="#{backingBean.sort}">	
	          <h:outputText value="asc" />
	          <f:param name="by"                
              value="${fieldName}"/>
	          <f:param name="order" value="dec"/>
	        </h:commandLink>
					]
	      </c:if>			
	    </h:panelGroup>
	  </f:facet>
	  <!--  Display the field name -->
	  <h:outputText value="${entity[fieldName]}"/>
        </h:column>
</ui:composition>
THIS TEXT WILL BE REMOVED AS WELL
</html>

The fine points

Before I get into more advanced examples, I want to draw your attention to a few things. First, notice how I referenced the value binding in a generic way in Listing 5:

<h:outputText value="${entity[fieldName]}"/>

Second, when I invoke this composition component, I'll pass the entity and fieldName as attributes, as shown here:

<a:column entity="${cd}" fieldName="title" backingBean="${CDManagerBean}"/>

The EL spec used by Facelets lets you refer to fields using the dot (.) notation or the less-used Map notation. For example, ${entity[fieldName]} would equate to CDManager.title if invoked as above. Notice also that I didn't need the f:verbatim tags or ancillary h:outputText. This will be true of any Facelets page you write. Facelets knows about the JSF component tree, and its sole purpose in life is to build that component tree. This is another advantage of Facelets over using JSP and Tiles.

Once I've written it, I can use the column.xhtml composition component in many other places. As a general rule: If you're breaking the DRY principle, think about using composition components instead.


Creating a component

You've had a quick look at composition components with the column.xhtml example. Now let's walk through the process of creating one step-by-step. Here are the steps to create a composition component:

  1. Create a Facelets tag library.
  2. Declare the tag library in web.xml.
  3. Import the tagfile using namespace.

Step 1. Create a Facelets tagfile

A tagfile is a file that follows the facelet_taglib_1_0.dtd. It is similar in concept to a TLD file in JSP. Listing 6 is an example tag library file:

Listing 6. A tag library file -- arcmind.taglib.xml
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "facelet-taglib_1_0.dtd">
<facelet-taglib>
      <namespace>http://www.arc-mind.com/jsf</namespace>
	<tag>
		<tag-name>field</tag-name>
		<source>field.xhtml</source>
	</tag>
	<tag>
		<tag-name>column</tag-name>
		<source>column.xhtml</source>
	</tag>
	<tag>
		<tag-name>columnCommand</tag-name>
		<source>columnCommand.xhtml</source>
	</tag>
</facelet-taglib>

The arcmind.taglib.xml file declares three tags: field, column (you've already seen that one!), and columnCommand. All you have to do is specify the name of the tag using tag-name and the location of the implementation file. The implementation file name is relative. You'll find all this code, including the DTD, in the WEB-INF\facelets\tags file of the example Web application.

Be sure to notice the namespace element that is declared before the tag element above: you'll need it later to use this tag library from another Facelets page.

Step 2. Declare the tag library in web.xml

Having a tag library is nice, but for it to be useful, you have to tell Facelets that it exists. You do this with the facelets.LIBRARIES init parameter in the web.xml file, as shown here:

<context-param>
	<param-name>facelets.LIBRARIES</param-name>
	<param-value>
		/WEB-INF/facelets/tags/arcmind.taglib.xml
	</param-value>
</context-param>

Passing facelets.LIBRARIES as a semicolon-delimited list lets you define as many tagfiles as you like.

Step 3. Import the tagfile using namespace

Once you've created your tagfile and defined it in a Facelets tag library, you're ready to use it. You use a tagfile by declaring it as an XML namespace, as shown here:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:a="http://www.arc-mind.com/jsf">

...
...

<a:column entity="${cd}" fieldName="title"  
  backingBean="${CDManagerBean}"/>
<a:column entity="${cd}" fieldName="artist" 
  backingBean="${CDManagerBean}"/>
<a:column entity="${cd}" fieldName="price" 
  backingBean="${CDManagerBean}" sort="${false}"/>
<a:columnCommand label="Edit" action="editCD"

              backingBean="${CDManagerBean}"/>

Notice the namespace defined as follows:

xmlns:a="http://www.arc-mind.com/jsf"

The namespace value is the same as the namespace element I declared in the tag library back in Step 1.


Advanced tricks and tips

That just about covers the basics of composition components. You can use what I've shown you so far to create reusable components. In my own use of Facelets, I've discovered some little tricks for making composition components even more useful, and in some cases working around small problems. For example, consider the following code fragment from the cdForm.xhtml template:

Listing 7. A fragment from cdForm.xhtml
<h:form id="cdForm">

  <h:inputHidden id="cdid" value="#{CDManagerBean.cd.id}" />

  <h:panelGrid id="formGrid" columns="3" rowClasses="row1, row2">

	<!-- Title                                   -->
	<h:outputLabel id="titleLabel" for="title" styleClass="label"
                     value="Title" />
	<h:inputText id="title" value="#{CDManagerBean.cd.title}"
				     required="true" />
	<h:message id="titleMessage" for="title" styleClass="errorText"/>

	<!-- Artist                                   -->
	<h:outputLabel  id="artistLabel" for="artist" styleClass="label" 
                     value="Artist" />
	<h:inputText id="artist" value="#{CDManagerBean.cd.artist}"
				     required="true" />
	<h:message id="titleMessage" for="artist"  
                     styleClass="errorText"/>

	<!-- Price                                   -->
	<h:outputLabel  id="priceLabel" for="price" styleClass="label" value="Price" />
	<h:inputText id="price" value="#{CDManagerBean.cd.price}"
				     required="true">
		<f:validateDoubleRange minimum="15.0" maximum="100.0" />
	</h:inputText>
	<h:message id="priceMessage" for="price" styleClass="errorText"/>

The above page is similar in concept to the one shown Listing 3 in that it leaves room for some Facelets love and a field composition component to get rid of duplicate code. Based on this code, it should be easy to create a composition component for displaying fields, but there's one little snag. Do you see it? Look at the price field of the form: it includes a validator.

Now, how do you pass a validator to a composition component?


Passing subelements

Here's a dirty little secret about Facelets: A composition component is basically a type of template. As such, you can pass a template argument using the ui:define tag that goes with a particular ui:insert, or you can pass the body as a default ui:insert.

Listing 8 is just such an implementation of the field component (field.xhtml):

Listing 8. field.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:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:z="http://www.qualcomm.com/jsf/core"
      xmlns:c="http://java.sun.com/jstl/core"
      xmlns:fn="http://java.sun.com/jsp/jstl/functions"
      xmlns:t="http://myfaces.apache.org/tomahawk">

THIS TEXT WILL BE REMOVED
<ui:composition>

	      <!--  The label is optional. 
                Generate it if it is missing. -->
		<c:if test="${empty label}">
			<c:set var="label" value="${fieldName}" />
		</c:if>
	 
	 	<!-- The required attribute is optional, 
                 initialize it to true if not found. -->
		<c:if test="${empty required}">
			<c:set var="required" value="true" />
		</c:if>
	

		<h:outputLabel id="${fieldName}Label" 
                      value="${label}" for="#{fieldName}" />			

		<h:inputText id="#{fieldName}" value="#{entity[fieldName]}" 
			             required="${required}">
			  <ui:insert />
		</h:inputText>

		<!--  Display any error message that are found -->
		<h:message id="${fieldName}Message" 
			style="color: red; text-decoration: overline" 
			for="#{fieldName}" />

</ui:composition>
THIS TEXT WILL BE REMOVED AS WELL

</html>

By now, the workaround in Listing 8 should be more or less what you expected. Notice the use of the unnamed ui:insert tag inside of h:inputText. Once you've got it, you can use this composition component as shown in Listing 9:

Listing 9. Field tag composition component
<!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:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:a="http://www.arc-mind.com/jsf">

...
<h:form id="cdForm">

	<!-- Title, Artist, Price -->
	<a:field fieldName="title" entity="#{CDManagerBean.cd}" />
	<a:field fieldName="artist" entity="#{CDManagerBean.cd}" />
	<a:field fieldName="price" entity="#{CDManagerBean.cd}" >
		<f:validateDoubleRange minimum="15.0" maximum="100.0" />
	</a:field>

...

The field tag for price gets passed the validator as an anonymous insert. Because the other fields don't define a body, the anonymous insert introduces nothing as the default.


Passing actions

At times you may want to pass an action binding to create elements like toolbars and navigation lists. The problem is that with the standard expression language you can't, but there's a workaround! In the same way that you can reference fields from an object, you can reference methods in an object. So, to create a component that creates an action binding, you could do the following (from the columnCommand.xhtml):

<h:commandLink id="#{action}" value="#{label}"  
                              action="#{backingBean[action]}"/>

Study the value of the action attribute. Notice that I've accessed the method in the same way that I earlier referenced a field from the entity. I can invoke this component using the following syntax:

<a:columnCommand label="Edit" action="editCD" 
backingBean="${CDManagerBean}"/>

This call binds the editCD() method from the CDManagerBean to the link when invoked. Listing 10 shows the complete listing for columnCommand.xhtml:

Listing 10. columnCommand.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:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:z="http://www.qualcomm.com/jsf/core"
      xmlns:c="http://java.sun.com/jstl/core">

THIS TEXT WILL BE REMOVED
<ui:composition>

	<!--  The label is optional. Generate it if it is missing. -->
	<c:if test="${empty label}">
			<c:set var="label" value="${action}" />
	</c:if>
	
	<h:column>
		<f:facet name="header">
			<h:panelGroup>
				<h:outputText value="#{label}" />
			</h:panelGroup>
		</f:facet>
		<h:commandLink id="#{action}" value="#{label}" 
                                     action="#{backingBean[action]}"/>
	</h:column>
		
</ui:composition>
THIS TEXT WILL BE REMOVED AS WELL

</html>

Downsides of Facelets

I've clearly showed the benefits of using Facelets, namely component composition and a template framework whose lingua franca is components, not Servlets output. But there are some downsides to adopting Facelets. For one thing, IDE support for Facelets is minimal. Only one Eclipse IDE implementation support Facelets at all (a commercial one; see Resources), and it doesn't seem to support code completion.

There's also no IDE support for debugging Facelets (that is, setting a break point and such). For debugging, you need to read the Facelets manual, turn on its JDK 1.4-style logging, and set up its init parameters accordingly for development.

On the upside, I found working with the Facelets API to be very natural and intuitive. The debugging was a bit arcane at first, but livable in the end. The demo applications that come with the Facelets distribution do not have examples of custom tags or functions, but the core project code does, so use that as a guide.

If you use a new JSF component library, you have to have a Facelets tag library file that exposes that library. Some tag libraries exist for major component libraries like Oracle’s and Tomahawk, but even those need tweaking. I had to tweak the Tomahawk tag library to get the Tomahawk calendar component in my application. Granted it is somewhat easy to write tag library files that export components, but it's yet another hassle. If you want to use a new custom component library, you have to write a tag library file.

Facelets seems to only work with MyFaces 1.1.1 and Sun's 1.2 JSF reference implementation because of problems in other implementations (Sun's JSF RI 1.2 is not officially out yet). You can't use Facelets with the 1.1 RI. You can't use Facelets with IBM's implementation, although you can use MyFaces with IBM WebSphere. (If you use the latest version of Facelets, you have to use the nightly build of MyFaces 1.1.2, which isn't out yet.)

Also note that the underlying mechanics of MyFaces 1.1 and the JSF RI 1.2 differ. Despite that, Facelets attempts to accommodate both implementations in their current forms (nightlines of MyFaces 1.1.2 and JSF RI 1.2), which seems to account for the bulk of the time spent recently on Facelets. It will be nice when the two conform and solidify a bit more, requiring less time to make Facelets work the same in both environments so more time can be spent improving Facelets.


In conclusion

Even with some shortcomings, I strongly recommend that you download Facelets and start using it as quickly as possible. Facelets is the future of JSF, or ought to be, and using it can keep you DRY in any JSF storm. If you can't use it on your current project, keep it in mind for your next one.

I've used Facelets to create an entire library of composition components, custom Facelet tags, and functions for an Internal CRUD framework. I've discovered a lot more tricks and techniques for building composition components (for example, a field tag that auto generates a checkbox, calendar component, or text field based on the type of the value binding that is bound to the component) than I could cover in an introductory article like this one. Instead, I've focused on the basics of getting you up and running with composition components. With what you've learned here, you can create some amazing components using just a minimal amount of custom functions and custom Facelets tags.

Acknowledgment

Special thanks Jacob Hookom, creator of Facelets, for his review and input on this article, and props to Athenz for his careful and insightful editing.


Downloads

DescriptionNameSize
Facelets source codej-facelets_code.zip267KB
Facelets source code with jars and warsj-faceletsjarsandwars.zip47MB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=104099
ArticleTitle=Facelets fits JSF like a glove
publish-date=02212006