Web Tier to Go With Java EE 5: Summary of New Features in JavaServer Faces 1.2 Technology

   
By Jennifer Ball and Ed Burns, February 2006  

Articles Index

The first article of the "Web Tier to Go With Java EE 5" series summarizes new features in JavaServer Pages (JSP) 2.1 technology. As that article describes, the biggest contribution of JSP technology is better alignment with JavaServer Faces technology, which was accomplished by unifying the two expression languages (ELs). Alignment with the JSP framework is also one of the more important achievements of JavaServer Faces 1.2 technology, developed through JSR 252. In addition to these changes, JavaServer Faces technology contributes a host of other significant ease-of-use features. This article briefly describes the more substantial ones, which include the following:

The Preface section of the JavaServer Faces specification provides a complete list of new features.

Alignment With JSP Technology

At the center of the incompatibilities between the JSP and JavaServer Faces technologies was the difference between the page life cycles that they support. As the previous article explains, the JSP specification supports a single render-and-response life cycle during which the elements in the page are executed in the order they appear, and the page is rendered immediately. The JavaServer Faces technology life cycle, on the other hand is divided into several phases, during which a component tree is created, the components' data is processed, and the components are rendered to the page. Therefore, a JavaServer Faces page is not necessarily rendered immediately after it is executed. As a result, the use of JavaServer Faces components in JSP pages sometimes caused content to be rendered in the wrong order, component state to be lost, or other problems to occur.

The article summarizing new features in JSP 2.1 technology touched on some of these issues. This article gives you more detail on what has changed in JavaServer Faces technology to foster alignment between the two technologies:

  • First-class support of JSTL's forEach tag with JavaServer Faces components
  • Improvements in tree creation and content interweaving
  • Deprecation of the JavaServer Faces technology EL in favor of the unified EL

First-Class Support of JSTL's forEach Tag With JavaServerFaces Components

As described in the article describing new features in JSP technology, one benefit of unifying the EL in the entire Java EE web tier is that iterating tags such as JSTL's forEach tag can now be used with JavaServer Faces components in an intuitive way. For example, to render a simple table with input components, you could have the following code:

<table>
                  

<tr><th>Item Name</th> <th>Item Price</th> <th>Item Quantity</th></tr>
                  

<c:forEach var="item" items="#{shoppingCart.items}">
                  

  <tr>
                  

        <td><h:outputText value="#{item.name}" /></td>
                  

        <td><h:outputText value="#{item.price}" /></td>
                  

        <td><h:inputText value="#{item.quantity}" /></td>
                  

  </tr>
                  

</c:forEach>
                  

<h:commandButton value="update quantities" action="update" />
                  

</table>
                
 

Without the unified EL, this coordination would not be possible.

Improvements in Tree Creation and Content Interweaving

As documented by Hans Bergsten in his article about the use of JavaServer Faces technology with JSP pages, mixing JSP code with JavaServer Faces tags sometimes yielded unexpected results. For example, in the following code, the value of the JavaServer Faces output text component Hi. should be displayed before the JSP template text What's your name?

    <h:panelGroup>
                  

      <h:outputText value="Hi. "/>
                  

      What's your name?
                  

    </h:panelGroup>
                
 

However, these two lines are reversed in the code's output. What caused this problem? The JavaServer Faces implementation depended on the JSP rendering engine to render the component tree. Because JSP technology immediately executes and adds static text to the response, whereas the children of the panelGroup tag are not rendered until after the end-tag of panelGroup is reached, the text What's your name? would be rendered before the text Hi.

Problems such as this and others mentioned in Hans Bergsten's article have been fixed in JavaServer Faces 1.2 technology. The solution involved changing how the component tree is created and how various kinds of content are processed and rendered. The most important changes are the following:

  • The creation and rendering of the component tree is now split into two steps to prevent the JSP technology engine from rendering content prematurely.
  • The rendersChildren properties of all standard renderers are now set to true so that the body content of the associated components is not rendered separately from the components themselves.
  • The static content in the body of tags whose renderers have rendersChildren set to true is captured and stored in a transient UIOutput component and added to the tree.
  • State-management tasks have been moved from ViewTag to ViewHandler to prevent writeState from being called before the state is actually saved.

The upcoming article in the "Web Tier to Go With Java EE 5" series provides a more detailed discussion of the improvements in tree creation and content interweaving, which now make it possible to mix JavaServer Faces component tags with other JSP code.

Deprecation of the JavaServer Faces EL in Favor of the Unified EL

As the previous article in this series explains, the ELs of both the JSP and JavaServer Faces technologies are consolidated into the unified EL. This means that the JavaServer Faces EL is now deprecated. Those of you who had built JavaServer Faces applications prior to the introduction of the unified EL can be assured that your applications are completely backward-compatible.

However, in order to take advantage of the unified EL's features, you will need to change your custom components and custom tags. Migrating to the unified EL primarily involves changing ValueBinding to ValueExpression and changing MethodBinding to MethodExpression. These changes are fairly easy to make. Furthermore, the new way of doing things is also easier. For example, because all standard tag attributes are enabled to accept value expressions, your tag handler does not need to check whether an attribute is enabled to accept value expressions.

To get more details on migrating to the unified EL, please see the article " Unified Expression Language."

Ease-of-Use Improvements in Support for Custom Messages

The most-improved feature of JavaServer Faces 1.2 technology is the ability to add custom messages to a JavaServer Faces application. The improvements in this area include the following:

  • A new set of standard converter messages
  • New requiredMessage, converterMessage, and validatorMessage attributes for input components
  • A new label attribute for input components, allowing the name of the component to be included in an error message
  • A new resource-bundle element for registering resource bundles with an application

Set of Standard Converter Messages

Prior versions of JavaServer Faces technology included a set of standard error messages to accompany the standard validators. Version 1.2 also includes a set of messages for the standard converters. To see the entire list of messages, refer to section 2.5.2.4 of the specification.

New requiredMessage, converterMessage, and validatorMessage Attributes

In most cases, a standard error message meets your needs. When it does not, you can override it with your own custom messages by using the requiredMessage, converterMessage, or validatorMessage attributes of your input component.

This new feature allows you to override a message when you want to. For example, let's say you are using the length validator on the userid and password fields. You want to have one message that says Userid must be 9 characters and another that says Password must be 9 characters, but you want to use the same validator for each. With the validatorMessage attribute, you can set these separate messages on the appropriate components rather than associating one message with every instance of a particular validator.

These attributes accept literal values as well as value expressions, as do most JavaServer Faces tag attributes. Therefore, you can use a value expression to reference a message contained in a resource bundle, as this example shows:

     <h:inputText value="#{customer.userID}"
                  

              validatorMessage="#{customMessages.userIdMessage}" >
                  

             <f:validateLongRange minimum="9" maximum="9"/>
                  

     </h:inputText>
                
 

As you might have guessed, the value of an input component's requiredMessage attribute overrides the default message for the required validation failure. The value of an input component's converterMessage attribute overrides the default message of the converter registered on the input component. Likewise, the value of an input component's validatorMessage attribute overrides the default message of the validator registered on the input component.

Because of this feature, page authors can now provide error messages that are more tailored to the component using it. Thus, the user can more easily determine the source of the error.

A New label Attribute for Input Components

Another feature that helps users decipher error messages is the new label attribute for input components. Most standard error messages include substitution parameters that take the name of the component that produced the error. The value of an input component's label attribute is substituted at the start of the appropriate default message. For example, the following message is associated with the DATE_ID message identifier of DateTimeConverter:

    {2}: "{0}" could not be understood as a date.
 

Say that you have a DateTimeConverter instance registered on a text-field component, and you set the input component's label attribute to Birth Date. If the user enters older than the hills into the text field, the conversion will fail. When the page is rendered again, the user will see the following error message:

     Birth Date: "older than the hills" could not be understood as a date.
 

The label component accepts both literal and value expressions. So, as with most other JavaServer Faces tag attributes, you can use an expression to reference the name of the component from a resource bundle.

New resource-bundle Configuration Element

Prior to version 1.2 of JavaServer Faces technology, page authors used the loadBundle tag to load a resource bundle into a page in order to reference localized data from a page. Page authors can still load resource bundles into a page using this method in version 1.2.

A new, more efficient way of loading resource bundles involves registering a resource bundle with the entire application by using a resource-bundle element in the application's configuration file. The following resource-bundle element registers a ResourceBundle class named CustomMessages, which is in the resources package.

     <resource-bundle>
                  

         <var>customMessages</var>
                  

         <base-name>resources.CustomMessages</base-name>
                  

     </resource-bundle>
                
 

The var child element defines the name that page authors will use in expressions that reference the resource bundle, as shown here:

     <h:outputText value="#{customMessages.myText}" />
 

In this example, myText is the key that maps to the message in the resource bundle.

With the new resource-bundle element, you can load any number of resource bundles into the entire application. Not only does this new element eliminate the need to add a loadBundle tag to multiple pages, but it also has significant performance benefits because loading a resource bundle is an expensive operation.

Improved State-Saving Behavior

Version 1.2 of JavaServer Faces technology contains two major changes to the state-management facility. One change involves rectifying problems with application state becoming disoriented when an application uses multiple frames or windows. The other change is providing the option to secure state on the client.

The cause of the disoriented application state in multiframe or multiwindow applications was that these multiple logical views within the root view often would have duplicate IDs and would therefore confuse the state-management facility. Several changes to the state-management API in version 1.2 solve this problem.

First, each window or frame within a view now has a unique ID, which is a combination of the view root's ID and a random number that is saved into a hidden field in the form associated with the window or frame. The writeState method of ViewHandler has been modified to generate the unique ID and write it out to the client during the life cycle's render response phase. Additionally, the encodeEnd method UIForm has been modified to call writeState before writing out the markup for the closing tag of the form so that state for multiple forms can be saved.

Also during the life cycle's render response phase, the newly modified saveSerializedView method of StateManager uses the unique ID to store the serialized view in the session. For example, if the server crashes, the saved state can be replicated to another server. Therefore, the state-saving mechanism now supports high availability. Finally, the restoreView method of ViewHandler now uses the unique ID to identify the view to restore during the life cycle's restore view phase.

The other major improvement to state saving allows you to encrypt client-side state before including it in the rendered markup that is sent to the client. You can choose to encrypt client-side state by using the ClientStateSavingPassword environment entry, as shown here:

     <env-entry>
                  

             <env-entry-name>
                  

                     com.sun.faces.ClientStateSavingPassword
                  

             </env-entry-name>
                  

             <env-entry-value>somePassword</env-entry-value>
                  

             <env-entry-type>java.lang.String</env-entry-type>
                  

     </env-entry>
                
 

The password that you provide is used to generate keys and cyphers for encryption. If this environment entry is not present in your configuration file, no encryption will occur.

Ability to Turn Off Generation of Component Client IDs

JavaServer Faces technology uses an algorithm to generate client IDs for components included in a form. In prior versions, these components' client IDs looked like this:

     [form ID]:[clientID]
 

Page authors had the option of specifying a client ID for a form component and for any of the other components included in the form. If the page author did not specify a form's client ID or a component's client ID, the implementation would generate them automatically.

Earlier versions of JavaServer Faces technology did not specify this algorithm well enough for developers to understand how it worked. Furthermore, a custom component or renderer class had no easy way to determine whether the page author had set a component's client ID or the implementation had automatically generated it. Finally, an author of custom renderers might not be able to change the name of the form for one reason or another but might still need to reference its components with JavaScript technology.

This release of JavaServer Faces technology includes a more explicit explanation of the algorithm that generates the client ID. You can find it primarily in the API documentation for UIComponent . The algorithm has also changed with the addition of the prependId attribute on the UIForm component. Page authors can now change the value of this attribute from the default of true to false to indicate that the form ID should not be a prefix of the component ID. Table 1 shows the different possibilities for generated client IDs in the most common scenarios.

Table 1: Client ID Generation Scenarios
 
 
Scenario prependId==true prependID==false
Page author sets no client IDs.
_id0:_id1
_id1
Page author sets the form client ID only.
myForm:_id0
_id0
Page author sets the component client ID only.
_id0:myComponent
myComponent
Page author sets client IDs of both the form and the component.
myForm:myComponent
myComponent
 
New setPropertyActionListener Tag

In addition to the actionListener tag that allows you register a custom action listener onto a component, the core tag library now includes the setPropertyActionListener tag. You use this tag to register a special action listener onto the ActionSource instance associated with a component. When the component is activated, the listener will store the object referenced by the tag's value attribute into the object referenced by the tag's target attribute.

To illustrate this tag's usefulness, let's suppose you have a forEach tag that includes a commandButton tag and iterates over a list of books, as shown here:

     <c:forEach items="#{bookDBAO.books}" var="book" varStatus="stat">
                  

          <c:set var="book" scope="request" value="${book}"/>
                  

          ...
                  

          <h:commandButton id="add" action="#{catalog.add}"
                  

                 value="#{bundle.CartAdd}">    
                  

                 <f:setPropertyActionListener
                  

                        target="#{requestScope.book}"
                  

                        value="#{book}"/>
                  

          </h:commandButton>
                  

          <c:remove var="book" scope="request"/>
                  

     </c:forEach>
                
 

When the user clicks the button represented by the commandButton tag, the current book is added to the shopping cart, and the next page of the application displays.

If you are familiar with JSTL, you know that the var attribute of the forEach tag is always in page scope. However, the book data must be in request scope so that the page that displays after the user has clicked the button has access to the book data. Therefore, the setPropertyActionListener tag is used to set the current book object into request scope when the user activates the button.

In this case, the setPropertyActionListener tag's value attribute references the book object. The setPropertyActionListener tag's target attribute references the value expression requestScope.book, which is where the book object referenced by the attribute is stored when the user clicks the button associated with the commandButton component.

Conclusion

This article demonstrates that JavaServer Faces 1.2 technology offers plenty of valuable new features and includes solutions to many long-standing problems. We encourage you to give version 1.2 a try. If you have any questions or comments, please write or join us at the forum or in our public IRC chat room. In the meantime, watch for the next article in the series, which will describe resource injection on the web tier.

For More Information

Web Tier to Go With Java EE 5: Summary of New Features in JSP 2.1 Technology, Part 1 in the series
Web Tier to Go With Java EE 5: Summary of New Features in JSTL 1.2 Technology, Part 2 in the series
JavaServer Faces Technology
JSR 252: JavaServer Faces 1.2
JavaServer Pages Technology
Hans Bergsten's article on the incompatibilities between the JSP and JavaServer Faces technologies
Unified Expression Language
Java Forums -- JavaServer Faces Technology
Public IRC chat room: See Community heading

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.