Chapter 3. The Seam life cycle

This chapter covers

  • Using Seam to improve JSF
  • Navigating between JSF views
  • Mapping requests to page actions
  • Handling exceptions

There is a stark difference between hitting balls at the driving range and taking your shot out on a golf course. The driving range offers a nice, level surface that’s perfect for making square contact with the ball. The golf course surfaces are rarely so ideal. Surface variations include the tee box, the fairway, the rough, the sand trap, from behind a tree, in a creek, and—if you are my brother—on top of a warehouse. The point is, the real world is not as manageable as the practice area.

The JavaServer Faces (JSF) specification lives in the ideal world with driving ranges, where everything works by design. As long as your application doesn’t need to pass data across redirects, call EJB 3 session beans from a JSF page, execute actions on an initial request, or execute contextual navigation—to cite several problem cases—JSF appears to be a pro. The JSF component model and event-driven design conveniently mask the underlying HTTP communication between the browser and the server-side logic. Where JSF comes up short is in catering to nonconforming use cases. Unfortunately, the real world is full of nonconformity. To adapt JSF to these less-than-ideal situations, Seam taps into the extension points in the JSF life cycle, putting shape to a more sophisticated request-handling facility known as the Seam life cycle. Seam provides a front controller, advanced page navigation, support for RESTful URLs, and exception handling, which are so integrated with JSF that it’s hard to know where JSF ends and where Seam begins.

This chapter sorts out which aspects of JSF Seam keeps and which parts are tossed to the side. By the end of the chapter, you’ll have an understanding of the difference between an initial JSF request and a subsequent postback and how Seam weaves its enhancements into both styles of request to form the Seam life cycle. You’ll then be ready to learn about Seam components—those are beans for you Spring fans—which are used to control the user interface and respond to actions triggered from it.

 

Note

If you aren’t familiar with JSF, you may be concerned that you can’t use Seam without JSF experience. Seam doesn’t depend on JSF, but you aren’t going to appreciate Seam’s JSF enhancements, which is the focus of this chapter, without a basic understanding of how JSF works. After all, Seam was developed to provide integration between JSF and EJB 3, and happened to solve shortcomings in JSF along the way. If you aren’t familiar with JSF, or its problems, I recommend that you read through the JSF introduction provided in the front of this book before continuing. If you’re a quick learner, or have spent enough time in the Java enterprise landscape, you should pick up on JSF in no time. Given that Seam extends beyond the user interface, you can boldly skip this chapter and advance to learning about Seam components and contexts in chapter 4.

 

Since this chapter focuses on the Seam life cycle, let’s begin by looking at how Seam registers itself to participate in both JSF and basic servlet requests.

3.1. Exploring how Seam participates in a request

For us to use Seam in an application server environment, it must be hooked into the life cycle of the servlet container. When the application starts, the servlet container bootstraps Seam, at which time Seam loads its contextual container, scans for components, and begins serving out component instances. Once running, the servlet container also notifies Seam when HTTP sessions are opened and closed. Seam also enrolls itself in servlet requests by registering a servlet filter, a servlet, and a JSF phase listener. It is through these servlet and JSF phase events that Seam manages its container and enhances the default JSF life cycle.

Before getting knee-deep into configurations, I want to provide context to the phrase life cycle, as it’s being thrown around quite casually. I’ve referred to a servlet context life cycle, a request life cycle, a JSF life cycle, and a Seam life cycle. Let’s sort them out.

The servlet context life cycle represents the entire lifespan of the web application. It is used to bootstrap services, such as the Seam container. The request life cycle, on the other hand, is the overarching life cycle for a single request. It envelops the JSF and Seam life cycles. It lasts from the time the browser requests a URL handled by the application to the time the server finishes sending the request to the browser. The JSF life cycle is fairly limited in scope. It’s confined to the service() method of the JSF servlet and doesn’t concern itself with non-JSF requests. The Seam life cycle is broader. On the one hand, it works alongside the JSF life cycle, weaving in extra services at strategic extension points. On the other hand, it extends beyond the JSF life cycle, both vertically, capturing events that occur outside the scope of the JSF servlet, and horizontally, by participating in non-JSF requests. You can think of the Seam life cycle as an evolution of the JSF life cycle.

In this section, you learn how to register Seam to participate in servlet requests. The configurations covered here are simply a review of what seam-gen has already prepared for you. However, if you’re starting an application from scratch without seam-gen, you’ll have to perform these steps in order to use Seam. Let’s begin by learning how to “turn on” Seam.

3.1.1. Flipping Seam’s switch

A servlet life cycle listener is notified as soon as the application with which it is registered is initialized. Seam uses this life-cycle event to bootstrap itself. You register the SeamListener by adding the following XML stanza to the application’s web.xml descriptor, located in the WEB-INF directory:

  <listener>
    <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
  </listener>

As soon as Seam is called into action, it begins scanning the classpath for components. The component scanner places the definition for components that it locates into the Seam container. Any components marked as application-scoped startup components (i.e., annotated with both @Startup and @Scope (ScopeType.APPLICATION)) are automatically instantiated by Seam at this time. Startup components are ideal for performing “bootstrap” logic, such as updating the database or registering modules.

The SeamListener also captures notifications when new HTTP sessions are started, at which time it instantiates startup components that reside in the session scope (i.e., annotated with both @Startup and @Scope(ScopeType.SESSION)). All other components are instantiated on demand during the processing of an HTTP request. You’ll learn all about components and how Seam locates, starts, and manages them in the next chapter.

Once Seam is running, it’s ready to lend a hand with incoming requests. A majority of that work is done in the JSF servlet, so let’s see how Seam ties in with JSF.

3.1.2. The JSF servlet, the workhorse of Seam

Given that Seam is so deeply invested in JSF (though not tied to JSF), it should come as no surprise to you that the main servlet in a Seam application is the JSF servlet. This servlet could easily be named the Seam servlet because of how much Seam-related activity occurs within it. If you’re using JSF in your project, or you started with seam-gen, then your web.xml descriptor already has the necessary servlet configuration. If not, add the following two XML stanzas to your application’s web.xml descriptor to enable the JSF servlet:

  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.seam</url-pattern>
  </servlet-mapping>

Notice that the mapping pattern is defined as *.seam rather than the default for JSF requests, *.jsf. Applications created by seam-gen are configured to this Seam-branded extension for the JSF servlet mapping. You are free to use the extension of your choosing. The change to the servlet pattern is, for the most part, cosmetic. However, the choice of which view technology to use with JSF is far more significant.

A commitment to Facelets

There is an important change that you should consider making to your JSF technology stack if you haven’t done so already. Seam developers strongly recommend using Facelets as the JSF view handler in place of JavaServer Pages (JSP). JSF and JSP have an inherant mismatch that causes a great deal of pain for the developer. The purpose of JSP is to produce dynamic output, while JSF component tags are intended to produce a UI component model capable of rendering itself. These vastly different goals clash at runtime.

Facelets is a lightweight, XML-based view technology that parses valid XML documents with the sole intent of producing the JSF UI component tree. It provides component tags that are translated natively into UI components and dually wraps non-JSF markup, including inline EL, into JSF text components (meaning you no longer need <f:verbatim>[1] for outputting HTML or <h:outputText> for outputting a value expression). As a result, the need for the JSP tag layer, as well as the entire overhead of JSP compilation, is eliminated.

1 This tag is necessary in JSP to wrap plain HTML markup as a JSF UI component or else it is skipped.

Facelets accommodates the same familiar XML-based tags as JSP, making its adoption very easy, but it purges the problems that seek to complicate JSP, such as its pseudo, non-validating XML syntax and the permitted use of Java scriptlets. Originally, Facelets was attractive because it delivered JSF 1.2 features before the JSF 1.2 implementations were ready and capable of being run on servlet containers such as Tomcat. The value of Facelets extends beyond its early utility because it removes the coupling between JSF and JSP and, more importantly, the variance of JSP versions across containers.

Facelets is more than just a view parser. It offers an extensible templating system akin to Struts Tiles. You create templates, known in Facelets as compositions, to define page layouts. A page inherits the template’s layout by extending it and contributing unique content to specially marked regions. Compositions can also serve as reusable page fragments. In fact, a composition can act as a UI component itself.

Using this feature, you can build new JSF components without having to write a line of Java.

To use Facelets, you have to register the Facelets view handler in the faces-config.xml descriptor, which is located in the WEB-INF directory:

  <faces-config>
    <application>
        <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
    </application>
   </faces-config>

Next, you need to get JSF to look for Facelets templates rather than JSPs, the default.

 

Using Facelets with Ajax4jsf/RichFaces

At one time the Facelets view handler had to be registered using a web.xml context parameter, org.ajax4jsf.VIEW_HANDLERS, when Facelets was used in combination with Ajax4jsf/RichFaces. This requirement is no longer necessary. You only need this context parameter if you’re using more than one view handler and you want to set the order in which they are called. Otherwise, you can simply register the Facelets view handler in the faces-config.xml descriptor.

 

Examining the project tree created by seam-gen, you should recognize an abundance of files ending in .xhtml in the view directory. The .xhtml extension is the default suffix for Facelets view templates. However, the default behavior of JSF is to map the incoming request for a JSF view identifier, or view ID for short, to a JSP file with the file extension .jsp. To get JSF to look for a Facelets template instead, you must register the .xhtml extension as the default suffix for JSF views in the web.xml descriptor using a servlet context parameter:

  <context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.xhtml</param-value>
  </context-param>

Figure 3.1 illustrates how an incoming JSF request is processed and translated into a UI component tree. The JSF servlet mapping extension (e.g., .seam) tells the servlet container to direct the request to the JSF servlet, FacesServlet. The servlet mapping extension is stripped and replaced with the javax.faces.DEFAULT_SUFFIX value to build the view ID. The JSF servlet then hands the view ID to the registered view handler, FaceletViewHandler. Facelets uses the view ID to locate the template. It then parses the document and builds the UI component tree.

Figure 3.1. Translation from servlet path to UI component tree, which is built by Facelets

 

Note

One of the pitfalls of JSF is that the file extension of the view template is hard-coded as part of the view ID. The view ID not only determines what template is to be processed, but is also used to match against navigation rules. Therefore, a change to javax.faces.DEFAULT_SUFFIX affects all places where the view ID is referenced.

 

Seam goes beyond just swapping in the Facelets view handler—it leverages Facelets compositions to keep the JSF views DRY (Don’t Repeat Yourself).

Facelets compositions

JSF is clumsy when it comes to including dynamic markup in a page, something Facelets addresses as a primary feature. Facelets is founded on the idea of compositions. A composition is a branch of a UI component tree, defined using the <ui:composition> tag. Unlike JSF subviews, a composition fuses the branch into the component tree without leaving a trace of itself. A composition tag also has templating abilities, which means that it can accept markup as a parameter and incorporate that markup into the fused branch.

Seam’s UI component library (see the accompanying sidebar) includes the tag <s:decorate> that extends the functionality of <ui:composition>, adding to it predefined template facets and features that cater to the rendering of form input fields. Let’s consider an example of how the <s:decorate> tag helps minimize redundant markup in a form-based JSF view.

 

Seam’s UI component library for JSF

Seam bundles a UI component library for JSF (in the jboss-seam-ui.jar file). The component tags fall under the http://jboss.com/products/seam/taglib namespace and are usually written with the prefix “s”. The aim of this component set is to further extend JSF in areas where it is deficient, serving as controls rather than rich widgets. There are tags for creating RESTful command links and buttons, templating, custom validators and converters, and page fragment caching, to cite several examples. Note that several of these tags may only be used in conjunction with Facelets (not JSP).

 

As you’d expect, every form has fields and those fields must have labels. But to do it right, you also need to have a marker to indicate required fields (often represented as a “*”) and a place for an error message when validation fails. To round things off, you want to centralize the HTML used to lay out the label and input for each field so that the look is consistent and can be easily changed.Listing 3.1 shows typical markup that you need for each field. It’s certainly a lot of typing (or will lead to a lot of copy-paste).

Listing 3.1. A field in a JSF form using standard markup
  <div class="prop">
    <h:outputLabel for="name" styleClass="name">    
      Name: <span class="required">*</span>    
    </h:outputLabel>
    <span class="value">

       <h:inputText id="name" required="true"    
         value="#{courseHome.instance.name}">
         <f:validateLength minimum="3" maximum="40"/>    
       </h:inputText>
     </span>
     <span class="error">
       <h:message for="name" styleClass="errors"/>    
    </span>
  </div>

The main problem with this markup is not so much that it is verbose, but that there’s a lot of repetition. And this is just a single field! The identifier (id) of the field appears three times: at , , and . The required symbol has to be consistent with the required attribute on the field . There’s no easy way to add an error icon that’s rendered only if an error occurs on the field because JSF doesn’t make that flag available on a per-field basis. Each field must be validated explicitly using nested validation tags . Finally, the layout and associated CSS classes are hard-coded into each field, which makes them difficult to change or augment later on a page-wide or site-wide basis.

In contrast, you’ll find the form field declaration in listing 3.2 to be far more reasonable. This substitute markup uses <s:decorate> to push most of the aforementioned work to the Facelets composition template view/layout/edit.xhtml, shown in listing 3.3. Now, instead of laying out and formatting the field, the focus of the markup is on providing the template with what it needs to do this work. Every character typed is providing vital information with minimal repetitive elements. In addition, a change to the template is propagated to all fields.

Listing 3.2. A JSF form field decorated by the layout/edit.xhtml composition template

Listing 3.3. The layout/edit.xhtml composition template for input fields
  <ui:composition xmlns="http://www.w3.org/1999/xhtml"    
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:s="http://jboss.com/products/seam/taglib">

    <div class="prop">
      <s:label styleClass="name #{invalid ? 'errors' : ''}">
        <ui:insert name="label"/>      
        <s:span styleClass="required" rendered="#{required}">*</s:span>
      </s:label>
      <span class="value #{invalid ? 'errors' : ''}">
        <s:validateAll>    
          <ui:insert/>    
        </s:validateAll>
      </span>
      <span class="error">
        <h:graphicImage value="/img/error.gif"
          rendered="#{invalid}" styleClass="errors"/>
        <s:message styleClass="errors"/>
      </span>
    </div>

  </ui:composition>

Although not a feature provided by the template, the input field has been augmented to perform instant validation upon losing focus, instrumented by the Ajax4jsf <a:support> tag. But what about the <f:validateLength> tag? Its absence doesn’t mean that the validation requirement has been lifted. Instead, this common bit of functionality has been pushed into the input field template, shown in listing 3.3. There, the validations are applied to the input component automatically using another custom Seam UI component, <s:validateAll>, which enforces validation rules declared using Hibernate Validator annotations on the corresponding entity class property.

Although this template appears complex, it isolates all of that complexity into a single document. The root of the template is <ui:composition> , which indicates that the markup should be fused into the parent JSF tree. Tag libraries are declared as XML namespaces on the root element, similar to the XML-based JSP syntax. The composition accepts two insertions. The first is a named insertion for supplying a label , and the second is an unnamed insertion for supplying any number of input fields . The <s:decorate> tag sets two implicit variables, required and invalid, which indicate if the input field is required and whether it has an outstanding validation error, respectively.

You may notice that this template doesn’t use standard JSF component tags for the field label and error message. Instead, they are replaced with equivalent Seam component tags, <s:label> and <s:message>. The benefit of using the Seam tags is that they are automatically correlated with the adjacent input component, a feature of <s:decorate>.

The <s:validateAll> tag enveloping the unnamed insertion activates the Hibernate Validator for any input components it passes in. The Hibernate Validator can also be registered by nesting <s:validate> within the component tag. For the field in listing 3.2, the following annotation on the name property of the Course entity would ensure that the number of characters entered is greater than 3 but doesn’t exceed 40:

  @Length(min = 3, max = 40)
  public String getName() { return this.name; }

The Hibernate Validator validations are applied twice, once in the UI to provide the user feedback, thanks to the Hibernate Validator-JSF validator bridge registered by the <s:validateAll> component tag, and once before the entity is persisted to ensure no bad data ends up in the database. The model validations are applied alongside other validators registered with the input component.

seam-gen includes a similar template for displaying field values, view/layout/display.xhtml, and a master composition template, view/layout/template.xhtml, that provides the layout for each page. The master template accepts a single named insertion, body, which injects primary page content into the template. Any markup outside of the <ui:define> tag is ignored. This example page uses the master template:

  <ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    template="layout/template.xhtml">
    {this text is ignored}
    <ui:define name="body">
      main context goes here
    </ui:define>
    {this text is ignored}
  </ui:composition>

Facelets offers additional features that you may find helpful for defining your JSF views. One of the most enticing features is the ability to create JSF components purely using XHTML markup (no Java code). Given that the task of creating a JSF component in the standard way is so involved, this can save you a lot of time. It’s also a great way to prototype a JSF component before you commit to creating it. To learn more about what Facelets has to offer, consult the Facelets reference documentation.[2]

2https://facelets.dev.java.net/nonav/docs/dev/docbook.html

Most of the calls in a JSF application go through the JSF servlet. However, in some cases you need to send other types of resources to the browser that are not managed by the JSF life cycle. Seam uses a custom servlet to handle this task.

3.1.3. Serving collateral resources via the Seam resource servlet

The JSF specification doesn’t provide guidance on how to push supporting resources, such as images, Cascading Style Sheets (CSS), and JavaScript files, to the browser. The most common solution is to serve them from a custom JSF phase listener that traps requests matching designated path names. Rather than getting mixed up in the JSF life cycle, Seam uses a custom servlet to serve such resources, sidestepping the life cycle and thus avoiding the unnecessary overhead. Using a separate servlet is justifiable since the steps involved in serving a resource are inherently different from those of processing an application page, eliminating the need for a comprehensive life cycle.

To configure the resource servlet, place the following servlet stanzas above or below the JSF servlet configured earlier. The URL pattern for this servlet must be different than the pattern used for the JSF servlet:

  <servlet>
    <servlet-name>Seam Resource Servlet</servlet-name>
    <servlet-class>
      org.jboss.seam.servlet.SeamResourceServlet
    </servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Seam Resource Servlet</servlet-name>
    <url-pattern>/seam/resource/*</url-pattern>
  </servlet-mapping>

The SeamResourceServlet uses a chaining model to minimize the configuration you perform in the web.xml descriptor. Seam uses this servlet to

  • Serve JavaScript files for the Ajax Remoting library
  • Handle Ajax Remoting requests
  • Serve CAPTCHA images (visual-based challenges to circumvent bots)
  • Serve dynamic images
  • Integrate with Google Web Toolkit (GWT) (and other RPC view technologies)

Keep in mind that Seam operates just fine without this servlet, but these extra features listed won’t be available. Seam may use this servlet for other purposes in the future. If you have it installed, you won’t have to worry about changing your configuration to take advantage of new features that rely on it.

In addition to the resource servlet, which allows Seam to process non-JSF requests, Seam offers a servlet filter, which it uses to operate beyond the reach of both the JSF servlet and the custom resource servlet. Let’s see how the servlet filter is registered and what it can do for you.

3.1.4. Seam’s chain of servlet filters

Servlet filters wrap around the entire request, executing logic before and after the servlet handling the request. Seam uses a single filter to wrap the JSF servlet in order to trap scenarios that fall outside of the JSF life cycle—or that JSF fails to capture. But Seam’s filter isn’t limited to JSF requests. It canvases all requests, allowing non-JSF requests to access the Seam container as well. Seam can function without relying on filters, but the services it adds are worth the small effort of getting them installed.

The Seam filter must be positioned as the first filter in the web.xml descriptor. By not putting this filter first, you run the risk of some features not functioning properly. To register it, place the following two stanzas above all other filters in the web.xml descriptor:

  <filter>
    <filter-name>Seam Filter</filter-name>
    <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>Seam Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Although there’s only a single filter definition shown here, I’ve alluded to the existence of more than one filter. Seam uses a chaining model, trapping all requests and delegating to any filter registered with the Seam container. This delegation model[3] minimizes the configuration that you need in web.xml descriptor. Once the SeamFilter is installed, the remaining configuration of Seam-controlled filters occurs in the Seam component descriptor.

3 The article “Follow the Chain of Responsibility” (http://www.javaworld.com/javaworld/jw-08-2003/jw-0829-designpatterns.html) gives a nice explanation of the chain of responsibility pattern that is employed by the SeamFilter.

Seam’s built-in filters

Filters registered in the Seam component descriptor (e.g., /WEB-INF/components.xml) are managed by the master SeamFilter using a chain delegation model. Every filter supports two properties, url-pattern and disabled, to control which incoming requests are trapped. By default, Seam applies all of the filters in the chain to all requests captured by the filter. You can reduce the matched set of requests by providing an override pattern in the url-pattern attribute of the servlet configuration. It’s also possible to disable a filter outright by setting the disabled attribute to true. The component configuration syntax used to configure these filters is covered in section 5.3.3 of chapter 5.

The filters that are included with Seam at the time of writing are summarized in table 3.1 The table explains the purpose of each filter, lists the additional configuration properties, and indicates under what conditions they are installed.

Table 3.1. The built-in Seam filters

Component/Purpose

Additional configuration

Installed?

ExceptionFilter Handles exceptions generated in the JSF life cycle; performs transaction rollbacks. None yes
RedirectFilter Propagates conversations and page parameters across redirects for navigations defined in facesconfig.xml. None Yes
MultipartFilter Processes file uploads from the Seam upload UI component. create-temp-files Controls whether a temporary file is used instead of holding the file in memory max-request-size Aborts request if file is used being uploaded is larger than this limit (in bytes) Yes
LoggingFilter Binds the username of the authenticated user to the Log4j Mapped Diagnostic Context (MDC),[a] referenced using the literal pattern %X{username}. none Yes, if Log4j is on the classpath; uses the Seam identity component
CharacterEncodingFilter Sets the character encoding for submitted form data. encoding The output encoding (i.e., UTF-8) override-client Ignores client preference No
Ajax4jsfFilter Configures the Ajax4jsf filter that ships with the Ajax4jsf library. Eliminates the need to have to set up this filter individually in the web.xml descriptor. force-parser Applies XML syntax checker to all requests, not just Ajax ones enable-cache Caches generated resources Yes, if Ajax4jsf is on the classpath
ContextFilter Enables Seam container and contexts for non-JSF requests. Should not be applied to JSF requests as it causes duplicate logic to be performed, leading to undefined results. None No
AuthenticationFilter Provides HTTP Basic and Digest authentication. realm The authentication realm auth-type Basic or digest key Used as a salt for the digest nonce-validity-seconds Length of time the security token is valid, helping to prevent replay attacks No

a The MDC is a thread-bound map that allows third-party libraries to contribute to the log message. The MDC is described in this wiki page: http://wiki.apache.org/logging-log4j/NDCvsMDC.

These filters each offer specific features that contribute to enhancing the narrowly scoped JSF life cycle. For instance, the ExceptionFilter allows Seam to capture all exceptions that are thrown during request processing, something that servlets alone cannot encompass. I cover exception handling in Seam near the end of this chapter. As fine-grained as the JSF life cycle is, its scope is limited to the JSF servlet alone. The ContextFilter opens access to the Seam container and its context variables to non-JSF servlets, such as Struts, Spring MVC, and Direct Web Remoting (DWR). Although a majority of Seam’s work is done in the JSF servlet, these additional filters allow Seam to extend the boundaries of its life cycle above and beyond the reach of the JSF servlet.

That covers the configurations necessary to hook Seam into the servlet life cycle. But wait a minute; aren’t we missing the JSF phase listener configuration? After all, that’s how Seam is able to tap into the JSF life cycle.

3.1.5. The Seam phase listener

Considering that many of Seam’s enhancements to JSF are performed in a JSF phase listener, SeamPhaseListener, it would appear as if there’s one more configuration to put in place. But there isn’t—at least, it isn’t necessary. Seam leverages a design feature of JSF that allows for any faces-config.xml descriptor available on the classpath to be loaded automatically. In Seam 2.0, the Seam phase listener is declared in a faces-config.xml descriptor that’s included in the core Seam JAR file, jboss-seam.jar. Thus, the phase listener is available as soon as you include this JAR file in your application. The stanza that registers the Seam phase listener is as follows:

  <lifecycle>
    <phase-listener>
      org.jboss.seam.jsf.SeamPhaseListener
    </phase-listener>
  </lifecycle>

Although you aren’t required to add this declaration to your faces-config.xml descriptor, that doesn’t mean you can’t adjust how it operates. Configuration settings that affect this phase listener are adjusted in the Seam component descriptor (using <core:init>). You can control such things as transaction management, debug mode, and the JNDI pattern used to locate EJB components. I explain component configuration in Chapter 5.

If the Seam debug JAR file, jboss-seam-debug.jar, is included on the classpath, and Seam is running in debug mode, Seam registers an additional JSF phase listener, SeamDebugPhaseListener. The sole purpose of this phase listener is to trap requests for the servlet path /debug.seam (assuming the JSF servlet extension mapping .seam) and render a developer debug page. This debug page introspects various Seam contexts (conversation, session, application, business process) and lets you browse the objects stored in them. Information about the long-running conversations in the current session is displayed and conversations can be selected to reveal the objects stored in them. The debug page is also used to display the exception summary when the application faults.

That wraps up the configuration necessary to allow Seam to partake in requests. From here on, I’ll refer to the combination of the Seam servlet filter and the JSF life cycle, which Seam now has a hand in, as the Seam life cycle. Figure 3.2 illustrates the two paths that a request can take as it enters the Seam life cycle. The SeamFilter can also wrap additional servlets such as Struts, Spring MVC, or DWR, allowing you to tap into the Seam container from these third-party frameworks as needed.

Figure 3.2. Requests are preprocessed by the Seam filter, proceeding to the JSF servlet or the Seam resource servlet.

With the configuration of Seam out of the way, let’s take a step back and consider what the JSF life cycle is like without Seam. The goal of this exercise is to gain an appreciation for the assumptions made by the JSF specification and where those assumptions come up short. Contrasting the native JSF life cycle with the version enhanced by Seam helps you understand why Seam is relevant and clarifies when you should choose the Seam facilities over the JSF equivalents that they replace. I’ll start by reviewing the general principles of JSF and then walk you through the JSF life cycle.

3.2. The JSF life cycle sans Seam

It’s certainly possible to learn how to develop a JSF application while remaining naive of the fact that there’s an underlying life cycle that processes each request. Figure 3.3 shows the leap the JSF designers want you to make between the click of a command button (e.g., <h:commandButton>) and the invocation of an action method on a server-side component that’s registered with the command button using an EL method binding expression.

Figure 3.3. A rudimentary look at event-driven behavior in JSF. Method-binding expressions on command buttons trigger methods on server-side components—in this case a Seam component—when activated.

This event-driven relationship is one of the fundamental ways that JSF is supposed to make web development easy. The direct binding between the command button and the server-side component weeds out most, if not all, of the low-level details of the HTTP request that you would otherwise have to address, instead getting you right down to the business logic. There is no HttpServletRequest, HttpServletResponse, or ActionForm (for you Struts developers) to have to concern yourself with. It’s perfect... too perfect.

JSF developers often fall victim to the leaky abstraction.[4] When the use case fits, life is grand and you don’t need to know how the request is handled by JSF. You just know that your action method is executed when a certain button is clicked. However, when things get messy, as they often do in the real world in which our applications live, you need to know what’s going on inside. That means it’s time to hit the books and learn the phases of the JSF life cycle. Since this book focuses on Seam, we’re only looking at the life-cycle phases as a means to better understand what Seam does to improve on them. To study the JSF life cycle in greater depth, consult the JSF resources recommended in the introduction of this book (The JSF for Nonbelievers series published by IBM developerWorks, JavaServer Faces in Action [Manning, 2005], and Pro JSF and Ajax[Apress, 2006]).

4http://www.joelonsoftware.com/articles/LeakyAbstractions.html: According to Joel Spolsky, all nontrivial abstractions are, to some degree, leaky.

3.2.1. The JSF life-cycle phases

The JSF life cycle decomposes a single servlet request—typically sent over HTTP—into six distinct phases. Each phase focuses on one task in a progressive chain that ultimately results in sending a response back to the browser. By executing these steps incrementally, it gives frameworks, such as Seam, the ability to get intimately involved in the life cycle (in contrast to servlet filters, which only get the before and after picture). Each phase raises an event both before and after it executes. Classes that want to be notified of these phase transition events, perhaps to execute arbitrary logic or weave in additional services, are called phase listeners. Phase listeners must implement the PhaseListener interface and be registered with the JSF application, just like the SeamPhaseListener. The phase listener serves as the backbone of Seam’s life cycle.

The six phases of the JSF life cycle are shown in figure 3.4. Execution occurs in a clockwise manner. We have not yet activated the life cycle, which is why there are no arrows in this initial diagram. In the next two sections, you’ll discover the path that a request takes through this life cycle as we put it into motion.

Figure 3.4. The six phases of the JSF life cycle are executed in a clockwise manner.

The JSF life cycle phases perform their work on a component hierarchy. This tree of components is similar to the Document Object Model (DOM) that’s built for an HTML page (typically exposed through JavaScript). Each node of the component tree is responsible for an element in the rendered page. JSF uses this tree to keep track of events that are triggered from those components. Having an object representation of the rendered view makes it easy to apply partial page updates using Ajax (Ajax4jsf is one library that provides this feature).

JSF can handle two types of requests: an initial request and a postback. Let’s start by looking at how an initial request is processed.

3.2.2. The initial request

Every user interaction in a web application starts with an initial request for a URL. The source may be a bookmark, a link in an email or on another web page, or as a result of the user typing in the URL directly. However it occurs, there is no prior saved state. That means there are no actions and thus no form data to process. Initial requests to the JSF servlet use an abbreviated life cycle of only two phases, as shown in figure 3.5.

Figure 3.5. The life cycle phases used on an initial request for a JSF page

In the first phase, Restore View, the only activity that occurs is the creation of an empty component tree. The request then proceeds immediately to the Render Response phase, skipping most of the life cycle. It does not pass Go, it does not collect the proverbial $200.[5] An initial request isn’t designed to handle any events or process form data.[6]

5 This reference is to the game of Monopoly by Parker Brothers. When you get sent to Jail, you pass by the payday square on the board.

6 It’s possible to implement a phase listener to perform this work, but as you’ll see, Seam handles these tasks without any work on your part.

The main activity on an initial request happens in the Render Response phase. In this phase, the request URL is examined to determine the value of the view ID. Next, the template associated with this view ID is passed to the view handler, parsed, and converted into a UI component tree, which was illustrated in figure 3.1.

While the template is being read, two things happen. The component hierarchy is built and the response to the client is prepared by “encoding” each component. Encoding is a way of saying that the component spits out generated markup, typically XHTML, though JSF can accommodate any type of output. The generated response includes elements that are “bound” to server-side components. Input and output elements bind to properties on backing bean components, while links and buttons bind to methods on action bean components. A single component can serve in both roles. In the absence of Seam, components must be defined in the faces-config.xml descriptor as managed beans. When an event is triggered on the page, it launches JSF into a postback, which we’ll get to next.

Once the entire response has been rendered, the UI component tree is serialized and either stuffed into the response sent to the client or saved in the HTTP session under a unique key. The state of the UI component tree is stored so that on a subsequent postback, changes to the form input values can be applied to the properties bound to them and any events can be enqueued and subsequently invoked.

 

Server-side vs. client-side state saving in JSF

No technology platform would be complete without a vanilla versus chocolate debate. For JSF, that debate is whether to store the UI component tree on the server or on the client. Let’s consider the two options.

In server-side state saving, the UI component tree is stored in the user’s HTTP session. A token is sent along with the response and stored in a hidden form field. The token value is used to retrieve the component tree from the session on a postback. Server-side state saving is good for the client but bad for the server (because it increases the size of the HTTP session).

In client-side state saving, the UI component tree is serialized (using the standard Java serialization mechanism), compressed, encoded, and sent along with the response. The whole process is reversed on a postback to reinstate the component tree. Client-side state saving is bad for the client (because it increases the size of the exchanged data) but good for the server.

So which should you choose? In my opinion, the choice is clear. Never make your customer or your web server suffer. If you have an opportunity to reduce bandwidth usage, take it. The connection to the client is often unpredictable. While some customers may be able to take the large pages in stride, others may experience significant lag. There is an even more compelling reason to use server-side state saving. JSF-based Ajax requests must reinstate the component tree, so if you use client-side state saving, what was once a trickle of information going from the browser to the server on an Ajax request is now a massive exchange. Server-side state saving limits the extra overhead to the value of the token. The one benefit to client-side state saving is that it’s not affected by session expiration. However, if the session expires, there could be a deeper impact.

The state-saving method is set using a top-level context parameter named javax.faces.STATE_SAVING_METHOD in the web.xml descriptor. The web.xml descriptor installed by seam-gen doesn’t include this context parameter, so the setting falls back to the JSF default, which is server-side state saving.

     <context-param>
       <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
       <param-value>server</param-value>
     </context-param>

Each JSF implementation offers ways to tune the memory settings for state saving. seam-gen projects use Sun’s JSF implementation (code-named Mojarra), so consult the Mojarra FAQ[7] to learn about the available settings.

7http://wiki.glassfish.java.net/Wiki.jsp?page=JavaServerFacesRI

 

Before moving on to postback, let’s consider a couple of the assumptions made by this abbreviated life cycle. The initial request assumes that

  • No logic needs to happen before the response is generated
  • The user has permission to view this page
  • The page requested is an appropriate place to begin within the application flow

I’m sure you can think of a handful of situations from the applications that you have developed in which these assumptions don’t hold true. The initial request is the Achilles’ heel of JSF. You’ll soon discover that, thanks to Seam, there’s a better way.

As bad as JSF is at handling the initial request, it does a pretty good job of handling a postback. After all, that’s what JSF was primarily designed to do. Let’s check it out!

3.2.3. The postback

Unless a condition occurs that short-circuits the process, a postback exercises the full JSF life cycle, illustrated in figure 3.6. The ultimate goal of a postback is to invoke an action method during the Invoke Application phase, though various ancillary logic may accompany this primary activity. During a postback, a short-circuit may happen as the result of a validation or conversation error, an event designated as “immediate,” or a call to the renderResponse() method on the FacesContext. In the event of a short-circuit, control is passed to the Render Response phase to prepare the output to be sent to the browser. If a call is made to the responseComplete() method on the FacesContext at some point during the life cycle, even the Render Response phase is skipped.

Figure 3.6. During a postback, the full JSF life cycle is used unless short-circuited by an error.

The Restore View phase of a postback restores the component hierarchy from the state information stored in the client or server, rather than just creating an empty shell. In the Apply Request Values phase, each input component retrieves its value from the submitted form data and any events (such as a button click or a notification of a changed value) are queued. The next two phases deal with massaging the submitted values and, if all validations and conversions are successful, assigning the values to the properties on the object (or objects) to which the form inputs are bound (the Update Model Values phase).

The life cycle hands control back over to the application during the Invoke Application phase, which triggers the method bound to the action of the command component that initiated the postback. If any action listeners have been registered with the command component, they are executed first. However, only the action method affects navigation.

Following the execution of the action method, the navigation rules defined in faces-config.xml are consulted to decide where to go next. If the return value of the action method is null or the method return type is void, and there are no rules that match the EL signature of the method (the method-binding expression), then the same view is rendered again. If the return value of the action method is a non-null string value, or there is a rule that matches the method’s EL signature, then the rule dictates the next view to be rendered. The presence of the <redirect/> element in the rule indicates that a redirect should be issued prior to rendering the next view, rather than rendering the view immediately in the same request, which is the default. A redirect results in a new initial request. An example of a navigation rule is shown here:

  <navigation-rule>
    <from-view-id>/register.xhtml</from-view-id>
    <navigation-case>
      <from-action>#{registerAction.register}</from-action>
      <from-outcome>success</from-outcome>
      <to-view-id>/welcome.xhtml</to-view-id>
      <redirect/>
    </navigation-case>
  </navigation-rule>

That concludes your crash course in JSF. Let’s reflect on what you just learned and address several holes in the aforementioned life cycle. This discussion will lead us into Seam’s most targeted improvement to JSF: advanced page orchestration.

3.2.4. Shortcomings of the JSF life cycle

As I’ve mentioned a number of times in this chapter, JSF is well designed, but there’s no denying that it has some quirks. In this section I want to enumerate them so that it’s clear what problem Seam is attempting to solve. I am hard on JSF in this section, perhaps unnecessarily so, because I want to emphasize that Seam addresses the concerns people have with JSF so that the Seam/JSF combination is an attractive choice as a web framework. The weaknesses in JSF begin with the initial request. So, let’s start there.

Life before the first action

The two styles of request in JSF are very lopsided. On the one hand, you have an anemic initial request that hardly does more than serve the page. On the other, you have a robust and sophisticated postback that exercises the entire life cycle and triggers all sorts of activity. There are times when you need the services of a postback on an initial request.

Frameworks like Struts allow you to invoke an action as soon as a page is requested. JSF, in contrast, assumes that the first activity will come after a page has been rendered. Lack of a front controller makes it difficult to implement functionality such as RESTful URLs, security checks, and prerender navigation routing (unless you’re willing to place this logic in a phase listener or at the top of the view template). It also makes it tough for other frameworks to interact with a JSF application since JSF doesn’t expose a mechanism for invoking action methods from a regular link. You’ll see in the next section that Seam allows page actions, and navigation events that result from them, to occur on an initial request.

 

Note

Savvy JSF readers may point out that a custom PhaseListener can be used to execute code prior to the Render Response phase. However, doing so requires a lot of redundant work on your part to achieve what Seam gives you right out of the box. Not only do you have to instrument a lot of boilerplate code, you end up hard-coding the view IDs—easily the most irresolute component of the application—into your compiled Java code. Seam allows you to externalize these mappings in a configuration file.

 

The back-loaded design of JSF leads us into the next problem: the postback becomes the predominate means of navigation in JSF.

Everything is a Post

The critics of JSF often point to its reliance on POST requests (i.e., submitting a form) as its biggest downfall. On the surface, this may appear to be just a cosmetic problem, but in fact it is more severe. The browser is very boorish when dealing with POST requests. If users click the browser Refresh button after invoking a JSF action, the browser might prompt them to make a decision about whether to allow the form to be resubmitted. That might not be frightening to you and me, but it may cause customers a great deal of stress and paranoia. Consider the fact that the customer just submitted a large order and the browser is now asking them if they want to resubmit the form. If I were a paranoid customer, I’d just force-quit my browser at that point to prevent any damage from being done. How would I know that the developer was smart enough to check for a duplicate response (and that the QA team confirmed that the logic works)?

Here’s an example of a navigation rule, as defined in the faces-config.xml descriptor, that would direct users back to the course detail page once they click the save button on the course editor page:

  <navigation-rule>
    <from-view-id>/CourseEdit.xhtml</from-view-id>
    <navigation-case>
      <from-action>#{courseHome.update}</from-action>
      <to-view-id>/Course.xhtml</to-view-id>
    </navigation-case>
  </navigation-rule>

Submitting the editor form issues a POST request. When the browser comes to rest after rendering the Course.xhtml, the location bar will still end in /CourseEdit.seam, appearing as if it is behind by one page. This situation happens because JSF posts back to the same URL that rendered the form and then selects a different template to render. If this navigation rule were changed to perform a redirect instead of a render by adding a nested <redirect/> tag with the <navigation-case> element, the URL bar would reflect the new page. However, in the process, all of the request parameters and attributes would get dropped.

If keeping the state of the browser location bar in sync with the current page is a requirement, then JSF’s behavior puts the developer in a difficult place. One workaround is to make heavy use of the session, to avoid lost data, and perform a redirect on every navigation event, to keep the location bar updated and make bookmarking pages possible. However, using the session precariously is dangerous because it can lead to memory leaks, concurrency problems, multiwindow complications, and overeager state retention.

Rudimentary navigation rules

The other problem with the JSF life cycle is that the navigation model is rudimentary. Navigation rules defined in the faces-config.xml descriptor assume the use of a controller layer whose methods are capable of returning declarative navigation outcomes. The rules match against an originating view ID, the outcome of the action method (i.e., its return value), and the action method’s EL signature. The rule dictates the navigation event that should take place, but the rule itself has no access to the general context, such as the value of other scoped variables. You end up having to mix application logic with UI logic in your component. You find that many applications struggle with this model.

An overly complex life cycle

Some people consider the JSF life cycle to be overly complex. This issue I will actually defend in JSF’s favor. I don’t believe the problem is being accurately represented. The JSF life cycle is a good decomposition of the logical phases that occur in just about any web request, written in any programming language, and run on any platform. The problem is that the life cycle is missing some areas of coverage. The lack of an action-based front controller, like Struts, is a perfect example. As a result of these oversights, developers have been forced to use the framework in ways for which it wasn’t intended or to bolt on haphazard solutions that seek to fill these voids.[8] Having to constantly compensate for these problems is where the pretense of complexity manifests itself.

8 The On-Load module of the jsf-comp project (http://jsf-comp.sourceforge.net/components/onload/index.html) is a perfect example of a haphazard solution to JSF’s lack of a front controller.

The vast majority of JSF’s limitations come down to the fact that JSF fails to provide strong page-oriented support, coming up short on features such as page-level security, prerender actions, intelligent navigation, and RESTful URLs. Seam focuses heavily on strengthening these weak areas by adding advanced page controls to the JSF life cycle, remedying the shortcomings just mentioned and stretching JSF’s capabilities beyond these expectations. Let’s explore these page-oriented enhancements.

3.3. Seam’s page-oriented life-cycle additives

In this section, you discover the page orchestration that Seam weaves into the JSF life cycle, saving you from having to patch JSF with the missing page-related functionality yourself. This section introduces Seam’s page descriptor, pages.xml, which gives you a way to configure Seam’s page-oriented enhancements, namely, more advanced navigation and page actions. By the end of this section, you’ll have all but forgotten about faces-config.xml and the pain it may have caused you.

3.3.1. Advanced orchestration with pages.xml

For as much control as the JSF life cycle gives to Seam, the JSF descriptor, faces-config.xml, offers no support for extended elements. For that reason, Seam introduces a new configuration descriptor to support its advanced page orchestration.

Seam’s page descriptor offers a much wider range of navigation controls than what the faces-config.xml descriptor is capable of supporting. Describing the page descriptor as a navigation configuration, though, doesn’t do it justice. It’s really about the page and everything that happens around it—hence the term page orchestration. The page descriptor can be used to

  • Define contextual navigation rules
  • Generate messages and pass parameters on a redirect
  • Invoke actions before rendering a view
  • Enforce security restrictions and other prerequisites
  • Control conversation boundaries
  • Control page flow boundaries
  • Control business process and task boundaries
  • Map request parameters to EL value bindings
  • Bind context variables to EL value bindings and vice versa
  • Raise events
  • Handle exceptions

The default global page descriptor is /WEB-INF/pages.xml, though its location can be changed, as shown in section 5.3.3 of chapter 5. This descriptor is used to configure an unbounded set of pages, each represented by a <page> element, as well as a handful of non-page-specific configurations. The page-oriented configuration can also be divided into fine-grained configuration files. These individual files serve a single JSF page. They are named by replacing the suffix of the JSF view ID with .page.xml. For example, the fine-grained configuration file for Facility.xhtml is Facility.page.xml.

 

Warning

The same page cannot be configured in both the global page descriptor and the fine-grained descriptor. In fact, there can be only be a single page configuration per view ID.

 

In seam-gen projects, a fine-grained page descriptor accompanies each page that’s generated by the seam generate command. Given that Seam boasts about avoiding the use of XML, the abundance of page descriptor files in a seam-gen CRUD application may seem contradictory to this goal. The fine-grained configurations could have been crammed into one file using multiple <page> elements. Even then, you may wonder why you need XML at all. The reason is that seam-gen projects are designed to support RESTful behavior, which is best implemented through the use of page descriptors. It’s certainly possible to design a Seam application that works without these page-oriented features. What you’ll discover, though, is that the page descriptors give you the best control over the incoming request and are worth the XML you have to endure to get that control.

 

Making the switch to Seam’s navigation rules

Seam’s page descriptor is a stand-in replacement for the navigation rules defined in the faces-config.xml file. The main difference is that the <navigation-rule> node from faces-config.xml becomes <navigation> in the Seam page descriptor and the nested <navigation-case> nodes become <rule> nodes. The page descriptor supports additional navigation conditions that extend beyond what faces-config.xml offers. Seam also uses its own navigation handler that is capable of folding Seam-specific functionality into the execution of the navigation rule. For instance, it will append the conversation id to the redirect URL to ensure that the conversation propagates across a redirect.

 

Seam’s page descriptor offers a plethora of additional features beyond what the faces-config.xml descriptor has to offer. While the added palette of XML tags is important, the real benefit is its awareness of context, emphasized in the first bullet point. Context—the current state of the system—is a common thread in Seam. By leveraging context, navigation rules defined in Seam’s page descriptor are cognizant of the big picture. In other words, they are intelligent.

3.3.2. Intelligent navigation

Seam gives you an intelligent mechanism for orchestrating the transition between pages, more so than what is available with faces-config.xml. When defining navigation rules, you can take advantage of the following extra page descriptor controls:

  • Use an arbitrary value binding to determine the outcome of an action rather than using the return value of the action method
  • Make navigation cases conditional using a value-binding expression
  • Indicate how the conversation should be propagated through the transition
  • Control page flows and business processes through the transition
  • Add JSF messages before rendering or redirecting
  • Add parameters to a redirect
  • Raise an event at a transition

The rules defined in Seam’s page descriptor make decisions not just based on where the request is coming from, or what action was executed, but on what the objects in context—or scope—have to tell.

Negotiating where to go next

Let’s consider a hypothetical conversation that may occur between the navigation handler and the navigation rules when taking the user through a basic wizard for adding a new golf facility to the directory (if only code could speak):

  • Navigation handler: The user wants to register a new facility.
  • Navigation rule: Take the user to the /FacilityEdit.xhtml page.
  • Navigation handler: The #{facilityHome.persist} method was called from the /FacilityEdit.xhtml page and it returned an outcome of “persisted.”
  • Navigation rule: Does the user want to enter a course?
  • Context variable #{facilityHome.enterCourse}: Yes.
  • Navigation rule: Take the user to the /CourseEdit.xhtml page.
  • Navigation handler: The #{courseHome.persist} method was called from the /CourseEdit.xhtml page and it returned an outcome of “persisted.”
  • Navigation rule: Does the user want to enter a tee set?
  • Context variable #{courseHome.enterTeeSet}: No.
  • Navigation rule: Is there somewhere that we need to return the user?
  • Context variable #{courseFrom}: Facility.
  • Navigation rule: Take the user to the /Facility.xhtml page and display a message to the effect that the user has finished registering the facility.

The critical piece of this negotiation consists of the context variables. They are used to make the navigation rules conditional. You’ll learn about context variables in the next chapter. For now, you can attribute them to the request- and session-scoped attributes with which you are familiar, though they go well beyond the limits of these two scopes. Using context variables in conjunction with the extensive set of controls in the pages.xml descriptor gives you fine-grained control of page-specific handling and transitions between pages.

Putting words into action

Let’s attempt to translate some of the previous example into JSF navigation rules. Unfortunately, using rules defined in faces-config.xml, we can only make a decision based on the EL signature of the action method and the outcome of that method:

The trouble with this rule is that it can’t make a complex decision as to where to go next, such as whether to return to the Facility.xhtml or move on to the CourseEdit.xhtml page. It’s blind to the larger context. You could have the action method return finer-grained outcomes, but that forces it to be more specialized merely to accommodate navigation. These rules also require that action methods return string outcomes, making them less business-like (they are tied to the requirements of the framework).

Seam’s page descriptor uses a similar, yet abbreviated syntax for defining navigation rules than does the faces-config.xml descriptor. The <rule> node in Seam’s page descriptor, which is the equivalent of the <navigation-case> node from faces-config.xml, can draw on the larger context. In listing 3.4, the negotiation with the navigation handler presented earlier has been translated into page descriptor configuration. The value of the #{facilityHome.enterCourse} expression is consulted to determine the next page, assuming this value is captured by a checkbox in the facility editor. The user is also kept informed about why the redirect is occurring through the use of a JSF message.

Listing 3.4. Contextual navigation rule consulted after persisting a facility

During a redirect, Seam can add both request parameters and JSF messages. The courseFrom parameter is added explicitly to track how we arrived at the course editor. Seam adds additional request parameters based on page parameter configuration. One such parameter is facilityId, which is added to the redirect for the purpose of associating the facility just entered with the new course about to be entered. You’ll learn about page parameters in the next section. In the JSF message that’s added, you can see that it’s possible to use an EL value expression. In this case, the message includes the name of the facility, read from the component named facilityHome. The EL is commonly used to reference Seam components, which you’ll learn about in the next chapter.

A similar set of navigation rules is added for the /CourseEdit.xhtml page to continue the progression. The navigation rules decide whether to return the user to the course editor or to the facility detail page after saving a course according to the value of the #{courseFrom} context variable. Notice that EL notion is being used in the view-id attribute:

  <page view-id="/CourseEdit.xhtml">
    <navigation from-action="#{courseHome.persist}">
      <rule if-outcome="persisted" if="#{courseFrom != null}">
        <redirect view-id="/#{courseFrom}.xhtml">
          <message severity="INFO">
            The data entry for #{courseFrom} is complete.
           </message>
        </redirect>
      </rule>
      <rule if-outcome="persisted" if="#{courseFrom == null}">
        <redirect view-id="/Course.xhtml"/>
      </rule>
    </navigation>
  </page>

If you’re getting the sense that the navigation rules in this example could be better written as a page flow, you are right. In addition to declarative navigation rules demonstrated here, Seam supports stateful page flows. Page flows are tied closely with conversations. You’ll study both in Chapter 7. The purpose of this example is to show that you can consult EL value expressions to determine which navigation rule to apply. You might want to direct users to a special page if they entered a private golf facility versus a public facility. The actual use case is going to depend heavily on the requirements for your application.

Finding the outcome another way

Up to this point, you have relied on the action method to return a logical outcome value. There are two problems with this approach, depending on how you look at it. For rapid prototyping, this level of indirection is inconvenient since it forces you to a define navigation rule even if you don’t require the flexibility yet. To simplify matters, Seam lets you specify the target view ID in the return value of the action method. If the return value begins with a forward slash (/), Seam assumes it’s a valid view ID and immediately issues a redirect to the view ID:

  public String goToCourse() {
      return "/Course.xhtml";
  }

At the other extreme, using the action method return value as the navigation outcome imposes a requirement on business methods to assist with navigation decisions. The declarative return value likely won’t make sense in the context of the business logic. This coupling becomes especially noticeable when you start attaching EJBs to your JSF pages. EJB components are supposed to be business components. Using return values for the purpose of driving navigation is just wrong. A far better way is to expect the business object to maintain state that can be consulted by the navigation rule to determine the appropriate maneuver.

 

Catchall navigation rules in the page descriptor

Instead of matching against a specific outcome (action method return value), you can define a generic navigation rule to match against either a non-null or null outcome. A <rule> node without any attributes will match any non-null outcome (including a void return value). A null outcome is matched by placing either a <redirect> or <render> node as a direct child of the <navigation> node. In Seam, null is often considered an “exceptional” outcome, canceling the normal behavior, such as beginning a conversation.

 

Let’s ignore the return value of the persist() method, assuming that it doesn’t tell us anything particular about navigation. Instead, the entity state (persisted, deleted, updated) will be exposed via the property lastStateChange. The evaluate attribute on the <navigation> element, which is an EL value expression, is consulted to obtain an outcome value rather than the return value of the action method. The resolved expression is matched against the if-outcome attribute on the <rule> nodes to select the navigation to follow:

  <page view-id="/FacilityEdit.xhtml">
    <navigation from-action="#{facilityHome.persist}"
      evaluate="#{facilityHome.lastStateChange}">
      <rule if-outcome="persisted" if="#{facilityHome.enterCourse}">
        ...
      </rule>
      <rule if-outcome="persisted" if="#{!facilityHome.enterCourse}">
        ...
      </rule>
    </navigation>
  </page>

In simple terms, the pages.xml steps the navigation capabilities of JSF up a notch. Before we get into the other features of the page descriptor, I want to briefly mention two UI components that Seam introduces that complement the page-oriented controls.

3.3.3. Seam UI command components

I mentioned earlier that one of the main criticisms of JSF is that “everything is a POST.” This means that any link or button slated to execute an action method when activated does so by submitting a POST request (i.e., a form post). While this design is suitable for accepting form data, it’s not so ideal for creating bookmarkable links. Seam offers two UI command components, one for creating links, <s:link>, and one for creating buttons, <s:button>, that stand in for the corresponding command components, <h:commandLink> and <h:commandButton>, from the standard JSF component set. The Seam UI command components can perform all the same functions as the standard command components, with one exception: they can’t submit form data. But then again, if you’re submitting form data, you likely aren’t concerned with the fact that a POST request is being issued; in fact, that’s what you want.

You’re going to see <s:link> and <s:button> used a lot in this book. Of the two, <s:link> is probably the most attractive because it allows a user to right-click and open the link in a new tab or window, something that isn’t possible with JSF command links. In addition to being able to execute an action method, the Seam UI command components can navigate directly to a specific view ID, eliminating the need for a navigation rule:

  <s:link view="/CourseList.xhtml" value="Course List"/>

The value of the view attribute can either use the servlet extension (.seam) or the view ID suffix (.xhtml) to reference the view ID (the real secret is that the extension doesn’t matter at all). What <s:link> has over <h:outputLink> in this case is that Seam will prepare page parameters associated with the target view ID as part of the URL, which you’ll learn about next. As you move to the next section, pay attention to how Seam frees JSF from the grips of postbacks and allows it to behave more like an action-based framework.

3.3.4. Page parameters

In the native JSF life cycle, value-binding expressions are only passed to the underlying model during the Update Model Values phase on a JSF postback. Seam brings this feature to initial requests by introducing a feature known as page parameters.

Page parameters are a truly unique feature in Seam. They’re used to bind request parameters to model properties through the use of value expressions. The request parameter can either be form POST data or a query-string parameter. The “model” can be any Seam component (or JSF managed bean), whether it be a presentation model or a business domain model. Again, Seam doesn’t force your hand. When a request for a given JSF view is received, as identified by its view ID, each page parameter associated with that view ID is evaluated upon entering the page—just prior to the Render Response phase. That value is then assigned to the model property using its JavaBean setter method as mapped by the value expression.

Let’s consider the course detail page, Course.xhtml, from the Open 18 directory application generated in the previous chapter. Assume there’s an incoming request for the Course entity with an identifier of 1:

  http://localhost:8080/open18/Course.seam?courseId=1

The component responsible for providing data for the course page is named courseHome. (A component is the Seam equivalent of a JSF managed bean.) Prior to the rendering of the Course.xhtml page, the value of the courseId query string parameter must be assigned to the courseId property on the courseHome component. That assignment occurs as a result of the following page parameter assignment in pages.xml:

  <page view-id="/Course.xhtml">
    <param name="courseId" value="#{courseHome.courseId}"/>
  </page>

The name attribute specifies the name of the request parameter and the value attribute specifies the value expression to which the value of the request parameter gets bound. The courseHome component then retrieves the instance from the database to be rendered. Alternatively, you could specify this mapping in the fine-grained configuration file, Course.page.xml, which sits adjacent to the Course.xhtml view template. The fine-grained configuration file is intended to serve only a single view ID. Therefore, the view-id attribute can be excluded in the declaration:

  <page>
    <param name="courseId" value="#{courseHome.courseId}"/>
  </page>

For the remainder of the chapter, I’ll always include the view-id attribute for clarity.

The <page> node is used to designate which pages the configurations apply to. In a global page descriptor, the view-id attribute can either be an exact match or it can match multiple view IDs by using a wildcard character (*).

 

Home and Query components

Throughout this chapter, you have seen a lot of references to components that end in either Home (e.g., courseHome) or List (e.g., facilityList). Components ending in Home extend from the EntityHome class and components ending in List extend from the EntityQuery class, both of which are part of the Seam Application Framework. The EntityHome class is used for managing the persistent state of a single entity instance, while the EntityQuery component manages a JPQL query result set. Chapter 10 provides comprehensive coverage of the Seam Application Framework and explains how to take advantage of these two components.

 

Page parameters aren’t limited to accepting values—they are bidirectional. In addition to taking request parameters, they’re used to rewrite links by reading the value of the mapped value bindings and appending name-value pairs to the query string. In this way, page parameters automatically take care of decomposing server-side objects into string values, passing them along with the request, and then reconstructing the objects on the other side by mapping the parameters to value binding expressions. For instance, the course editor page includes a link to cancel and return to the course detail page, <s:link view="/CourseList.xhtml" value="Cancel"/>. The courseId parameter is automatically appended to the page by reversing the page parameter declaration shown earlier:

  /Course.seam?courseId=1

This rewriting happens in the following cases:

  • The URL generated by Seam command components (<s:link> and <s:button>)
  • JSF postbacks from UICommand components (i.e., <h:commandLink>)
  • Navigation redirects defined in the page descriptor (pages.xml or *.page.xml)

For links and redirects, the parameters that are applied to the URL are read from the configuration for the target view ID. JSF forms post back to the same page, so the target view ID is the same as the page that rendered the form. It’s a bit trickier with <s:link> and <s:button> since the target page can be different than the current page. For example, consider the following link:

  <s:link view="/Course.xhtml" value="View course"/>

The page parameters will be read from the Course.page.xml page descriptor, even if this link is included on the CourseList.xhtml page.

Let’s explore how the page parameters and the Seam UI component exchange request parameters.

The search form paradox

When would you want to use page parameters to pass on values? Consider the paradox of providing both search capabilities and sorting for a data set. I can almost guarantee you have been in this seat before. When the user searches, you need to retain the sort and pagination, and when the user sorts or paginates, you have to retain the search. This leads to heavy use of hidden form elements within a form that wraps the entire page or a liberal use of JavaScript to move values between forms. One way or another, it becomes a tangled mess and leads to many headaches.

Page parameters in Seam make this situation trivial. Consider the golf course facility listing page in the same application. The facilityList component is the action class that manages the collection of courses. The page parameters are defined as follows:

  <page view-id="/FacilityList.xhtml">
    <param name="firstResult" value="#{facilityList.firstResult}"/>
    <param name="order" value="#{facilityList.order}"/>
    <param name="from"/>
    <param name="name" value="#{facilityList.facility.name}"/>
    <param name="type" value="#{facilityList.facility.type}"/>
    <param name="address" value="#{facilityList.facility.address}"/>
    <param name="city" value="#{facilityList.facility.city}"/>
    <param name="state" value="#{facilityList.facility.state}"/>
    <param name="zip" value="#{facilityList.facility.zip}"/>
  </page>

For any Seam command component on the page (<s:link> or <s:button>), the expressions are evaluated during page rendering and the resolved value and corresponding parameter name are combined and added to the query string of the link. If you searched for PUBLIC facilities and then sorted on the name of the facility, the URL would look like this:

  /FacilityList.seam?zip=&phone=&state=&type=PUBLIC&uri=&cid=25&country=&city=&order=name+asc&county=&address=&description=&name=

The sort link is built using the link component tag from the Seam UI component set (trimmed down for clarity):

  <s:link value="name">
    <f:param name="order"
      value="#{facilityList.order=='name asc' ? 'name desc' : 'name asc'}"/>
  </s:link>

Note that the <s:link> tag automatically targets the current view ID if one is not explicitly provided. Both the type and order request parameters are maintained in the URL generated by this link. The order clause is divided into property name and sort direction and both clauses are sanitized by the FacilityList component to protected against SQL query injection vulnerabilities. When you submit the search form, you don’t see these parameters in the browser’s location bar because they’re passed through the UI component tree instead. Since page parameters transcend forms—propagated because of their association with a given view ID—it doesn’t matter where the links that use them are located. When a search is executed, the sort order is maintained; when a sort is issued, the search parameters are maintained. All of this happens without any custom URL rewriting on your part. Another place page parameters are extremely valuable is on a navigation redirect.

Surviving redirects

As I pointed out earlier, JSF normally drops request-scoped data when issuing a redirect. Page parameters offer a way to retain these values across the redirect. When the redirect is prepared, the data mapped to the view ID using page parameters is automatically appended to the redirect URL. You’ll learn in chapter 7 that Seam automatically carries conversation-scoped data over a redirect as well, even in the absence of a long-running conversation.

Parameter peace of mind

By now you are probably getting excited about these page parameters. But here’s the real kicker: page parameters can also register converters and validators. That means you aren’t blindly stuffing request parameters into properties on your model. You get the peace of mind of the JSF conversion and validation process just as you would on a postback.

In JSF, validators and converters operate at the field level. A validator is a class that implements the javax.faces.validator.Validator interface and a converter is a class that implements the javax.faces.convert.Converter interface. Validators and converters can be defined as managed beans (or Seam components) or they can be registered under a lookup id in faces-config.xml. If defined as a managed bean, the class instance is referenced using a value expression. When the lookup id is used, JSF is responsible for instantiating the class.

Let’s assume that we need to perform some conversions and validations for our facility search to give the user a better chance of locating a facility without getting tripped up over errant symbols or confused when no results are found because of an invalid parameter value. In the following excerpt, the phone number parameter is converted to the storage format used in the database using a custom converter registered under the id org.open18.PhoneConverter. The value of the state parameter is checked using a custom validator registered under the id org.open18.StateValidator. (You declare validators and convertors in faces-config.xml or by adding @Validator and @Converter annotations to a Seam component, respectively.) The validator for the facility type is retrieved from a value expression, #{facilityTypeValidator}, which resolves to a JSF managed bean or Seam component implementing the javax.faces.Validator interface:

  <page view-id="/FacilityList.xhtml">
    <param name="phone" value="#{facilityList.facility.phone}"
      converterId="org.open18.PhoneConverter"/>
    <param name="state" value="#{facilityList.facility.state}"
      validatorId="org.open18.StateValidator"/>
    <param name="type" value="#{facilityList.facility.type}"
      validator="#{facilityTypeValidator}"/>
  </page>

What about model validations defined using Hibernate Validator? Good news. Seam enforces model validations on any property referenced by a page parameter as long as the parameter value is non-null. Speaking of null values, it’s possible to declare a page parameter as required. Though not the friendliest approach, such a feature does comes in handy for enforcing the presence of a request parameter. For instance, an error can be thrown if the user attempts to request for the facility detail page without the facilityId parameter:

  <page view-id="/Facility.xhtml">
    <param name="facilityId" value="#{facilityHome.facilityId}"
      required="true"/>
  </page>

The downside of adding the required flag is that Seam throws a ValidatorException when the parameter is missing or empty rather than directing the user to a proper page. There are other ways to handle this problem, which are explored later.

Page parameters essentially emulate a form submission on an initial request. But what makes them especially valuable is that they are also propagated transparently through a JSF postback, making them bidirectional.

From query string to page scope and back

Here’s something easy to overlook the first time you encounter page parameters: they don’t necessarily have to refer to a value-binding expression. When the value is left off the declaration, the request parameter is simply placed into the page scope under the same name. Valueless page parameters are useful when you just need to carry values around but don’t want to map them into a model object or use hidden form fields. You can sort of think of them as JSF hidden fields. For instance, you can track the page from where the user came using the following valueless page parameter:

  <page>
    <param name="returnTo"/>
  </page>

You can then make a decision based on this value when creating navigation buttons:

  <s:button value="Cancel"
    view="/#{empty returnTo ? 'FacilityList' : returnTo}.xhtml"/>

Please note that this example is conceptual. You probably want to filter the returnTo variable through a preprocessor to ensure that its value is legitimate given the context.

What about when you need to execute an action on an initial request, not just apply request parameters to the model? Executing code prior to rendering a page is the forte of Seam’s page actions.

3.3.5. Page actions: execute me first!

Page actions are what drew me to Seam and encouraged me to stick with JSF. In my mind, they are the saving grace of JSF. More times than not, information is retrieved by pulling up a URL in the browser, or following a link from another site, not from clicking a button in the application. However, the JSF specification focuses heavily on the latter use case. Seam adds the ability for JSF to accommodate RESTful URLs (i.e. “bookmarkable” links).

RESTful URLs

Without page actions, you have to think about the world in terms of form submissions. That is a stark contrast with the direction the world is actually taking, which is to rely on a REST architecture style—or the more pertinent term, RESTful URLs.[9] Once you have the power of page actions at your fingertips, any request can be made to perform prerender logic to retrieve and prepare data before the component tree of the next view is built and ultimately rendered. You may even decide to serve a different view than what was requested by the browser. In this case, there isn’t an automatic mapping between the URL that’s requested and the page template that’s to be rendered, like the default behavior of JSF.

9 Admittedly, I am using the term RESTful URL with great liberty in this section. I cannot claim that a GET request is enough to qualify it as a RESTful URL. However, the point here is that prerender page actions are a prerequisite to implementing a complete REST solution.

 

What is a RESTful URL?

A RESTful URL is one that permanently represents a resource that is returned by the server when that URL is requested by a client, typically a browser. A resource is any item of interest, such as information about a golf course or a golfer’s profile. The URL contains all the information necessary to pull up a unique resource (citing the read operation). REST is an acronym for Representational State Transfer. The state is the resource (the golf course information or golfer’s profile) as it exists on the server, typically stored in a database. The representation of that state is the document returned. When the URL is requested, the state is transferred from the server to the client.[10]

10http://www.xfront.com/REST-Web-Services.html

 

In essence, page actions tack a front controller onto the JSF life cycle. Page actions behave similarly to Struts actions. In either framework, the action is selected by the controller based on a URL-to-action mapping and subsequently invoked prior to any view processing or page rendering. The front controller is the design pattern used by action-based frameworks, including Struts, WebWork (Struts 2), and Spring MVC. You can take comfort in the fact that, with Seam at the helm, you don’t have to abandon your action-based way of thinking or the ability to serve RESTful URLs when you make the move to JSF.

Page actions are specified using method-binding expressions. There are two ways to associate a page action with a view ID. The action can be defined on a page node in Seam’s page orchestration descriptor, pages.xml, either in the action attribute on the <page> node or in a nested <execute> node. The action can also be specified in the action attribute on a Seam UI command component, <s:button> or <s:link>. You may wonder how the latter can be considered a page action since it’s triggered by a user action, just as the UICommand components work. It’s because the Seam command components construct URLs that issue an initial request (not a postback) and therefore contain all the information necessary to trigger an action method. If the URL created by one of these components is bookmarked, the action is executed just as if the user had activated the component.

One of the most common use cases for page actions is preloading data prior to rendering a view. To satisfy this use case, it’s most appropriate to use the pages.xml descriptor to associate the action method with the view ID since the idea is to handle all requests for the resource, even invalid ones.

Preloading data

Suppose you wanted to preload the list of golf courses before rendering the directory listing. Doing so would allow you to trap possible errors that might occur when retrieving the results from the database before the page begins rendering.

To execute an action before rendering, you specify a method-binding expression in the action attribute of the <page> node in any page descriptor. The page parameters are applied to the model before the page action executes. So, just as form element bindings are used to populate the model for actions executing in the Invoke Application phase of a JSF postback, page parameters are used to populate the model for page actions. Here, the Facility result list is fetched in the page action, perhaps eagerly fetching lazy associations on the Facility entity as part of the query:

  <page view-id="/FacilityList.xhtml"
    action="#{facilityList.preloadFacilities}">
    ...
  </page>

Now let’s assume that you want to bring up the list of facilities that are in the home state of the user, if the user is authenticated. You’ll learn how to implement authentication with Seam in chapter 11. Assuming that there’s a mechanism available to access the current user’s information, the #{facilityList.applyRegionalFilter} method will apply it to the search parameters, but only if an active search isn’t detected (to avoid interfering with it). The facilities will then be preloaded as before since the actions are executed in the order they appear in the page node. To apply multiple page actions to a single page node, you use nested <action> nodes:

  <page view-id="/FacilityList.xhtml">
    <action execute="#{facilityList.applyRegionalFilter}"
      if="#{identity.loggedIn and !facilityList.searchActive}"/>
    <action execute="#{facilityList.preloadFacilities}"/>
    ...
  </page>

Having the ability to execute a method prior to rendering is only half the benefit. The true value of page actions is their ability to trigger declarative navigation. This is one feature you don’t get by putting the prerender logic in the beforePhase() method of a JSF PhaseListener.

3.4. Combining page actions with navigation

The navigation that follows a page action works just like the navigation used after the Invoke Application phase on a JSF postback. Thus, Seam’s page actions can be combined with its intelligent navigation capabilities in order to make decisions about how to direct the user in the event that a page action needs to divert the user from the requested page. If you perform a redirect—not a <render>—in the navigation rule, then the ensuing page may also use a page action. Thus, chaining actions prior to rendering a page is possible. A view ID that participates in this chain does not need to correspond to an view template (i.e., it’s a pseudo-page).

The most obvious use for combining a page action with navigation is to validate that the URL being requested is legitimate and that the page can be rendered successfully.

3.4.1. Sanity checking a request

Consider what happens when a user requests the course detail screen directly, perhaps from a bookmark. The course is looked up by id using the value supplied in the courseId request parameter. What happens when the requested courseId is empty or no such id exists in the course table? JSF is notoriously awful at handling this situation. Because the JSF controller works in a passive manner, it doesn’t figure out that the request is missing information until halfway through the rendering process. Once the page begins rendering, you can’t reroute the user to a more appropriate page, even when it becomes apparent that the target data is absent—unless you throw an exception. You end up displaying a page with blank values and other potential rendering glitches.

Page actions to the rescue! Let’s implement a method validateEntityFound() that verifies that a course can be found before rendering begins:

  public String validateEntityFound() {
      try {
          this.getInstance();
      }
      catch (EntityNotFoundException e) {
          return "invalid";
      }

      return this.isManaged() ? "valid" : "invalid";
  }

Behind the scenes, the getInstance() method is using the courseId value that’s assigned to the courseHome component by the page parameter to look up the corresponding entity instance in the database. The isManaged() method tells us whether the entity was found in the database, as opposed to a new, transient instance being created.

Of course, if things don’t go well, and the outcome value is “invalid,” then we need to perform navigation. Navigation rules are invoked after executing a page action just as they are when an action is invoked on a JSF postback. Here, we redirect users to the /CourseList.xhtml JSF view if the course cannot be successfully loaded, letting them know with a warning message why they were redirected:

  <page view-id="/Course.xhtml" action="#{courseHome.validateEntityFound}">
    <navigation from-action="#{courseHome.validateEntityFound}">
      <rule if-outcome="invalid">
        <redirect view-id="/CourseList.xhtml">
          <message severity="WARN">
            The course you requested does not exist.
          </message>
        </redirect>
      </rule>
    </navigation>
  </page>

Your Course.xhtml page is now protected from bogus requests. You may be wondering about the CourseEdit.xhtml page, which also needs to be protected. You could apply the same logic to that page as well by registering equivalent configuration with the /CourseEdit.xhtml view ID. However, just to demonstrate additional capabilities of the <page> node, let’s combine the two view IDs together and use a complex conditional expression to determine when the validation should be applied. First, a <page> node is defined that matches all view IDs that begin with /Course. Then, by consulting the implicit JSF expression #{view.viewId}, which resolves to the current view ID, the validation can be applied to the detail page and, if the courseId property on courseHome is non-null, the editor page:

  <page view-id="/Course*">
    <action execute="#{courseHome.validateEntityFound}"
      if="#{view.viewId == '/Course.xhtml' or
        (view.viewId == '/CourseEdit.xhtml' and
        courseHome.courseId != null)}"/>
    <navigation from-action="#{courseHome.validateEntityFound}">
      <rule if-outcome="invalid">
        <redirect view-id="/CourseList.xhtml">
          <message severity="WARN">
            The course you requested does not exist.
          </message>
        </redirect>
      </rule>
    </navigation>
  </page>

Note that the navigation rules are consulted after each action is executed. If the outcome of a page action matches a navigation rule, the remaining page actions will be short-circuited. So for all page actions to execute, only the last one can trigger navigation.

As you can see, it’s possible to create fairly sophisticated rules about when to invoke page actions. However, they do require some setup. To handle the more common cases of prerender functionality, Seam provides a couple of built-in page actions to secure a view.

3.4.2. Built-in page actions

Every application needs certain page-oriented features, such as the ability to restrict unauthenticated or unauthorized users from accessing protected pages. Rather than forcing you to invest time in a solution for every application, Seam offers a handful of built-in page actions for handling this work.

If you’ve ever tried to use a servlet filter-based security mechanism, such as Spring Security, to secure JSF pages, you were likely frustrated by the fact that it doesn’t do a good job of securing JSF pages because it’s not granular enough. Securing JSF pages is easy if done at the proper level, just prior to the Render Response phase. Page actions are the perfect fit. To restrict access to users that aren’t authenticated, you simply add the login-required attribute to the page definition:

  <page view-id="/CourseEdit.xhtml" login-required="true"/>

You can also enforce custom security rules using a nested <restrict> element. If you’re using a Java Authentication and Authorization Service (JAAS) principle (we cover its configuration in chapter 11), and you want to enforce role-based security according to the return value of isUserInRole(), then you can do so using the built-in EL function named s:hasRole in the <restrict> element. Let’s assume that there’s a role named “edit” that is used to grant privileges to modify records. You can prevent anyone who isn’t assigned the edit role from modifying a course with the following page declaration:

  <page view-id="/CourseEdit.xhtml" login-required="true">
    <restrict>#{s:hasRole('edit')}</restrict>
  </page>

In a fashion similar to how you require the user to be authenticated, you can enforce that a conversation already be in effect by adding the conversation-required attribute to the page declaration. Both of these tags can also be added to the root <pages> node if you want either of them to apply to all pages. If either of these two conditions fails, Seam provides the login-view-id and no-conversation-view-id attributes that indicate where to direct the user. We’ll look at security and conversations in much greater depth later in this book. Just note that these are features of Seam that you can configure using pages.xml.

There is another built-in page action that is capable of loading a message bundle for a set of pages. The keys are added to the unified message bundle that’s prepared by Seam. You learn how to configure and use the Seam message bundle in section 5.5.2 of chapter 5. The following declaration loads the message bundle defined in the admin.properties file on the classpath for the administration section of the website:

  <page view-id="/admin/*" bundle="admin"/>

It’s also possible to enforce that a page be requested via an HTTPS request using a built-in action. The scheme attribute on the page declaration checks the current scheme and redirects the user to the appropriate scheme if it’s not the correct one:

  <page view-id="/secure/*" scheme="https"/>

I could fill a book trying to cover every last detail of Seam’s page-oriented functionality. Since there’s plenty more in Seam to cover, I need to move on rather than itemize the entire page descriptor schema. I encourage you to consult the Seam reference documentation if you’re curious about a lesser-used page descriptor configuration element that I haven’t covered here.

The prerender logic discussed so far is transparent to the user. However, a URL that makes sense to the developer doesn’t always make sense to the end user or a search engine. Specifically, URLs that have a lot of query string parameters appear rather cryptic. The next section shows you how to create friendlier-looking URLs in Seam.

3.4.3. Search engine–friendly URLs

Using a layer of abstraction between the URL and the rendered view can accommodate a more logical, prettier, and RESTful URL strategy. The goal is to turn URLs that look like /Course.seam?courseId=15 into /course/view/15. JSF wasn’t designed with the REST concept in mind, so we must look elsewhere. Although it’s possible to preprocess the request using page actions, as we did in the previous example, it’s far easier to accomplish this task using a third-party rewrite filter, aptly named UrlRewriteFilter. If you’re familiar with Apache’s mod_rewrite filter, the premise is the same.

 

Why are search engine–friendly URLs desirable?

To help people find information on your site, you want to ensure that search engines understand your website or application. One way to optimize a site for search engines is by making the links that point to other pages of the site self-describing. The URL should contain words and characters that provide clues as to what resource will be displayed when the URL is requested. Search engines can then learn this pattern and provide search results that associate a direct link to a resource that matches the search terms.

All the relevant information should also be in the URL path. Putting information in the query string makes it difficult for the search engine to sort between essential and nonessential information and may even cause important information about the resource to be truncated. Statistics engines are notorious for wreaking such havoc on URLs. So having search engine–friendly URLs also means having statistics engine–friendly URLs. The statistics generated are also more accurate since you get the granularity of showing the requests for resources rather than just the servlet path that serves them.

Search engine–friendly URLs are desirable because they are simple and they are technology agnostic. Suppose you implement your application in Struts and spread around links that ended in .do. Then, if you later switch to JSF, all of the existing links instantly become invalid, likely resulting in a 404 error for the user. You now have the job of publicizing the new links that end in .jsf (or .seam). Instead, what you want to do is make the URL about the resource, not about the framework that’s serving it.

 

At the time of this writing, Seam doesn’t include a filter in its filter chain for enabling and configuring the UrlRewriteFilter, though it’s expected to be in the Seam 2.1 release. Until then, it needs to be configured in the web.xml descriptor. Add the following XML stanza anywhere below the SeamFilter in that file:

  <filter>
    <filter-name>UrlRewriteFilter</filter-name>
    <filter-class>
      org.tuckey.web.filters.urlrewrite.UrlRewriteFilter
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>UrlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

You’ll also need to modify the build to include the urlrewritefilter.jar file in the deployment archive. Please see appendix A for details on how to add a library to the deployment archive.

The rewrite rules are defined in the /WEB-INF/urlrewrite.xml descriptor. The rules are defined using either Perl 5 regular expressions or wildcards. It’s possible to capture match references and pass them on to the new URL that’s constructed. Listing 3.5 shows the configuration for friendly course URLs.

Listing 3.5. URL rewrite configuration for friendly URLs

Friendly URLs can cause relative paths to break since the servlet path is no longer representive of the rendered view. A reference to a stylesheet may stop working because the browser thinks that the friendly URL is the base URL of the resource. To solve this problem, you should use absolute references to such resources, such as

  #{facesContext.externalContext.request.contextPath}/stylesheet/theme.css

It’s also possible to create friendly URLs using the inverse mechanism. If you use regular HTML links, links created with <h:outputLink>, or Seam UI command components in your view, you can define outbound rules that convert link targets to friendly URLs before they are sent along with the response. Here’s an example of an outgoing rewrite rule that produces friendly course URLs for the course detail page:

  <outbound-rule>
    <from>^(/.+)?/Course.seam?courseId=(d+)$</from>
    <to>$1/course/view/$2</to>
  </outbound-rule>

When defining outbound rules with strict matching (the leading caret), the context path (in this case /open18) must be captured in the <from> expression and passed on to the target URL. You also have to consider all the possible query parameters that may appear in the URL for the rule to be matched. A common parameter to watch out for is the conversation id parameter, thus requiring a more complex expression.

The UrlRewriteFilter is quite capable of slicing and dicing the URL in whatever creative ways you can think of to write regular expressions. Not only is it useful for creating friendly URLs, but it can also help when you want to migrate a site to a new structure, serve custom resources based on the user agent (browser), or trim long or complicated URLs. You can see more examples of the UrlRewriteFilter in action in the example projects (under the examples directory) that come with the Seam distribution.

Now that you are well versed in Seam’s pages.xml configuration, it’s time to see how Seam ties this functionality into the JSF life cycle and what else it adds in the process.

3.5. The JSF life cycle with Seam

The JSF life cycle under the direction of Seam is more well balanced than its intrinsic counterpart. By that, I mean that in Seam’s version of the JSF life cycle, the initial request processing is just as full-featured as the postback processing. You’ve seen many of the ways in which Seam expands the activity in the initial request by applying page-oriented features. These new features include parameter mappings, front controllers, and request routing. In this section, we’re going to (quickly) step through the JSF life cycle again, this time observing the points where Seam adds its enhancements.

3.5.1. Phase listeners versus servlet filters

Seam is able to work closely with JSF thanks to the granularity offered by a phase listener. Few other frameworks offer such a deep view into the execution processes. You’ll often see frameworks using servlet filters to perform such tasks, such as Spring Security. The problem with filters is that they work at too high a level and lack the intimate knowledge of what’s going on inside the request. Without this context, it becomes difficult to make the correct decision. Under some circumstances, it’s impossible for a filter to influence the execution path. Seam’s phase listener, SeamPhaseListener, is low-level enough to alter the execution flow of the life cycle as dictated by the page-oriented functionality or to get it involved in supplemental business. Let’s examine when these activities take place.

3.5.2. Stepping through the augmented life cycle

Before we get started with the revamped JSF life cycle, let me warn you that the amount of activity that happens in the Seam life cycle is daunting. Trying to cover it all on a single walkthrough would be difficult. Therefore, I’ll give you a general idea of what happens, emphasizing key points. Think of this run-through as the highlights reel: it’s going to give you a broad overview and plenty to be excited about. Are you ready to roll the tape?

The initial request, Seam-style

Once again, we’ll examine the life cycle as it processes the initial request. I promise that the story is far more interesting this time around. Table 3.2 walks through the tasks that Seam wraps around the JSF phases on the initial request.

Table 3.2. A general overview of the tasks that Seam incorporates into the JSF life cycle on an initial request (JSF phases shown in bold; horizontal line signifies transition from Restore View to Render Response)

Step

Task

Description

1 Initial request The life cycle begins with a GET request captured by the JSF servlet.
2 Begin JTA transaction If transaction management is enabled and JTA transactions are being used, a JTA transaction is opened.
3 Restore View On an initial request, the Restore View phase merely creates an empty component hierarchy.
4 Restore or initialize conversation Restore the long-running conversation if requested. If there’s a problem restoring it due to a timeout or concurrent access and authentication isn’t required, advance to the no-conversation view. If a long-running conversation doesn’t exist, initialize a temporary conversation.
5 Handle conversation propagation Determine from the request parameters if a long-running conversation is to begin, end, be joined, or remain untouched.
6 Validate page flow If a stateful page flow is in use, it is validated to ensure the user isn’t attempting to request a page out of sequence. If the request isn’t compliant, appropriate action is taken.
7 Process page parameters The parameters associated with this view ID are read from the request, converted, validated, and stored in the view root.
8 Enforce login, long-running conversation, and permissions If the user must be authenticated to view this page, the nonauthenticated user is redirected to the login page. Once authenticated, the process of rendering this page is resumed. If a long-running conversation is required to view this page and one doesn’t exist, the user is forwarded to the no-conversation view. If the user doesn’t have appropriate permissions to view this page, a security error is raised.
9 Apply page parameters If all validations and conversations pass, the page parameters are applied to the model via the value bindings or stored in the page context (no value binding).
10 Begin non-JTA transaction If transaction management is enabled and resource-local (non-JTA) transactions are being used, the remaining response is wrapped in a resource-local transaction (through interaction with the persistence manager).
11 Emulate the Invoke Application phase The life cycle temporarily takes on the signature of the Invoke Application phase to accommodate postback features on an initial request.
12 Enforce login, long-running conversation, and permissions The restrictions are once again applied. This step occurs twice because some execution paths will skip steps 1–9 when rendering a given view ID after a navigation event.
13 Select data model row If request was initiated by a Seam UI command component within a UIData component, advance the index of DataModel to the corresponding row.
14 Execute page actions Each page action associated with the view ID is executed. This includes actions that are passed through a Seam UI command component. Navigation rules are applied after each execution. If more than one navigation rule is applicable, the one with the highest priority is used.
15 Commit transaction If transaction management is enabled and a transaction is active, it is committed. A new transaction is opened to prepare for the rendering of the response.
16 Migrate JSF messages Interpolate then migrate Seam-managed FacesMessages stored in the conversation to the FacesContext, having now survived any redirects.
17 Prepare conversation switching Conversations can be selected through a UI component. This step remembers the description and view ID for the current page. The stack must be prepared at this point in the event the life cycle is short-circuited before the Render Response phase.
18 Store conversation The conversation is stored in the session until the next request.
19 Render Response The response is rendered by reading the JSF view template and encoding it to the generated markup (typically XHTML). The UI component hierarchy is stored in either the client or the server to be restored on a postback.
20 Commit transaction If transaction management is enabled, commit the transaction that was active during the rendering of the response.
21 Prepare conversation switching Conversations can be selected through a UI component. This step remembers the description and view ID for the current page, and updates the stack prepared prior to the Render Response phase.
22 Clean up conversation Either end the temporary conversation or update the last request time of the long-running conversation.

You can breathe again; the process is over. Table 3.2 doesn’t cover every last detail of the steps added by Seam in the JSF life cycle, but it comes pretty close. If you had to abbreviate this list, the most notable improvements made to the initial request are

  • Transactions are started and stopped automatically (if they are enabled).
  • Page parameters, actions, and restrictions defined in the page descriptor are applied.

The global transaction that Seam wraps around each request is an important part of what makes Seam applications so practical. You can safely perform persistence operations in your page actions and action methods without having to worry about beginning and committing a transaction. Seam takes care of it for you. If you prefer to push your persistence logic to other layers, you are still able to take advantage of the global transaction since it spans the entire action method call stack. Global transactions are addressed in chapters 8, 9, and 10, which cover transactions and persistence in depth.

 

Lazy associations in the view

One of the key benefits of Seam is how it properly scopes the persistence manager (JPA EntityManager or Hibernate Session) to allow uninitialized proxies and entity associations to be traversed in the view without fear of encountering a LazyInitializationException (LIE). In short, they just work. In the past, developers have relied on the Open Session in View pattern to extend the lifetime of the persistence manager across a single request. Seam takes a smarter approach by binding the persistence manager to the conversation scope and dually wrapping a transaction around the request. In chapter 9, you learn about Seam’s conversation-scoped persistence manager and how it contrasts with the Open Session in View pattern.

 

After seeing nearly two dozen steps on the initial request, you may be dreading the postback. Well, fear not, because there isn’t much to cover. Seam performs most of its work around the Restore View and Render Response phases.

Less patching on postback

This section is extremely short because a postback in the Seam life cycle is simply a combination of Seam’s page-oriented additives and the standard JSF postback mechanism. The most notable enhancement is that Seam wraps a transaction around the Invoke Application phase, committing the transaction once the phase is complete. This parallels how page actions are managed. Once again, Seam takes the tedium of dealing with transactions out of the picture until we’re absolutely ready to start fine-tuning them. One thing to watch out for is that page actions get executed on a postback, something you might not think about at first. To ensure that a page action only executes during an initial request, you can apply the following conditional logic to the page action declaration:[11]

11 In JSF 1.2, this check is performed by the ResponseStateManager#isPostback(FacesContext) method.

  <page>
    <action execute="#{actionBean.executeOnInitialRequestOnly}"
      if="#{empty param['javax.faces.ViewState']}"/>
  </page>

The Seam life cycle introduces quite a number of new features on top of what was already available with the JSF life cycle by hooking into its phase listener architecture. The most blatant deficiencies in JSF are the initial request handling and the navigation capabilities, both of which Seam corrects, making it possible to create more sophisticated JSF applications. All too often, though, things go wrong. When they do, the application should handle itself just as well as it does when things go as planned. In the next section, you’ll learn that Seam helps out in this area by tacking an exception-handling facility onto JSF.

3.6. A try-catch block around the life cycle

The ability to handle exceptions is just as important as all the other cool and exciting things that a framework such as Seam can do. Unfortunately, exception handling is often overlooked. This is true of JSF. The faces-config.xml descriptor doesn’t allow exception handlers to be defined. Fortunately, Seam taps into the JSF life cycle to trap and handle exceptions gracefully.

3.6.1. Failing gracefully or with intentional crudeness

Seam handles failures by catching a thrown exception that occurs during the processing of the request and offers you a chance to deal with it from within the same execution of the life cycle. By catching the exception as part of its life cycle, Seam can retain page parameters, the temporary or long-running conversation, and any JSF messages that may have been added before the exception occurred. Seam will also ensure that any transactions are rolled back before delegating to the exception handler if deemed appropriate.

When dealing with an exception, you can take one of two actions:

  • Redirect
  • Send HTTP error code

In the process of handling an exception, you may also

  • Add a JSF message
  • End a conversation
  • Add parameters to a redirect

There are two ways you can define how an exception is handled. You can either define exception matching rules in the page descriptor that watch and act on exceptions when they are thrown, or you can go straight to the exception class and configure how the exception should be handled when it is raised.

3.6.2. Registering an exception handler

To configure an exception handler, you again leverage the page descriptor. Using the code in listing 3.6, we capture a Seam authorization exception in a graceful manner. When Seam catches the exception, it first stores the original exception in the conversation-scoped variable named org.jboss.seam.caughtException.[12] It then looks through the exception hierarchy for an exception handler. If it finds one, it stores the handled exception in the conversation-scoped variable named org.jboss.seam.handledException. The exception handler can then add a message to the request and issue navigation to an error page. The message is a standard JSF FacesMessage and is thus displayed in the user interface using the <h:messages> component tag.

12 Prior to Seam 2.1 the original exception was stored in the variable named org.jboss.seam.exception.

Listing 3.6. Configuration for capturing authorization exceptions

 

Note

If you’re using Facelets, you have to ensure that both Facelets development mode and Seam debug mode are disabled in order for the exception handler to kick in all cases. Otherwise, you may be presented with a special debug page that displays the exception. The instructions for toggling Seam debug mode and Facelets development mode can be found in section section 2.6.1 of chapter 2.

 

3.6.3. Handling the exception at the source

You can also configure exception handling through annotations by adding either an @HttpError annotation or a @Redirect annotation to the exception class (but not both). You can supplement either of these with the @ApplicationException annotation to control how the active transaction or long-running conversation is handled.

The @Redirect annotation, summarized in table 3.3, allows you to render a pretty error page and kindly inform the user what went wrong.

Table 3.3. The @Redirect annotation

Name:

Redirect

Purpose:

Indicates that an HTTP redirect should be issued when this exception is raised.

Target:

TYPE (exception class)

Attribute

Type

Function

message String (EL) The message used to register an info-level FacesMessage. Default: the exception message.
viewId String (EL) The JSF view ID to redirect to when this exception is thrown. Default: the current view ID.

The @HttpError annotation, on the other hand, is typically used to generate a fatal and ungraceful response to the client. I think of it as screaming at an unwelcome guest. When an exception class annotated with @HttpError is thrown, Seam will send the specified HTTP status code to the browser along with the message in the exception. The @HttpError annotation is summarized in table 3.4.

Table 3.4. The @HttpError annotation

Name:

HttpError

Purpose:

Indicates that an HTTP error response should be sent when this exception is raised.

Target:

TYPE (exception class)

Attribute

Type

Function

message String (EL) The message used to register an info-level FacesMessage. Default: the exception message.
errorCode int One of the HTTP error code constants in the Java Servlet API. Default: 500, an internal server error.

The @ApplicationException annotation, summarized in table 3.5 is used to end a long-running conversation or immediately roll back the active transaction. When an exception class annotated with @ApplicationException is thrown, Seam determines from this annotation how to handle the conversation and the transaction. Note that unhandled exceptions always force a rollback. The @ApplicationException just forces the rollback to happen immediately.

Table 3.5. The @ApplicationException annotation

Name:

ApplicationException

Purpose:

Controls how the long-running conversation and transaction are handled when this exception is raised. A synonym to javax.ejb.ApplicationException for use in non-EJB environments.

Target:

TYPE (exception class)

Attribute

Type

Function

rollback boolean If true, this flag indicates that the transaction should roll back immediately. If false, the transaction is rolled back at the end of the request. Default: false.
end boolean If true, this flag indicates the long-running conversation should be ended. If false, the conversation is left untouched. Default: false.

As an example, suppose you’ve implemented an exception specific to your application:

  @Redirect(viewId = "/penaltyStrokeWarning.xhtml"
      message = "You're ball is out of play. That will cost you one stroke.")
  public class OutOfBoundsException extends Exception {}

With exceptions handled properly, and the user having received the appropriate slap on the wrist for foul play, the coverage of the Seam life cycle comes to a close. Seam is a tremendous web-oriented framework because it has taken JSF and extended it to give you all the control you need over the pages in your application.

3.7. Summary

In this chapter, you learned how Seam hooks into the Java Servlet and JSF life cycles to provide services for both JSF and non-JSF requests. You witnessed the multifaceted nature of this integration, which leverages a servlet listener to bootstrap Seam and listen for HTTP session events, a JSF phase listener to tap into the JSF life cycle, a servlet to generate and serve supporting resources, and a servlet filter to provide services beyond the reach of the JSF servlet. With this integration in place, focus turned toward Seam’s JSF enhancements.

This chapter dedicated a section to reviewing the JSF life cycle, presenting the stark contrast between an initial request and a postback and identifying which of the six life-cycle JSF phases play a role in each scenario. You discovered that the notification of each phase transition, captured using a JSF phase listener, is how Seam weaves in many of its JSF enhancements, giving rise to the Seam life cycle. The steps of the Seam life cycle were explained.

Most of Seam’s enhancements affect the initial request, in the form of page-oriented controls, which were covered in detail. The controls are configured in Seam’s page descriptor, which you learned acts as a stand-in replacement for navigation rules defined in the JSF configuration file. I encouraged you to move to Seam’s navigation rules to gain more intelligent navigation. You also learned that committing to Seam’s page descriptor gives you the ability to accomplish tasks that JSF has been criticized for lacking in the past, such as a front controller, advanced page navigation, RESTful URLs, and exception handling. In short, by extending JSF, Seam delivers features of an action-based framework like Struts without ditching the many benefits of a component-based model.

Having gained the big picture of a Seam request, you are now ready to turn to the other essential aspects of Seam: components and contexts. In the next chapter, you’ll learn about Seam components, those classes in a seam-gen project decorated with the @Name annotation. You’ll discover that Seam components can effectively replace the managed bean facility in JSF. But what makes Seam stand apart is that Seam components can serve many roles, ranging from presentation to business to persistence. In fact, a single component can serve in all three roles. Read on to discover how Seam’s contextual container is used to support the Seam life cycle and how Seam’s liberal architecture gives Seam components tremendous utility.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.35.122