ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Improving JSF by Dumping JSP Improving JSF by Dumping JSP

by Hans Bergsten, author of JavaServer Faces
06/09/2004

After a long wait and high expectations, JavaServer Faces (JSF) 1.0 was finally released on March 11, 2004. JSF introduces an event-driven component model for web application development, similar in spirit and function to the model used for standalone GUI applications for many years.

Much has already been written about JSF, and based on the high number of posts to Sun's JSF Developer Forum, many are already kicking its tires and use JSF for both prototypes and real applications. But as with any new specification, JSF 1.0 has some rough spots. In this article, I focus on one specific area of the JSF specification that I feel is riddled with problems: namely, the use of JavaServer Pages (JSP) for creating JSF views. I also discuss alternatives to JSP that you can develop today and that I hope will make it into a future version of the specification.

If you're not familiar JSF, you may want to read the sample chapters from my JavaServer Faces book before you read this article.

The Problems with JSP

Don't get me wrong: I like JSP and I like JSF. I wouldn't have spent so much time contributing to the specifications and writing books about these technologies if I didn't think they had value. It's the combination of these two technologies that I don't like, because they don't complement each other in a natural way.

JSP is good for mixing static content and dynamic content pulled from resources made available by other parts of the application; for instance, a servlet. I'm actually one of those who think it's okay to use JSP for things that purists say has no place in a JSP page at all, such as database access, if the application is so simple that doing it "the Right Way" costs more than it's worth. What's important to realize for this discussion, however, is that JSP's main mission in life is to generate a response to a request; a JSP page is processed in one pass from top to bottom, with JSP action elements processed in the order in which they appear in the page.

JSF, on the other hand, has a much more complex lifecycle. Somewhat simplified, JSF components are created, asked to process their input (if any), and then asked to render themselves. For JSF to work well, these three things must happen separately in a well-defined order, but when JSF is used with JSP, they don't. Instead, the component creation and rendering happens in parallel, causing all kinds of problems.

The fact that both JSP and JSF components add content to the response is another cause for a lot of grief. Unless you understand the difference between how these two technologies write to the response, you're in for a lot of surprises, such as content appearing out of order or not at all.

Finally, the main benefit of using JSP as templates for JSF views would be to make it easier for JSP developers to learn JSF. As it turns out, there are severe limitations on how JSF and non-JSF tag libraries can be mixed in a JSP page, and on top of that, developing a JSF application requires understanding the event-driven component model, which is likely an unfamiliar subject for most JSP developers.

Creating and Rendering Components in Parallel

Let's first look at one example that illustrates the issue with parallel component creation and rendering. Say you want to create a label for an input field. Your first attempt probably looks something like this:

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
  <h:form>

    <h:outputLabel for="name">
      <h:outputText value="Name:" />
    </h:outputLabel>

    <h:inputText id="name" />

    <h:commandButton value="Submit" />

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

The <h:outputLabel> action element identifies the component the label belongs to, through the for attribute, and renders an HTML <label> element with the client ID for that component. In this example the for attribute refers to an <h:inputText> component.

Related Reading

JavaServer Faces
By Hans Bergsten

If you run this example, you'll notice that no <label> element is rendered the first time you request the page, but if you submit the form (requesting the page a second time), a <label> element is rendered.

This strange behavior has to do with how the combination of JSF and JSP works. When JSF receives the first request for the page, the component tree for the view represented by the page doesn't exist. JSF creates a tree with just a UIViewRoot at the top and forwards the request to the JSP page to add the real components. The JSP container processes the page and invokes the JSF action tag handlers as they are encountered. A JSF tag handler looks for the JSF component it represents in the component tree. If it can't find the component, it creates it and adds it to the component tree. It then asks the component to render itself. This means that on the first request, the components are created and rendered in parallel. On subsequent requests, the component tree exists, so no new components are created; the tag handlers just ask the existing components to render themselves.

Given this behavior, it's easy to see why our example doesn't work as intended. On the first request, the <h:outputLabel> action creates its component and asks it to render itself. To do so, it needs to find the component identified by the for attribute, but this component doesn't exist because the action element that creates it appears after the <h:outputLabel> element and hasn't been invoked yet. Hence, the component created by <h:outputLabel> action can't render its <label> element. On the second request, all components exist, so the component represented by the <h:outputLabel> finds the component the label belongs to and happily renders the <label> element.

There are two workarounds for the specific problem illustrated by this example: move the <h:outputLabel> element after the element for the component it belongs to, or nest both elements with an element for a component that renders its children, such as <h:panelGroup>. But the point is that creating and rendering the components in parallel causes non-obvious problems.

JSP and JSF Both Writing to the Response

In a JSP page, we're used to specifying custom action input as the element body. For instance, I would intuitively expect this JSP page snippet to produce a link with the text "What about usability?":

<h:commandLink action="foo">
  What about usability?
</h:commandLink>

Instead it produces "What about usability?" followed by an empty <a> element. Because JSF components must function in a non-JSP environment, they can rely only on artifacts available in all environments. For instance, the JSF UICommand component combined with the Link renderer created by the <h:commandLink> action element uses its child components to render the link text rather than using the text from the <h:commandLink> element body. The reason the element body appears at all in the response is that the JSP container adds it, before the custom action tag handler generates the <a> element. To get the desired output, I must create a child component to render the link text; e.g., like this:

<h:commandLink action="foo">
  <h:outputText value="What about usability?"/>
</h:commandLink>

Let's look at another example. This snippet generates "Some text" followed by "Some more text":

<h:outputText value="Some text" />
Some more text

So far, so good, but let's see what happens if we include the same snippet within another JSF custom action element:

<h:panelGroup>
  <h:outputText value="Some text" />
  Some more text
</h:panelGroup>

Now the two texts are reversed: "Some more text" is followed by "Some text". The reason is that the JSP container adds the plain text to the response as soon as it encounters it, but the Panel component represented by the <h:panelGroup> custom action element is a component type that renders its children itself, and that doesn't happen until the custom action end tag is reached.

There are many other examples like this, and it's far from obvious what's going on unless you understand the nitty-gritty implementation details of both JSF and JSP. It's also hard to improve the situation; for instance, requiring JSF tag handlers to wrap body content in automatically created UIOutput components doesn't help in cases where the body contains both template text and JSF component custom actions, because the tag handlers can't tell whether a piece of template text appears before or after a component action.

Mixing JSF and Non-JSF Tag Libraries

To deliver on the promise of being a migration path to JSF for people with JSP experience, it seems reasonable to expect that any construct that's legal in a regular JSP page should also be legal in a page that contains actions from the JSF tag libraries. Unfortunately, this isn't the case. As an example, it seems natural that this page would create a JSF UIOutput component per item in the collection available through the books scoped variable:

<ul>
  <c:forEach items="${books}" var="b">
    <li><h:outputText value="#{b}" /></li>
  </c:forEach>
</ul>

The JSF specification (in section 9.2.8), however, explicitly forbids nesting JSF component actions inside of a non-JSF custom action that iterates over its body, such as the JSTL <c:forEach> action, and there's a good reason for this limitation. The <c:forEach> is evaluated by the JSP container (outside of the control of JSF) every time it processes the JSP page. The nested <h:outputText> action is therefore invoked once for each item in the collection, creating a new UIOutput component on each invocation the first time the page is processed. But what should happen on a subsequent request if the number of items is different than for the first request? The components for the old items would have to be replaced with components for the new items, but to do that, all components must have known component IDs. To satisfy this requirement, the <h:outputText> action's id attribute would need to accept an expression that evaluates to a new ID for each iteration, e.g.:

<ul>
  <c:forEach items="${books}" var="b" varStatus="s">
    <li><h:outputText id="id#{s.index}" value="#{b}" /></li>
  </c:forEach>
</ul>

Allowing the component ID to be set by an expression would open up a whole new can of worms, however. Besides, this example still wouldn't work, because JSF doesn't see the b and s page scope variables (the page scope is a JSP-specific concept and may not exist in other environments where JSF must work). Promoting the variables to request scope may seem like a solution, but JSF evaluates expressions both at rendering and when it processes the input for the post-back request, and at the time of the post-back, the request scope data used for the previous rendering phase is long gone. To make a long story short, there's no good way to solve this problem. You must use the JSF UIData component instead.

Other custom actions may be used together with JSF custom actions, but only with care. For instance, <c:if> and <c:choose> may contain JSF component custom actions, but only if the id attributes are set for the nested JSF component actions. Non-JSF custom actions within the body of a JSF component action must generally be wrapped in a <f:verbatim> action element. Dynamically including JSP pages containing JSF component actions requires the use of the <f:subview> and wrapping all included non-JSF content with <f:verbatim> elements. All in all, there's a whole set of new rules an experienced JSP developer needs to learn when using JSP to create JSF views.

A Better Idea

Clearly there are many issues related to using JSP with JSF, but fortunately, you don't have to use JSP to use JSF. Most of the JSF infrastructure can be replaced with custom classes, and the piece that handles view creation and rendering is called the ViewHandler. With a custom ViewHandler, you can create the view any way you like and have full control over when and how it's rendered.

In my JavaServer Faces book, I describe two custom implementations in detail. One uses plain Java classes to create the components, similar to how it's done in a Swing application. The second implementation uses an XML file to represent the component structure and a separate pure HTML file as a template, binding the JSF components in the XML file to the corresponding HTML elements in the template with the help of id attributes. The source code for both ViewHandler implementations is included as part of the book examples available at my web site. Note that they are intended only as starting points; both implementations require more work before they are usable for real applications.

Without going into the implementation details, let's take a closer look at how the second approach solves the problems discussed earlier. It's inspired by the Tapestry framework, but it doesn't have all of the bells and whistles in its current incarnation. Because it's similar to Tapestry, I use the hangman game example described in Chapter 2 of Howard M. Lewis Ship's Tapestry in Action (Manning) to illustrate how it can be used. You can download the complete JSF version of the hangman game from the Articles section of my web site if you like to look at the details and try it out.

The most interesting part of the hangman application is the Guess page, where the user guesses letters in the word. It contains four dynamic areas: the number of guesses left, a scaffold where a new body part is added for each incorrect guess, the letters guessed so far, and the letters available for new guesses. Figure 1 shows the Guess page after a few guesses.

Figure 1
Figure 1. JSF version of the hangman game

Portions of the HTML template for the Guess page looks like this:

<html>
  <head>
    <title>JSF Hangman</title>
    <link rel="stylesheet" type="text/css" href="css/hangman.css"/>
  </head>
  <body>
  <table>
    <tr>
      ...
      <td width="70" align="right">
        <img id="guessesLeft" height="36" src="images/Chalkboard_3x8.png" 
          width="36" border="0"/>
      </td>
      ...
    <tr>
      <td>
        <img id="scaffold" alt="[Scaffold]" src="images/scaffold.png" 
          border="0"/>
      </td>
    </tr>
  </table>
  <table>
    <tr valign="center">
      ...
      <td>
        <span id="letters">
          <img height="36" alt="_" src="images/Chalkboard_5x3.png" 
            width="36" border="0"/>
          <img height="36" alt="A" src="images/Chalkboard_1x1.png" 
            width="36" border="0"/>
          ...
        </span>
      </td>
    </tr>
    <tr>
      ...
      <td width="330">
        <form id="selectForm">
          <span id="selectForm:selections">
            <img height="36" alt="-" src="images/letter-spacer.png" 
              width="36" border="0"/>
            <a class="select-letter" href="#">
              <img height="36" alt="B" src="images/Chalkboard_1x2.png"
                width="36" border="0"/></a>
            ...
          </span>
        </form>
      </td>
    </tr>
  </table>
  </body>
</html>

Note that there are no special elements here -- just plain old HTML -- so you can preview this template directly in an HTML browser and work with it in any standard HTML authoring tool; no special IDE or runtime environment required. The only thing that's a bit out of the ordinary is that some of the HTML elements have id attributes. This is how the dynamic parts of the page are bound to JSF components.

The JSF component tree is defined in an XML document like this:

<view-specification>
  <component id="guessesLeft" type="javax.faces.Graphic" 
    value="#{guessesLeftImages[visit.game.incorrectGuessesLeft]}" />
  <component id="scaffold" type="javax.faces.Graphic" 
    value="#{scaffoldImages[visit.game.incorrectGuessesLeft]}" />
  <component id="letters" type="javax.faces.Data" 
    rendererType="com.mycompany.Bar"
    value="#{visit.letters}" var="letter">
    <component type="javax.faces.Column">
      <component type="javax.faces.Graphic" 
        value="#{letterImages[letter]}" height="36" width="36" border="0" />
    </component>
  </component>
  <component id="selectForm" type="javax.faces.Form">
    <component id="selections" type="javax.faces.Data" 
      rendererType="com.mycompany.Bar"
      value="#{visit.guesses}" var="guess">
      <component type="javax.faces.Column">
        <component id="l" type="javax.faces.Command" 
          rendererType="javax.faces.Link"
          styleClass="select-letter" action="#{guess.makeGuess}"
          rendered="#{guess.letter != '#'}">
          <component type="javax.faces.Graphic" 
            value="#{letterImages[guess.letter]}" height="36" width="36" 
            border="0" />
        </component>
        <component id="g" type="javax.faces.Graphic" 
          value="#{letterImages[guess.letter]}" height="36" width="36" 
          border="0" rendered="#{guess.letter == '#'}"/>
      </component>
    </component>
  </component>
</view-specification>

Each component is defined by a <component> element, sometimes with child components defined by nested elements. Note how the id attributes of most <component> elements match the id attributes of the HTML elements in the template file. The custom ViewHandler processes the XML file to create the component tree for the view in one pass. It then renders the response by processing the template, adding all content not bound to JSF components to the response as is. When it finds an element in the template with an id attribute matching the ID of a JSF component defined in the XML document, it asks the JSF component to generate itself in place of the HTML element.

All <component> elements must have a type attribute with a value that identifies a JSF component type name, and may optionally have other attributes, such as value and rendererType.

JSF EL expression attribute values bind the components to bean properties and methods, just as when you use the default JSP ViewHandler. For instance, the graphics component with the ID guessesLeft has a value attribute with an EL expression that gets the incorrectGuessesLeft property of a bean available as the game property of the a managed bean named visit, and uses it as an index into a list of image files configured as managed bean named guessesLeftImages:

<faces-config>
  <managed-bean>
    <managed-bean-name>visit</managed-bean-name>
    <managed-bean-class>hangman1.Visit</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>

  <managed-bean>
    <managed-bean-name>guessesLeftImages</managed-bean-name>
    <managed-bean-class>java.util.ArrayList</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
    <list-entries>
      <value>images/Chalkboard_1x7.png</value>
      <value>images/Chalkboard_1x8.png</value>
      <value>images/Chalkboard_2x7.png</value>
      <value>images/Chalkboard_2x8.png</value>
      <value>images/Chalkboard_3x7.png</value>
      <value>images/Chalkboard_3x8.png</value>
    </list-entries>
  </managed-bean>
</faces-config>

The visit managed bean is an instance of a slightly modified version of the Visit class from the Tapestry example, acting as an interface between the JSF components and the Game class. This class is exactly the same class as is in the Tapestry example, implementing the core application logic in an interface-independent way.

The JSF hangman game uses additional faces-config.xml declarations for the custom ViewHandler, navigation rules, and all the other images. For details, please download the example application and look at the source code and configuration files.

Even though the example here shows that JSF can be used in a manner similar to Tapestry, please note that I'm not making any claims that the current version of the custom ViewHandler is anywhere near Tapestry in terms of features; it barely scratches the surface. What I want you to note, however, is that with a custom ViewHandler, all of the issues described for the default JSP layer are resolved. The creation and rendering of components happen in two separate, distinct steps, so all components exist when the view is rendered; only JSF writes the response, eliminating the content reordering surprises; and only JSF artifacts are used, avoiding the issues related to the mixing of different component types.

Conclusion

I've tried to make a number of points in this article. First, be aware that the JSF JSP layer is flawed in many ways. Second, don't give up on JSF just because the JSP layer is flawed; using a custom ViewHandler resolves all of the issues, and at the core, JSF is a great technology for complex web application interfaces.

Most importantly, I'm trying to build support for an alternative to JSP for a future version of the JSF specification. The JSR for JSP 2.1 focuses on bridging the gap between JSF and JSP. While good things may come out of this (like alignment of the two ELs), I don't see JSP ever becoming a good template language for JSF; JSP has a completely different purpose, and trying to "fix it" for JSF would likely just make it more complicated and less useful for simple, dynamic content. Instead, I hope to see experimentation with custom ViewHandler implementations in the open source community (for instance, within the MyFaces project, and maybe even within the Tapestry project) as well as in the corporate world. I hope that the best ideas from these efforts will be incorporated into a future version of the JSF specification as an official alternative to JSP.

Hans Bergsten is the founder of Gefion Software and author of O'Reilly's JavaServer Pages, 3rd Edition.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.