Spring Web Flow for better workflow management in JSF

An alternative to the JavaServer Faces CustomNavigationHandler

1 2 3 4 Page 2
Page 2 of 4

Setting up the environment

Before we start coding, let's make sure your development environment is set up how it needs to be. Here's what you need to do:

  1. Ensure you have installed JDK 1.5 and your Java home environment variable points to it.
  2. Download and install apache-tomcat-6.0.14 from the Apache homepage.
  3. Make sure that the following files are available in your Tomcat lib directory:

    A snapshot of Tomcat's lib directgory
    Figure 3. Tomcat's lib directory

    Note that jsf-api.jar and jsf-impl.jar are essential to this environment setup, along with some others for implementing a JSF application.

  4. Go to your Tomcat webapps directory and create a new folder called Rave. You'll use this folder to experiment with the code examples and scenarios discussed in the next sections.
  5. Finally, start up Tomcat and make sure that you get the default Tomcat page when you access http://localhost:8080.

That's it -- we're ready to go!

The Course Registration application

We'll start with a very simple development scenario involving a customer requirement. Say the customer is interested in a couple of screens that will enable users to register for a course, perhaps one conducted by JavaWorld.

You'll start by creating a simple Course Registration application based on the initial requirements given. Figure 4 shows the first screen of the Course Registration application.

A snapshot of the course registration homepage.
Figure 4. Course Registration homepage

As you can see, the first screen contains some simple UI components -- inputText, selectOneRadio, and so on. The flow of the Course Registration application is illustrated in Figure 5. See the Resources section for the complete source code, which is found in Rave1.war..

A diagram of the course registration workflow.
Figure 5. Course Registration application flow

When a user clicks on index.jsp, she will be forwarded to registrationhome.jsp. Her only option there is to click on the hyperlink provided. Once she does, the click sends a Welcome message, which is interpreted by the JSF runtime. The JSF runtime compares what you have configured in faces-config.xml against this page and renders the outcome. The next page will be courseregister.jsp.

From here, the user may go back to registrationhome.jsp by clicking Cancel (which sends the outcome "cancel") or continue by clicking Register (which sends the outcome "register"). If she clicks Register she will be sent to courseconfirm.jsp, where she may edit or confirm her registration details.

Once confirmed the application flow ends by landing the user at the coursedone.jsp screen; otherwise she can start again from courseregister.jsp.

As you see, it is possible with the features available in JSF, and by writing and configuring some files, to implement the initial set of requirements for the Course Registration application. For the sake of brevity I present the faces-config.xml file (excluding the standard DOCTYPE reference and <? xml> header) in Listing 1.

Listing 1. faces-config.xml for the Course Registration application

<faces-config>

<navigation-rule>
     <from-view-id>/jsp/registrationhome.jsp</from-view-id>
     <navigation-case>
        <from-outcome>welcome</from-outcome>
        <to-view-id>/jsp/courseregister.jsp</to-view-id>
     </navigation-case>
</navigation-rule>
<navigation-rule>
      <from-view-id>/jsp/courseregister.jsp</from-view-id>
      <navigation-case>
        <from-outcome>register</from-outcome>
        <to-view-id>/jsp/courseconfirm.jsp</to-view-id>
      </navigation-case>

<navigation-case>
        <from-outcome>cancel</from-outcome>
        <to-view-id>/jsp/registrationhome.jsp</to-view-id>
      </navigation-case>

</navigation-rule>

<navigation-rule>
      <from-view-id>/jsp/courseconfirm.jsp</from-view-id>
      <navigation-case>
        <from-outcome>edit</from-outcome>
        <to-view-id>/jsp/courseregister.jsp</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>registered</from-outcome>
        <to-view-id>/jsp/coursedone.jsp</to-view-id>
      </navigation-case>

</navigation-rule>

<managed-bean>
<managed-bean-name>
UserBean
</managed-bean-name>
<managed-bean-class>
com.javaworld.command.UserBean
</managed-bean-class>
<managed-bean-scope>
session
</managed-bean-scope>
</managed-bean>
</faces-config>

Just one problem ...

Surprise, surprise: when you deliver the solution described so far, the customer has a complaint about a small problem in one of the screens. Figure 6 illustrates the problem.

A diagram of the problem in the work flow.
Figure 6. A problem in Course Registration's application flow

The issue is trivial -- the customer says that when he enters some data in the registration form incorrectly (notice that the above address email is entered without the @ symbol), and presses Cancel, a validation error is shown instead of taking him to the homepage!

Fortunately, you can use a JSF attribute called immediate to resolve this problem. Writing the code without the immediate attribute, as shown in Listing 1, means that the JSF runtime will execute the complete application lifecycle to fulfill a request. Hence, when the customer clicks Cancel, the JSF runtime lifecycle executor proceeds to the Process Validation phase.

The immediate attribute is an easy way to get around this problem -- and any other scenario where you need to abort or ignore further lifecycle steps and immediately go to a Restore View or Render Response phase. Adding the following code snippet to your courseregister.jsp should resolve this customer complaint:

<h:commandButton value="Cancel"
                action="cancel" immediate="true">
</h:commandButton>
1 2 3 4 Page 2
Page 2 of 4