JavaServer Faces, redux

An update on JSF's features and functions

Shortly after the first JavaServer Faces (JSF) early access (EA) release was introduced in September 2002, I wrote two JavaWorld articles detailing JSF (see Resources). Since then, JSF has matured considerably over four EA releases, and today, with a beta release in the wings, is poised to take the stage as the preeminent Java Web application framework. Furthermore, as the standard framework for developing Web applications, JSF will enjoy strong tool support from vendors like Sun Microsystems and its Project Rave development tool—a direct competitor to Microsoft's Visual Studio.

The underlying concepts from my first two JSF articles are still valid, but a multitude of changes to JSF has resulted in a different approach to implementing JSF applications. If you are unfamiliar with JSF, I suggest you review those articles; I will not repeat introductory material here.

These are the major additions to JSF since EA1:

  • Application configuration resources
  • Navigation handling
  • Actions
  • JavaBeans event model
  • Managed Bean Creation facility
  • Portlet compatibility
  • Framework extensions

In this article, I begin with an overview of each of these JSF additions. Once you have a solid theoretical understanding, I'll look at an updated version of the simple login application discussed in my first JavaWorld JSF article. That discussion will make the theoretical more concrete.

Read the previous "A First Look at JavaServer Faces" series:

Note: The code discussed in this article is based on the Early Access 4 release, which you can get by downloading the Java Web Services Developer Pack (JWSDP). See Resources for a link to the JWSDP download page.

Application configuration resources

Application configuration resources are resources you specify in an XML configuration file (typically /WEB-INF/faces-config.xml) instead of Java code; for example, you can specify navigation and managed beans (meaning beans created and managed by JSF) in faces-config.xml. Otherwise known as declarative programming, this is a feature Java 2 Platform, Enterprise Edition (J2EE) developers have learned to appreciate. Specifying things in XML is easier than writing code, and this XML is accessible to page authors with no Java experience. Plus, you can change resources without recompiling. Many JSF resources are now specified in configuration files; here's a partial list:

  • Navigation rules
  • Managed beans
  • Custom components
  • Converters
  • Validators
  • Render kits

Application configuration resources are closely tied to two other features listed above: navigation handling and the Managed Bean Creation facility. Both of those features are specified in the JSF configuration file and are discussed below.

Note: Although /WEB-INF/faces-config.xml is the default JSF configuration file, you can specify an alternate file, or a list of files, that serve as the application configuration file(s).

Actions and navigation handling

In JSF EA1, developers were forced to write an application handler that handled all of an application's action (application-specific) events. That application handler didn't scale well because it was essentially a switch statement that handled all action events. JSF EA4, like Struts, lets developers use the Command pattern to represent actions as objects instead of cases in a switch statement. (See "Take Command of Your Software" (JavaWorld, June 2002) for more about the Command pattern.)

Actions have a processAction() method that returns a string representing the action's outcome. The JSF framework uses that outcome to forward the request to some destination. Navigation, in terms of outcomes and forwarding destinations, among other things, are specified in—you guessed it—a faces configuration file.

A combination of actions and declarative navigation handling accomplishes two things: it moves developers from switch statements to the Command pattern and allows navigation rules, in terms of things like outcomes and JSP pages, to be specified in a faces configuration file. That's a strong one-two combination for maintainability and extensibility.

JavaBeans event model

Event models are an integral part of component frameworks because they let you react to component events, such as when a button is clicked or a value is changed. JSF EA4 offers two types of events and associated listeners: action events, fired when a button or link is activated, and value-changed events, fired when an input component's value is changed. If you use JSF with JavaServer Pages (JSP), you can register event handlers for components like this:

<h:input_text valueRef='someBean.someProperty'>
   <f:valuechanged_listener type='SomeListenerClass'/>
<h:command_button key='submit.button.prompt' bundle='messages'>
   <f:action_listener type='AnotherListenerClass'/>

A full-fledged event-handling example is discussed at the end of this article.

Managed Bean Creation facility

JSF lets you directly wire components to bean properties; for example:

  <h:input_secret valueRef='loginForm.password'/>

The preceding tag represents an input component whose value is wired to the password property of a bean named loginForm. Early JSF versions supported wiring components to bean properties (valueRef has replaced the modelReference attribute), but the developer had to instantiate the bean, typically with <jsp:useBean>. With EA4, the JSF framework takes care of instantiating those beans; all you need to do is declare them in a faces configuration file. The configuration file also lets you specify bean properties and runtime relationships between those beans. Those configuration files sure are handy!

Portlet compatibility

JSF EA4 provides portlet compatibility by eliminating references to the servlet API. For instance, in EA1, you could obtain a reference to the servlet context by calling FacesContext.getServletContext(), but that code won't work in a portlet; instead, you would need a reference to the portlet context. JSF EA4 no longer has a FacesContext.getServletContext() method; instead, you call FacesContext.getExternalContext(). The ExternalContext class is a wrapper around some type of context (servlet or portlet, typically). You can use the external context to access container contexts in a neutral fashion. For example, ExternalContext.getRequest() returns an Object reference that either points to a ServletRequest instance or an instance of PortletRequest; you cast the Object reference to whatever is appropriate. If you must have a reference to either the ServletContext or PortletContext, you can call ExternalContext.getContext(), which also returns an Object reference that you must cast.

Framework extensions

Finally, JSF EA4 lets developers modify and extend the JSF framework with pluggable objects for:

  • Navigation handler
  • Default action listener
  • Property resolver
  • Variable resolver
  • View handler

There are many reasons why you might want to change the default functionality offered by the objects listed above. For example, you might want to embed security checks in JSF every time the navigation handler forwards to a resource based on an outcome; if so, you could implement your own navigation handler and substitute it for the default. Perhaps you want JSF to recognize your own implicit objects in its value reference expressions; you can do that with a custom variable resolver. Of course, you register your custom classes—for example, AcmeNavigationHandler or AcmeVariableResolver—in a faces configuration file.

Old versus new

Now that you have a theoretical understanding of new JSF features, let's examine some code by comparing an application I wrote for EA1 and subsequently rewrote for EA4. In my first JavaWorld JSF article, I discussed the simple login application displayed in Figure 1.

Figure 1. A simple JSF login application. Click on thumbnail to view full-size image.

Figure 1's application works as you would expect: input is verified, and if correct, the application forwards to a welcome page. If login information is incorrect, the application redisplays the login page with an error message, as Figure 1 shows. The application uses standard JSF components and validators. Let's compare the original implementation with more current code.

The most offensive injustice a developer had to endure with JSF EA1 was the application handler—boilerplate code for event handling and navigation that had to be implemented by every JSF application. In my original JavaWorld JSF series, I implemented the application handler listed in Example 1.

Example 1. A JSF EA1 application handler

package com.sabreware.appHandlers;
import javax.faces.FactoryFinder;
import javax.faces.context.FacesContext;
import javax.faces.event.FacesEvent;
import javax.faces.lifecycle.ApplicationHandler;
import javax.faces.tree.TreeFactory;
public class SimpleApplicationHandler implements ApplicationHandler {
   public boolean processEvent(FacesContext context, FacesEvent facesEvent) {
      TreeFactory treeFactory = (TreeFactory)FactoryFinder.
                  treeFactory.getTree(context.getServletContext(), "/welcome.jsp"));
      return true;

The preceding application handler forwards all JSF requests to /welcome.jsp, so clicking Figure 1's Log In button always takes you to /welcome.jsp as long as there are no validation errors. In addition to the application handler, JSF EA1 required developers to implement a servlet context listener to install the application handler. I list the servlet context listener for my original JSF article series in Example 2.

Example 2. A servlet context listener installs the application handler

package com.sabreware.listeners;
import javax.servlet.*;
import javax.faces.*;
import javax.faces.lifecycle.*;
import com.sabreware.appHandlers.SimpleApplicationHandler;
public class SimpleServletContextListener implements ServletContextListener {
   public void contextInitialized(ServletContextEvent e) {
      LifecycleFactory factory = (LifecycleFactory)
      Lifecycle lifecycle = factory.getLifecycle(
      lifecycle.setApplicationHandler(new SimpleApplicationHandler()); 
   public void contextDestroyed(ServletContextEvent e) {
      // Nothing to do here

Finally, you had to register Example 2's context listener in /WEB-INF/web.xml, as Example 3 shows.

Example 3. The servlet context listener is registered in /WEB-INF/web.xml

<?xml version="1.0"?>
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   <!-- Context Listener creates and sets the application handler -->

The preceding listings show an awfully long-winded way to say go to /welcome.jsp. Instead of implementing code that grapples with factories and other JSF objects that the average developer will otherwise never directly access, Example 4 shows how Examples 1 through 3 are represented in JSF EA4.

Example 4. Navigation rules specified in XML replace Java code

      <description>All JSF requests (there's only one request in
                   this application) are directed to /welcome.jsp</description>

Example 4's XML is an excerpt from a faces configuration file that mimics the code from Examples 1 through 3: all JSF requests are forwarded to /welcome.jsp. Look how much work you save specifying that simplest of navigations: two Java source files and an entry in /WEB-INF/web.xml have been reduced to six lines of XML. And if you decide to change, for instance, /welcome.jsp to /start.jsp, you can do that without modifying or recompiling Java code.

Besides navigation handling, the old application handler was responsible for reacting to all application events. Figure 1's login application only has one event (Log In button activation), but in reality application handlers quickly became unmanageable switch statements that looked something like this:

public class UglyApplicationHandler implements ApplicationHandler {
   public boolean processEvent(FacesContext context, FacesEvent facesEvent) {
      if(facesEvent instanceof CommandEvent) {
         if("loginForm.login".equals(facesEvent.())) {
            // Code for logging in
         else if("loginForm.cancel".equals(facesEvent.())) {
            // Code for canceling the login form
         else if("loginForm.reset".equals(facesEvent.())) {
            // Code for resetting the login form
         if("registerForm.register".equals(facesEvent.())) {
            // Code for registering
         else if("registerForm.cancel".equals(facesEvent.())) {
            // Code for canceling the registration form
      TreeFactory treeFactory = (TreeFactory)FactoryFinder.
      if(someConditionSetInCodeAbove) {
                  treeFactory.getTree(context.getServletContext(), "/somewhere.jsp"));
      else if(someOtherConditionSetInCodeAbove) {
                  treeFactory.getTree(context.getServletContext(), "/somewhere-else.jsp"));
      return true;

Nobody wants to maintain giant switch statements, which are the impetus for the Command pattern. That pattern, which turns cases in a switch statement into objects, is widely used among user interface frameworks such as Swing, Struts, and now, JavaServer Faces. The Command pattern is popular because of its maintainability, flexibility, and extensibility. With JSF EA4, the Command pattern does away with the application handler altogether: each of the if statements above is transformed into a JSF action. One of those actions might look like this:

public class LoginAction extends javax.faces.application.Action {
   public String invoke() {
      // Code for logging in
         return "succeeded";
         return "failed";

Notice the preceding action's invoke() method returns either succeeded or failed. The JSF navigation handler uses those strings to determine a forwarding destination. Those destinations are specified in a faces configuration file:


The preceding XML specifies two navigation cases for JSF requests that come from /login.jsp. If the outcome, which is the string returned by the login action, is succeeded, the JSF navigation handler loads /welcome.jsp; otherwise, if the outcome is failed, the navigation handler loads /login-error.jsp.

That's how you implement an action and hook into the navigation system. How do you use an action? In JSP pages, actions are referenced with actionRefs like this:

<%@ taglib uri='' prefix='h' %@>
<h:command_button actionRef='login.action'/>

The preceding tag represents a button whose actionRef is login.action. When a user clicks the button, the getAction() method of a bean named login is invoked. That bean is instantiated by the JSF framework the first time it's referenced. The framework knows to instantiate the bean because it's specified in the faces configuration file:


Here's what the Login class looks like:

public class Login {
   public Action getAction() {
      return new LoginAction();

The Login.getAction() method returns a reference to an instance of LoginAction, listed above. So, actionRef='login.action' resolves to a call to Login.getAction(), which returns a reference to a LoginAction instance. The JSF framework then calls LoginAction.invoke(), and the business of logging in is carried out like this:

public class LoginAction extends javax.faces.application.Action {
   public void invoke() {
      // Implement login business logic here or delegate to
      // a pure business object

Value-changed events

In JSF, actions implement business logic, as illustrated above. Sometimes, however, you want to implement user interface (UI) logic in reaction to an event. For example, consider Figure 2's application: if the user selects United States for the country, the form contains fields for city and state. But if the user selects Canada, those fields change to municipality and province, respectively. That sleight-of-hand is implemented with a JSF value-changed event listener.

Figure 2. An accommodating user interface (United States)
Figure 3. An accommodating user interface (Canada)

The preceding application's value-changed listener is easy to implement and use. Example 5 lists this JSP login page.

Example 5. Use a value-changed listener

<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 Transitional//EN'>
   <%@ taglib uri='' prefix='f' %>
         <%@ taglib uri=''  prefix='fmt' %>
         <%@ taglib uri=''  prefix='h' %>
         <%@ taglib uri='' prefix='c' %>
         <fmt:setBundle basename='messages' scope='session' var='messages'/>
            <h:output_text key='register.window.title' bundle='messages'/>
      <style type='text/css'>
         @import url(<c:out value='${pageContext.request.contextPath}'/>/site.css);
         <h:output_text key='' bundle='messages' 
         <h:form formName='blank'>
            <h:panel_grid columns='2'>
               <h:output_text key='register.streetAddress.prompt' bundle='messages'/>
               <h:input_text id='streetAddress' valueRef='registerForm.streetAddress'/>
               <h:output_text id='cityPrompt' key='' bundle='messages'/>
               <h:input_text id='city' valueRef=''/>
               <h:output_text id='statePrompt' key='register.state.prompt' bundle='messages'/>
               <h:input_text id='state' valueRef='registerForm.state'/>
               <h:output_text key='' bundle='messages'/>
               <h:selectone_menu valueRef=""
                  <f:valuechanged_listener type='listeners.CountryChanged'/>
                  <h:selectitems valueRef='registerForm.countryNames'/>
            <h:command_button actionRef='registerForm.action' 
                                     key='register.submit' bundle='messages' 

In Example 5, I assigned unique IDs to the city and state prompts; the listener specified with the <f:valuechanged_listener> tag uses those IDs. I list that listener in Example 6.

Example 6. Implement a value-changed listener

package listeners;
import javax.faces.event.ValueChangedEvent;
import javax.faces.event.ValueChangedListener;
import javax.faces.event.PhaseId;
public class CountryChanged implements ValueChangedListener {
   public PhaseId getPhaseId() {
      return PhaseId.ANY_PHASE;
   public void processValueChanged(ValueChangedEvent event) {
      UIComponent c = (UIComponent)event.getSource(),
        cityPrompt  = c.getParent().findComponent("cityPrompt"),
        statePrompt = c.getParent().findComponent("statePrompt");
      if("Canada".equals(event.getNewValue())) {
         cityPrompt.setAttribute ("key", "register.municipality.prompt");
         statePrompt.setAttribute("key", "register.province.prompt");
      else {
         cityPrompt.setAttribute ("key", "");
         statePrompt.setAttribute("key", "register.state.prompt");

The preceding listener obtains a reference to the city and state prompt components and changes their values depending on the new value chosen from the country drop-down list.

Onward and upward

JavaServer Faces has come a long way since its first EA release. Many of the major deficiencies in that first release have been addressed. Today, JSF lets developers write robust, maintainable, and extensible Web applications. With a beta release in the wings—that promises more exciting features such as a data grid component and easier-to-use internationalization—JSF is poised to become the standard Java Web application framework, which should speed its adoption, both by users and IDE vendors.

David Geary is the author of Core JSTL Mastering the JSP Standard Tag Library (Prentice Hall, 2002; ISBN: 0131001531), Advanced JavaServer Pages (Prentice Hall, 2001; ISBN: 0130307041), and the Graphic Java series (Prentice Hall). David has been developing object-oriented software with numerous object-oriented languages for almost 20 years. Since reading the GOF Design Patterns book in 1994, David has been an active proponent of design patterns, and has used and implemented design patterns in Smalltalk, C++, and Java. In 1997, David began working full-time as an author and occasional speaker and consultant. David is a member of the expert groups defining the JSP Standard Tag Library and JavaServer Faces, and is a contributor to the Apache Struts JSP framework. David is currently working on Core JavaServer Faces, which will be published in the spring of 2004.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more