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.
.
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.
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 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.
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

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

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.
The steps to install Facelets are easy to follow. Note that I'm assuming you've already downloaded and installed the example application.
- Download the Facelets distribution and unzip it.
- 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).
- Add the Facelet init parameter(s) to the web.xml file.
- Add the FaceletViewHandler to the faces-config.xml file.
Steps 1 and 2 are basic. I'll cover the other two in detail.
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.
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>
|
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:
- Create a layout.xhtml page.
- Import the use of Facelets by defining the Facelet's namespace.
- Use
ui:inserttag to define logical areas of the page. - Use plain text and
ui:includetags 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!
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.
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.
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.
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>
|
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.
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:
- Create a Facelets tag library.
- Declare the tag library in web.xml.
- 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.
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?
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.
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>
|
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.
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.
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.
| Description | Name | Size | Download method |
|---|---|---|---|
| Facelets source code | j-facelets_code.zip | 267KB | HTTP |
| Facelets source code with jars and wars | j-faceletsjarsandwars.zip | 47MB | HTTP |
Information about download methods
Learn
- "JSF for nonbelievers: Clearing the FUD about JSF" (Richard Hightower, developerWorks, February 2005): A four-part series that defends and demystifies JSF programming. See
Part 2 for the original online CD store example used here.
- "In tune with Tapestry" (Brett McLaughlin, developerWorks, January 2006): An excellent two-part introduction to Tapestry.
- "Inside Facelets Part 1: An Introduction" (Jacob Hookom, JSF Central, August 2005): Thoughts on Facelets from its creator.
- Facelets documentation: See a complete listing of Facelets parameters.
- Another Sleepless Night in Tucson:
Author Rick Hightower's blog, where he thinks aloud about JSF (not to mention wine and cooking) till the wee hours of the morning.
- The Java technology zone: Hundreds of articles about every aspect of Java programming.
Get products and technologies
- Got JSR 252?: Download
JavaServer Faces.
- Facelets home page: Download Facelets.
- XULFaces:
One of the alternatives to XHTML markup in Facelets.
Discuss
- developerWorks
blogs: Get involved in the developerWorks community!
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.





