Skip to main content

JSF for nonbelievers: The JSF application lifecycle

Walk through the 6 phases of JSF's request processing lifecycle

Rick Hightower serves as chief technology officer for ArcMind Inc. He is co-author of the popular book Java Tools for Extreme Programming, about applying extreme programming to J2EE development, as well as co-author of Professional Struts. He worked on JSF QuickStart with Warner Onstine, and some of the material in this series is based on examples in that course. The discussion of JSF lifecycle is based on Warner's discussion of it in the ArcMind course, with some embellishments from Hightower. The lifecycle diagrams were created by Paul Tabor for the ArcMind JSF course; you will learn more about him when you read the third article in this series. Contact Hightower at rhightower@arc-mind.com.

Summary:  In this second article in his four-part JSF for nonbelievers series, Rick Hightower introduces the major phases of the JavaServer Faces (JSF) request processing lifecycle. Using a sample application, he walks you through the six phases of a request process. Along the way, he shows you how to combine JSF with JavaScript technology for immediate event handling and completes your introduction to the JSF component model with a first look at many of the components that ship with JSF.

Editor's notes: Since publication, Sun has open sourced JSF 1.2 under their CDDL license. See Resources for a link to the new project page.
For details on getting started with JSF 1.2, now integrated in JEE 5, see Richard Hightower's tutorial series.

View more content in this series

Date:  01 Mar 2005
Level:  Intermediate PDF:  A4 and Letter (93KB)Get Adobe® Reader®
Activity:  54508 views

Contrary to popular belief, it's possible to write Java™Server Faces (JSF) applications without knowing every little detail of how the technology works. You can learn a tremendous amount by just giving yourself a project and cobbling through it to the end. On the other hand, understanding certain fundamentals will make your development efforts much more rewarding -- and a lot less time-consuming.

In this second article in the JSF for nonbelievers series, I'll walk you through the six phases of the JSF request processing lifecycle. I'll explain what happens in each phase and how the phases interconnect, then use an example application to demonstrate the lifecycle in action. Along the way, I'll also show how to work with some of the built-in JSF components briefly touched on in Part 1. I'll also show you how to incorporate Struts Tiles into your JSF development, and how to combine JSF and JavaScript for immediate event handling.

As in the previous article, the default build environment for the example application is Maven. You can download the example source by clicking the Code icon at the top or bottom of this page. For simplicity, you'll find the example setup the same as it was in the previous article. See Resources for further directions on the build environment setup, including directions for building and running the example application in Ant, rather than Maven.

The JSF lifecycle: an overview

The six phases of the JSF application lifecycle are as follows (note the event processing at each phase):

  1. Restore view
  2. Apply request values; process events
  3. Process validations; process events
  4. Update model values; process events
  5. Invoke application; process events
  6. Render response

The six phases show the order in which JSF typically processes a form GUI. The list shows the phases in their likely order of execution with event processing at each phase, but the JSF lifecycle is hardly set in stone. You can change the order of execution by skipping phases or leaving the lifecycle altogether. For example, if an invalid request value were copied to a component, the current view would be redisplayed, and some of the phases might not execute. In this case, you could issue a FacesContext.responseComplete method invocation to redirect the user to a different page, then use the request dispatcher (retrieved from the request object in the FacesContext) to forward to an appropriate Web resource. Alternately, you could call FacesContext.renderResponse to re-render the original view. (See the sample application below for details.)

About this series

This four-part series is dedicated to dispelling fear, uncertainty, and doubt (FUD) about JavaServer Faces (JSF) technology, mainly by giving you a chance to get to know it for yourself in a step-by-step, easy-to-follow format. Over the course of four articles, I'll provide a series of examples to introduce you to the basic architecture, features, and functionality of JSF. Once you're familiar with the JSF way of doing things, I think you'll find it hard to go back to Struts Model 2-style development. After all, who would want to revisit XML configuration Hades after experiencing the JSF event-driven, GUI component model?

To get the most out of this series, you should be familiar with Java programming, JavaBeans (namely, event model and properties), JavaServer Pages (JSP), the JSP Standard Tag Library Expression Language, and all basic Web development concepts.

The point is to let the lifecycle structure your development efforts without feeling completely tied to it. You can alter the lifecycle when needed without fear of breaking your application. In most cases, you'll find that the JSF lifecycle is worth adhering to because it's quite logical. Forms have to be validated before any application logic can be executed, and field data has to be converted before being validated. Sticking to the lifecycle frees you up to think about the details of validation and conversion, rather than the phases of the request process itself. It's also important to note that other Web frameworks have similar lifecycles; they just don't tend to be as well advertised.

Focusing your efforts

Some developers using JSF may never write a component or extend the framework, while others may focus on just those tasks. While the JSF lifecycle will be the same for almost any project, you'll likely tap into it at different stages based on your role in the project. If you're concentrating more on the overall application development, you'll likely be concerned with the middle phases of the request processing lifecycle:

  • Apply requests values
  • Process validations
  • Update model values
  • Invoke application

If you're concentrating on JSF component development, you'll probably focus on the first and last phases of the lifecycle:

  • Restore view
  • Render response

In the sections that follow, I'll walk you through every phase of the JSF request processing lifecycle, including event handling and validation. Once you have a basic understanding of each phase, I'll introduce a sample application that shows how they all come together. Before we get started, take a look at Figure 1, a diagram of the JSF lifecycle.


Figure 1. The JSF lifecycle
A JSF lifecycle diagram

Phase 1: Restore view

In the first phase of the JSF lifecycle -- restore view -- a request comes through the FacesServlet controller. The controller examines the request and extracts the view ID, which is determined by the name of the JSP page.

The JSF framework controller uses the view ID to look up the components for the current view. If the view doesn't already exist, the JSF controller creates it. If the view already exists, the JSF controller uses it. The view contains all the GUI components.

This phase of the lifecycle presents three view instances: new view, initial view, and postback, with each one being handled differently. In the case of a new view, JSF builds the view of the Faces page and wires the event handlers and validators to the components. The view is saved in a FacesContext object.

The FacesContext object contains all the state information JSF needs to manage the GUI component's state for the current request in the current session. The FacesContext stores the view in its viewRoot property; viewRoot contains all the JSF components for the current view ID.

In the case of an initial view (the first time a page is loaded), JSF creates an empty view. The empty view will be populated as the user causes events to occur. From an initial view, JSF advances directly to the render response phase.

In the case of a postback (the user returns to a page she has previously accessed), the view corresponding to the page already exists, so it needs only to be restored. In this case, JSF uses the existing view's state information to reconstruct its state. The next phase after a postback is apply request values.


Phase 2: Apply request values

The purpose of the apply request values phase is for each component to retrieve its current state. The components must first be retrieved or created from the FacesContext object, followed by their values. Component values are typically retrieved from the request parameters, although they can also be retrieved from cookies or headers.

If a component's immediate event handling property is not set to true, the values are just converted. So if the field is bound to an Integer property, the value is converted to an Integer. If the value conversion fails, an error message is generated and queued in the FacesContext, where it will be displayed during the render response phase, along with any validation errors.

If a component's immediate event handling property is set to true, the values are converted to the proper type and validated. The converted value is then stored in the component. If the value conversion or value validation fails, an error message is generated and queued in the FacesContext, where it will be displayed during the render response phase, along with any other validation errors.

Immediate event handling

The immediate event handling property of JSF is used to handle events that normally don't necessitate validating the entire form. For example, say an employee form has a radio button denoting whether an employee is a manager. When the employee selects the Manager option, the application populates a list of perks for managers. Because the radio button is used only to populate the list and does not require the user to fill out the entire form, you do not need to validate the form in its entirety. In this case, you would use immediate event handling. See Immediate event handling for further details on this subject.


Phase 3: Process validation

The first event handling of the lifecycle takes place after the apply request values phase. At this stage, each component will have its values validated against the application's validation rules. The validation rules can be pre-defined (shipped with JSF) or defined by the developer. Values entered by the user are compared to the validation rules. If an entered value is invalid, an error message is added to FacesContext, and the component is marked invalid. If a component is marked invalid, JSF advances to the render response phase, which will display the current view with the validation error messages. If there are no validation errors, JSF advances to the update model values phase.


Phase 4: Update model values

The fourth phase of the JSF application lifecycle -- update model values -- updates the actual values of the server-side model -- namely, by updating the properties of your backing beans (also known as managed beans). Only bean properties that are bound to a component's value will be updated. Notice that this phase happens after validation, so you can be sure that the values copied to your bean's properties are valid (at least at the form-field level; they may still be invalid at the business-rule level).


Phase 5: Invoke application

At the fifth phase of the lifecycle -- invoke application -- the JSF controller invokes the application to handle Form submissions. The component values will have been converted, validated, and applied to the model objects, so you can now use them to execute the application's business logic.

At this phase, you also get to specify the next logical view for a given sequence or number of possible sequences. You do this by defining a specific outcome for a successful form submission and returning that outcome. For example: on successful outcome, move the user to the next page. For this navigation to work, you will have to create a mapping to the successful outcome as a navigation rule in the faces-config.xml file. Once the navigation occurs, you move to the final phase of the lifecycle.


Phase 6: Render response

In the sixth phase of the lifecycle -- render response -- you display the view with all of its components in their current state.

Figure 2 is an object state diagram of the six phases of the JSF lifecycle, including validation and event handling.


Figure 2. The six-phase progression of the JSF lifecycle
Object state diagram of JSF lifecycle

A working example

Now that you have a basic understanding of the phases of the JSF lifecycle, I'll show you how they all work together in an example Web application. In addition to demonstrating the basic functions of the JSF lifecycle, the application utilizes common JSF GUI components like Radio List, List, Text Field, Label, Panel, and more, so you can experience first-hand some of the components discussed briefly in Part 1.

The example application also demonstrates a couple of ways to combine JSF with other Java technologies. It combines JSF and JavaScript to enable immediate event handling (in cases where validating an entire form is unwanted), and its layout is managed by Struts Tiles. Struts Tiles is not necessarily part of JSF, but tiles are commonly used to lend a consistent look and feel to all the JSF pages in an application. See Resources to learn more about Struts Tiles.

Application setup

The example Web application is essentially a simple create, read, update, and delete (CRUD) listing that manages inventory for an online CD store. It includes a form that lets the end user enter a new CD into the system and a list of radio buttons that lets him select a music category. When the user selects a category, you'll fire off some JavaScript to post the form immediately back to the server. Combining JSF with JavaScript to deal with just one component, rather than the entire page, is called immediate event handling. In this case, it lets you populate a subcategory list without validating the rest of the form.

The example application also includes a CD listing that demonstrates how to work with JSF dataTables. From the listing page, the end user can sort the CD listing by title or by artist.

Classes and methods

Figure 3 shows the classes of the example application. Of the four classes shown, we're concerned only with three: StoreManagerDelegate, CD, and StoreController.


Figure 3. Example application classes
Example application classes

The StoreManagerDelegate class is the application's business delegate. It represents the main interface to the model. The CD class is a data transfer object (DTO). If this were a real application, the StoreManagerDelegate class would implement all the business rules for adding, deleting, and editing CDs, and would delegate storing a CD to a persistent store with a data access object (DAO). The StoreManagerDelegate and the CD comprise the model for this MVC application.

The StoreController class is the main backing bean for this example. The StoreController class is the glue from the GUI world to the model world. It delegates a lot of its behavior to the StoreManagerDelegate. The StoreController is the controller for this MVC application.

The StoreController class demonstrates how to build a sortable CRUD listing. It has the following CRUD-related methods:

  • editCD
  • addNew
  • addCD
  • updateCD

The StoreController is also responsible for presenting the model object to the form. In this case, it presents the current CD object to the CD form using its cd property, which is of type CD.


Let's code it

The best way to get started with coding the example application is to walk through its use cases:

  1. Add a new CD
  2. Edit an existing CD
  3. Sort CDs by title
  4. Sort CDs by artist

The code for the third and fourth use cases will be nearly identical, so I'll show you how to sort by title and leave the fourth as an exercise for you to complete on your own. We'll code the use cases soon, but first, let's take a look at what the pages will look like for the completed application.

Not quite CRUD

Note that the application is not an actual CRUD listing. It's really just a CRU listing, as I've left the D for you to implement. But don't sweat it -- it's quite easy. The steps for the delete operation are similar to the ones for the edit operation, which I've implemented for you here. Can you complete the CRUD?

Figure 4 shows the CD listing page with its sortable columns.


Figure 4. The CD listing page with sortable columns
CD Listing

Figure 5 shows the CD form page with its category component.


Figure 5. The CD form page with no category selected
CD Form

Figure 6 shows the CD form page with its category and subcategory components.


Figure 6. The CD form page with categories and subcategories selected
CD Form

Use case 1: Add a new CD

In the first use case for the application, the user adds a new CD by going to the CD listing page and clicking the Add CD link, which is defined in the listing.jsp file, as shown in Listing 1.


Listing 1. Add CD button defined in listing.jsp
<h:commandLink action="#{CDManagerBean.addNew}">
     <f:verbatim>Add CD</f:verbatim>
</h:commandLink> 

This link is bound to the CDManagerBean's addNew method. The addNew method is invoked in the (final) invoke application phase of the JSF lifecycle. The action is bound to this method with the JSF binding expression #{CDManagerBean.addNew}. CDManagerBean is an alias for the application's store controller. CDManagerBean is the logical name for the controller. The controller class is a managed bean defined in the faces-config.xml file, as shown in Listing 2.


Listing 2. StoreController class defined in faces-config.xml
<managed-bean>
  <description>The "backing file" 
    bean that backs up the CD application</description>
  <managed-bean-name>CDManagerBean</managed-bean-name>
  <managed-bean-class>
    com.arcmind.jsfquickstart.controller.StoreController
      </managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

Preparing the form

The addNew() method prepares the form by creating an empty CD, as shown in Listing 3.


Listing 3. addNew() creates an empty CD form
[StoreController.java]
/**
 * Prepare the cdForm to add a new CD. 
 * This gets executed before we prompt
 * the user to add a new CD.
 *
 * @return success
 */
public String addNew() {
    if (subCategoryList == null) {
        subCategoryList = new HtmlSelectOneListbox();
    }

    subCategoryList.setRendered(false);
    this.cd = new CD();

    return "success";
}

The addNew() method blanks out the CD form fields by creating a new CD. The fields of the CD form are bound to the cd property's properties. This method also blanks out the list of subcategories being displayed.

Returning a successful result

Next, the addNew() method is invoked, and control is redirected to the success mapping, which is the cdForm.jsp file. The cdForm.jsp file is defined in the faces-config.xml file, as shown in Listing 4.


Listing 4. cdForm.jsp is the success mapping for addNew()
<navigation-rule>
  <from-view-id>/listing.jsp</from-view-id>
  ...
  <navigation-case>
    <from-action>#{CDManagerBean.addNew}</from-action>
    <from-outcome>success</from-outcome>
    <to-view-id>/cdForm.jsp</to-view-id>
  </navigation-case>
    
</navigation-rule>

Listing 4 states that if the user went from the listing to the addNew (#{CDManagerBean.addNew}) action, and the addNew action returned success, then would go to the cdForm.jsp.

Setting up the cdForm and panelGrid

cdForm.jsp is the form that contains the CD form. It has fields for ID, Title, Artist, Price, Category, and Subcategory. The fields are placed in a container called a panelGrid. JSF components, like AWT components, have containers and components. A container is a component that contains other components. This is an example of the composite design pattern. The panelGrid has three columns. Each field is laid out on its own row with a label and a message to display error messages for the field. The cdForm and panelGrid are defined in Listing 5.


Listing 5. cdForm and panelGrid defined
<f:view>
    <h2>CD Form</h2>
 
    <h:form id="cdForm">
 
    <h:inputHidden id="cdid" value="#{CDManagerBean.cd.id}"/>
 
    <h:panelGrid columns="3" rowClasses="row1, row2">
 
       <h:outputLabel for="title" styleClass="label">
           <h:outputText value="Title"/>
       </h:outputLabel>

       <h:inputText id="title" 
         value="#{CDManagerBean.cd.title}" required="true"/>

       <h:message for="title" styleClass="errorText"/>

       <h:outputLabel for="artist" styleClass="label">
           <h:outputText value="Artist"/>
       </h:outputLabel>

       <h:inputText id="artist" 
         value="#{CDManagerBean.cd.artist}" required="true"/>

       <h:message  for="artist"  styleClass="errorText"/>

       <h:outputLabel  for="price" styleClass="label">
           <h:outputText value="Price"/>
       </h:outputLabel>

       <h:inputText id="price" 
         value="#{CDManagerBean.cd.price}" required="true"/>

       <h:message for="price" styleClass="errorText"/>

       <h:outputLabel for="category" styleClass="label">
           <h:outputText value="Category"/>
       </h:outputLabel>

       <h:selectOneRadio id="category" 
         value="#{CDManagerBean.cd.category}" immediate="true" 
         onclick="submit()"
         valueChangeListener="#{CDManagerBean.categorySelected}">
           <f:selectItems value="#{CDManagerBean.categories}"/>
       </h:selectOneRadio>

       <h:message for="category" styleClass="errorText"/>

       <h:outputLabel for="subcategory" styleClass="label">
           <h:outputText value="Subcategory"/>
       </h:outputLabel>
	
       <h:selectOneListbox id="subcategory" 
         value="#{CDManagerBean.cd.subCategory}"
         binding="#{CDManagerBean.subCategoryList}">
           <f:selectItems value="#{CDManagerBean.subCategories}"/>
       </h:selectOneListbox>

       <h:message  for="subcategory"  styleClass="errorText"/>

    </h:panelGrid>

    <br />

    <h:commandButton id="submitAdd" 
      action="#{CDManagerBean.addCD}" value="Add CD" 
      rendered="#{not CDManagerBean.editMode}"/>

    <h:commandButton id="submitUpdate" 
      action="#{CDManagerBean.updateCD}" value="Update CD" 
      rendered="#{CDManagerBean.editMode}"/>

    </h:form>
        
</f:view>

Notes about the code

Each input field binds the field to a property of the controller's cd property. For example, the input text field for the title is bound to the cd property with the following JSF binding expression: value="#{CDManagerBean.cd.title}".

You likely noticed that there is hardly any HTML in Listing 5. This is because the panelGrid generates most of the HMTL. Note that the real look and feel is determined by the style sheets associated with the panelGrid. The attribute rowClasses="row1, row2" sets the CSS classes for alternating rows. Row1 is white, and Row2 is gray. You can also specify the CSS classes for columns and much more. The JSF panelGrid component makes it convenient to quickly lay out a form. If you want to do something that the panelGrid does not provide, you don't have to use it: You can lay out your components using HTML. However, if you find that you use custom HTML on many pages, you may want to consider writing your own custom component. The idea is to make your reusable HTML as DRY as possible (DRY stands for don't repeat yourself, a term coined by Dave Thomas, the Pragmatic Programmer).

Something else to note about Listing 5 is that the controller presents an editMode property, which is used by the cdForm.jsp to selectively display the submitAdd button or thesubmitUpdate button; the submitAdd button is displayed when the form is not in edit mode. The submitUpdate button is displayed when the form is in edit mode. This makes it easy to use the same JSP for edit and add mode. (By default, the form is not in edit mode.) This magic is accomplished by the rendered expression on each button in the cdForm.jsp. For example, Listing 6 shows the rendered expression on the submitAdd button rendered="#{not CDManagerBean.editMode}". The submitAdd button is bound to the addCD method using the expression (action="#{CDManagerBean.addCD}") .


Listing 6. Adding a CD using the addCD() method
[StoreController.java]
/**
 * Add a cd to the store.
 *
 * @return outcome
 */
public String addCD() {
    store.addCD(this.cd);

    return "success";
}

Validating the fields

Before the addCD method is invoked, JSF has to validate the fields from the GUI. This is actually fairly easy, since you haven't associated the fields with any validators. The values are copied from the request parameters to the components' values (by the components themselves) in the apply request value phase. At this point, the price is converted from a string to a float. If the user entered "abc" for the price, the conversion to float would fail, and control would be redirect to the cdForm.jsp page for the end user to fix. The h:message associated with the price would display a conversion error message. If all the values could be converted and were present (if required to be present), you could advance to validation processing. Since this example application doesn't have validators associated with the components (I'll introduce this feature in the next article), you'll simply advance to the update model values phase.

In the update model values phase, the setter methods on the CD are invoked with the converted and validated values stored in the GUI components. The addCD() method is invoked in the invoke application phase. The addCD() method uses a business delegate (a store object) to perform this operation. The addCD method uses the store object to store the CD in the system. Since the addCD method returns success, the listing will be displayed next, as defined in faces-config.xm. The navigation rule defined in faces-config.xml is shown in Listing 7.


Listing 7. Navigation rule for the addCD successful outcome
<navigation-rule>
  <from-view-id>/cdForm.jsp</from-view-id>
  <navigation-case>
    <from-action>#{CDManagerBean.addCD}</from-action>
    <from-outcome>success</from-outcome>
    <to-view-id>/listing.jsp</to-view-id>
  </navigation-case>
  ...
</navigation-rule>


Use case 2: Edit a CD

The second use case for the example application also starts at the listing page (listing.jsp). In addition to showing you how to edit data on a JSF page, this use case will introduce you to the JSF dataTable component.

The listing page uses a dataTable to display a list of CDs. The dataTable's value is bound to the cds property of the controller class, StoreController. The cds property is defined as shown in Listing 8.


Listing 8. cds property defined in StoreController.java
[StoreController.java]
/** List of cds for CD listing. */
private DataModel cdModel = new ListDataModel();
{
    cdModel.setWrappedData(store.findTitleAsc());
 }
/**
 * List of CDs in the system.
 *
 * @return Returns the cds.
 */
public DataModel getCds() {
    return cdModel;
}

The cds property is based on a java.util.List returned from the store object StoreManagerDelegate, which is the application's business delegate. The cdModel wraps the list returned from the store in a DataModel. DataModel is the model for a dataTable.

The dataTable is defined as shown in Listing 9.


Listing 9. dataTable defined in listing.jsp
<f:view>
    <h:form>	
      <h:dataTable id="items" 
        value="#{CDManagerBean.cds}" 
        var="cd"
        rowClasses="oddRow, evenRow" 
        headerClass="tableHeader">

Notice that the value is bound to the controller's cds property. The rowClasses and headerClass attributes are used to specify CSS classes that will be used to define the look and feel of the dataTable. As mentioned, JSF relies heavily on CSS to define the look and feel of a GUI. If you don't know CSS (that is, you've been getting by with font tags and HTML tables), you may want to learn it before taking the JSF leap.

The column component

The Title, Artist, and Price fields are displayed with the column component, as shown in Listing 10 (only the Title field is shown).


Listing 10. Adding fields in the column component
<h:column>
    <f:facet name="header">
      ...
        <h:outputText value="Title"/>
    </f:facet>
      <h:commandLink action="#{CDManagerBean.editCD}">
        <h:outputText value="#{cd.title}"/>
      </h:commandLink>
</h:column>

The column component is a child component of the dataTable. The column component takes a single child component and a facet. A facet is a named subcomponent. A facet is not a child component. The column component has a facet called header that defines what is displayed in the header. commandLink is the child component of the column component for this example. commandLink displays the CD's title in a link that is bound to the action #{CDManagerBean.editCD}. The action attribute binds the commandLink to the editCD() method of the controller class, as shown in Listing 11.


Listing 11. Backing bean method for the editCD commandLink
[StoreController.java]
/**
 * Edit the CD. This get executed before the edit cdForm 
 * page gets loaded.
 *
 * @return outcome
 */
public String editCD() {
    this.cd = (CD) cdModel.getRowData();
    this.cd = (CD) store.getCDById(cd.getId());

    if ((cd.getCategory() != null) || !"".equals(cd.getCategory())) {
        this.subCategoryList.setRendered(true);

        this.subCategories = getSubcategoriesList(cd.getCategory());
    } else {
        this.subCategoryList.setRendered(false);
    }

    this.editMode = true;

    return "success";
}

The editCD() method

The editCD() method is invoked in the invoke application phase of the JSF lifecycle. The editCD() method prepares the controller to display the cdForm.jsp page in editing mode. It does this by looking up the current selected CD by invoking the cdModel.getRowData() method.

Note that the JSF DataModel allows you to work with data at higher level of abstraction than typical Web applications. You don't have to inspect the request parameters: You simply ask the DataModel (cdModel) which CD has been selected by invoking the cdModel.getRowData() method. This higher level of abstraction simplifies Web development considerably.

Once you have the current selected CD, you use the business delegate to load the latest copy of that CD (store.getCDById()). After loading the CD, store.getCDById() turns on the subCategory list (assuming the CD is associated with a category), then sets the editMode property to true. You'll recall that the editMode property is used by cdForm to display the Add or Update buttons. Last, the store.getCDById() method returns success. The important navigation rule shown in Listing 12 stipulates that returning success advances you to the cdForm.jsp, as shown below.


Listing 12. An important navigation rule
<navigation-rule>
  <from-view-id>/listing.jsp</from-view-id>
  <navigation-case>
    <from-action>#{CDManagerBean.editCD}</from-action>
    <from-outcome>success</from-outcome>
    <to-view-id>/cdForm.jsp</to-view-id>
  </navigation-case>
  <navigation-case>
    <from-action>#{CDManagerBean.addNew}</from-action>
    <from-outcome>success</from-outcome>
    <to-view-id>/cdForm.jsp</to-view-id>
  </navigation-case>
</navigation-rule>

The updateCD() method

The CD form loads and displays whatever the current value of the CD property's properties are set to. The end user edits the resulting form as needed and clicks the Update button when finished. The Update button is the only button that shows up when the user is in Edit mode, and it only shows up when editMode is true, as you see in Listing 13.


Listing 13. Update CD button
[cdForm.jsp]

<h:commandButton id="submitUpdate" 
  action="#{CDManagerBean.updateCD}" 
  value="Update CD" 
  rendered="#{CDManagerBean.editMode}"/>

The Update button is bound to the updateCD() method. Before the update method is invoked, JSF has to validate the fields from the GUI. The values are copied from the request parameters to the components' values (by the components themselves) in the apply request value phase. At this point, the price is converted from a string into a float. No validators are associated with the components, so if all the required values are present and can be converted, you can move on to the next phase of the lifecycle.

Updating the model values

In the update model values phase, the setter methods on the CD are invoked with the converted and validated values stored in the GUI components. The updateCD() method is invoked in the invoke application phase. The updateCD() method is shown in Listing 14.


Listing 14. updateCD() method
[StoreController.java]

/**
 * Update the CD loaded on the form.
 *
 * @return success
 */
public String updateCD() {
    store.updateCD(this.cd);
    this.editMode = false;

    return "success";
}

The updateCD() method delegates most of its responsibility to the business delegate. It sets the editMode to false, which is the default, and returns success. The success outcome redirects you back to the listing, where you can look at your newly edited CD based on the navigation rule shown in Listing 15.


Listing 15. A successful UpdateCD takes you to listing.jsp
[faces-config.xml]
<navigation-rule>
  <from-view-id>/cdForm.jsp</from-view-id>
  ...    
  <navigation-case>
    <from-action>#{CDManagerBean.updateCD}</from-action>
    <from-outcome>success</from-outcome>
    <to-view-id>/listing.jsp</to-view-id>
  </navigation-case>
</navigation-rule>


Use case 3: Sort CDs

The final use case I'll walk you through will show how to sort tables. This use case also starts at the CD listing page. The listing page allows CDs to be sorted by title and artist in ascending and descending order. In this example, I'll show you how to sort by title, leaving sorting by artist as a learning exercise.

The header for title sorts has links to sort methods on the controller. Listing 16 shows how the title's header is listed in listing.jsp.


Listing 16. Sorting commandLinks
[listing.jsp]
<h:column>
  <f:facet name="header">
     <h:panelGroup>
        <h:outputText value="Title"/>
          <f:verbatim>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[</f:verbatim>
              <h:commandLink styleClass="smallLink" 
                action="#{CDManagerBean.sortTitleAsc}">
                  <h:outputText id="ascTitle" value="asc"/>
              </h:commandLink>
                  <h:outputText value=","/>
              <h:commandLink styleClass="smallLink" 
                action="#{CDManagerBean.sortTitleDec}">
                   <h:outputText id="decTitle" value="dec"/>
              </h:commandLink>
          <f:verbatim>]</f:verbatim>
     </h:panelGroup> 
  </f:facet>
              <h:commandLink action="#{CDManagerBean.editCD}">
                 <h:outputText value="#{cd.title}"/>
              </h:commandLink> 
</h:column>

The panelGroup component

Notice in Listing 16 that the links are defined inside of the header facet for the title column. A facet only associates a single-named component; therefore, to place multiple-link components inside of the header facet, you need to use a panelGroup. A panelGroup (similar to a panelGrid) is a single component that contains a number of child components. The panelGroup contains two links, as shown in Listing 17.


Listing 17. panelGroup component links
[listing.jsp]
<h:commandLink styleClass="smallLink" 
  action="#{CDManagerBean.sortTitleAsc}">
    <h:outputText id="ascTitle" value="asc"/>
</h:commandLink>
...	
<h:commandLink styleClass="smallLink" 
  action="#{CDManagerBean.sortTitleDec}">
    <h:outputText id="decTitle" value="dec"/>
</h:commandLink>

The first link is bound to the controller method sortTitleAsc, and the second is bound to sortTitleDec. These methods are listed as shown in Listing 18.


Listing 18. panelGroup link methods
[StoreController.java ]
/**
 * Uses the store delegate to return
 * a sorted list of CDs by title (ascending).
 *
 * @return asc
 */
public String sortTitleAsc() {
    this.cdModel.setWrappedData(store.findTitleAsc());

    return "asc";
}

/**
 * Uses the store delegate to return
 * a sorted list of CDs by title (descending).
 *
 * @return dec
 */
public String sortTitleDec() {
    this.cdModel.setWrappedData(store.findTitleDec());

    return "dec";
}

Both of these methods rely on the business delegate to return a java.util.List sorted in the correct manner. Notice that the methods return the logical outcomes asc and dec. Neither of these outcomes has a mapping in the faces-config.xml file. Outcomes that do not have mappings cause the current view to be reloaded; thus, the listing.jsp would be reloaded when these methods were called, and the list would be redisplayed in the correct order.

The beauty of this approach is that it relies on the business delegate to do the sorting. The business delegate may in turn rely on a DAO object that in turn relies on a database query or an OR mapping query that sorts the CDs very efficiently. This is usually a much better approach than having "smart" GUI components that know how to sort random domain objects (CD is a domain object) because the sorting is often, strictly speaking, part of the model (that is, part of the domain object), not the view.

As mentioned, the code for sorting by title and sorting by artist is nearly the same. As a learning exercise, try writing the code for the fourth use case yourself, but this time, sort by artist rather than by title.


Immediate event handling

The final topic I'll cover is immediate event handling. Immediate event handling is useful in cases where you do not want (or need) to validate an entire page to process a user input. As you'll recall, the example application's cdForm.jsp page uses radio buttons to display a list of categories and subcategories. When a category is selected by the end user, the cdForm.jsp page uses JavaScript to post the form back so you can display a list of subcategories.

This is an example of immediate event handling, since the whole form is not validated before the event handler is invoked. Instead, the event handler for the category list populates the subcategories and forces JSF to skip to the render response phase. The event handler for components normally executes in the invoke application phase. Event handlers for immediate event components execute in the apply request values phase, which happens before the process validation phase of the rest of the components.

Listing 19 shows the category list on the cdForm.jsp page again.


Listing 19. Category list on cdForm.jsp
[cdForm.jsp]
<h:selectOneRadio id="category" 
  value="#{CDManagerBean.cd.category}"
  immediate="true"
  onclick="submit()"
  valueChangeListener="#{CDManagerBean.categorySelected}">
    <f:selectItems value="#{CDManagerBean.categories}"/>
</h:selectOneRadio>

The selectOneRadio category field is bound to the CD's category property (value="#{CDManagerBean.cd.category}"). Note that immediate event handling is turned on (immediate="true"). This setting means that the Category component's events will be handled (and converted and validated) in the apply request values phase, rather than the invoke application phase.

The JavaScript magic is in the line onclick="submit()" -- says that when the user makes a change, it should be immediately submitted to the Web application for processing.

The event handler method

The available categories that show up in the listing are determined by the f:selectItems tag's value (value="#{CDManagerBean.categories}"). The event handler for this component changing is the controller's categorySelected() method (valueChangeListener="#{CDManagerBean.categorySelected}"). The event handler is shown in Listing 20.


Listing 20. categorySelected event handler
[StoreController.java]
/**
 * Event Handler for a category getting selected.
 *
 * @param event event data
 */
public void categorySelected(ValueChangeEvent event) {
    subCategoryList.setRendered(true);

    String value = (String) event.getNewValue();

    if (value != null) {
        this.subCategories = this.getSubcategoriesList(value);
    }

    FacesContext context = FacesContext.getCurrentInstance();
    context.renderResponse();
}

The first thing the categorySelected() method does is allow the subCategoryList to render itself. The categorySelected() method then uses the selected category value to look up a list of subCategories. The subCategories property is bound to the values of the subcategoryList. Next, the event handler forces JSF to go to the render response phase by calling the renderResponse() method on the current FacesContext. Thus, the GUI (cdForm.jsp) will redisplay with the available subcategories for the current category displaying.

Binding a component to the controller

The subCategoryList component is bound from the GUI. Just like you can bind values to components, you can bind components into a controller. The subcategory is defined in the cdForm.jsp page, as shown in Listing 21.


Listing 21. Subcategory list defined in the cdForm.jsp page
[cdForm.jsp]
<h:selectOneListbox id="subcategory" 
  value="#{CDManagerBean.cd.subCategory}"
  binding="#{CDManagerBean.subCategoryList}">
    <f:selectItems value="#{CDManagerBean.subCategories}"/>
</h:selectOneListbox>

The binding attribute allows you to bind components from the GUI into the backing bean (controller). Thus, this above component is bound to CDManagerBean.subCategoryList, which is a property in your controller defined as shown in Listing 22.


Listing 22. subCategoryList property
[StoreController.java ]
/** GUI Component that represents 
   the Subcategory list on the CDForm. */
private UIInput subCategoryList;

{
    subCategoryList = new HtmlSelectOneListbox();
}

/**
 * Subcategory list component
 *
 * @param aSubCategoryList The subCategoryList to set.
 *
 * @uml.property name="subCategoryList"
 */
public void setSubCategoryList(UIInput aSubCategoryList) {
    this.subCategoryList = aSubCategoryList;
}

/**
 * Subcategory list component
 *
 * @return Returns the subCategoryList.
 *
 * @uml.property name="subCategoryList"
 */
public UIInput getSubCategoryList() {
    return subCategoryList;
}

Immediate event handling uses just a little bit of JavaScript magic (the onclick="submit()" command) and the convenience of the flexible JSF lifecycle to let you process input from a single component, rather than waiting for the entire page to be validated. In this example, I've shown how immediate processing of a Category component enables you to show subcategories without reloading the page.


Conclusion

This concludes the second article in the JSF series, where I've used a working example and three use cases to introduce you to the JSF request processing lifecycle and demonstrate some of the essential features of its component model. I've also shown you how JSF combines with Struts Tiles for a more uniform layout across JSF pages, how to work with the JSF DataModel, and how to combine JSF and JavaScript for immediate event handling.

Part 3 will pick up where I've left off, incorporating advanced features like conversion and validation. I'll show you how to create your own custom JSF validators and convertors, as well as how to use the built-in ones when the situation calls for it.



Downloads

DescriptionNameSizeDownload method
Source code without JAR filesjsf-example2NoJars.zip91.2 KB HTTP
Source code with JAR filesjsf-example2WithJars.zip6.26 MB HTTP

Information about download methods


Resources

About the author

Rick Hightower serves as chief technology officer for ArcMind Inc. He is co-author of the popular book Java Tools for Extreme Programming, about applying extreme programming to J2EE development, as well as co-author of Professional Struts. He worked on JSF QuickStart with Warner Onstine, and some of the material in this series is based on examples in that course. The discussion of JSF lifecycle is based on Warner's discussion of it in the ArcMind course, with some embellishments from Hightower. The lifecycle diagrams were created by Paul Tabor for the ArcMind JSF course; you will learn more about him when you read the third article in this series. Contact Hightower at rhightower@arc-mind.com.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=49003
ArticleTitle=JSF for nonbelievers: The JSF application lifecycle
publish-date=03012005
author1-email=rhightower@arc-mind.com
author1-email-cc=jaloi@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers