Spring Web Flow for better workflow management in JSF

An alternative to the JavaServer Faces CustomNavigationHandler

1 2 3 4 Page 4
Page 4 of 4

Integrating SWF with the Course Registration application

You're now ready to begin extending the Course Registration application to meet evolving requirements. The first thing you need to do is inform the JSF runtime that the application's navigation will now be managed by Spring Web Flow. You do this by planting a series of "hooks" in web.xml and faces-config.xml. After that, you can write a new file to configure the workflow, which you can call registration.xml.

In Spring Web Flow, application beans are registered in a separate file called services-config.xml, normally kept in the compiled classes' directory. For the example application, this file is as shown in Listing 2.

Listing 2. services-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

<bean id="UserBean" class="com.javaworld.command.UserBean">

</bean>
<bean id="WebBean" classs="com.javaworld.command.WebBean">
</bean>
<bean id="ClassBean" class="com.javaworld.command.ClassBean">
</bean>

</beans>

The above basically tells Spring Web Flow to instantiate the necessary beans and make them readily available for your use. Note that SWF uses Spring dependency injection.

You need to write two more files, the first one specifying to SWF where you will keep your flow sequence and transition definitions. Here is the work-flow config.xml file.

<flow:executor id="flowExecutor" registry-ref="flowRegistry"/>
        <flow:registry id="flowRegistry">
        <flow:location path="/WEB-INF/flows/registration.xml" />
    </flow:registry>


Note that the flow location path now points to the flow directory and registration.xml.

Configuring the application workflow

Looking back at Figure 8, you can now easily write the registration.xml file, which basically lists the start state, view state, decision state, and end state for the application. Listing 3 shows the registration.xml file.

Listing 3. registration.xml

<start-state idref="enterReg" />

    <view-state id="enterReg" view="/jsp/registerationhome.jsp">
        <transition on="register" to="confirmation"/>
        <transition on="cancel" to="enterReg"/>
    </view-state>

    <view-state id="confirmation" view="/jsp/courseconfirm.jsp">
        <transition on="edit" to="enterReg"/>
        <transition on="success" to="requiresStatus"/>
    </view-state>

    <decision-state id="requiresStatus">
    <if test="${flowScope.UserBean.webBased}" then="enterWebDetails" else="enterClassDetails" />

    </decision-state>

<view-state id="enterWebDetails" view="/jsp/webdetails.jsp">
        <transition on="cancelweb" to="enterReg"/>
        <transition on="confirmweb" to="done"/>
    </view-state>

<view-state id="enterClassDetails" view="/jsp/classdetails.jsp">
        <transition on="cancelclass" to="enterReg"/>
        <transition on="confirmclass" to="payment"/>
    </view-state>

    <view-state id="payment" view="/jsp/payment.jsp">
        <transition on="pay" to="done"/>
        <transition on="cancel" to="enterReg"/>
    </view-state>
    <end-state id="done" view="/jsp/done.jsp"/>

Note the darker line in the above code snippet. This piece of code allows the flow to take a decision based on a user selection. Such dynamism is the beauty of SWF. What you see is an expression enclosed in {..} and preceded by a $ symbol and a reserved word "flowScope". The $ is used with the expression language OGNL.

Note also that different kinds of scopes are provided in Spring Web Flow, such as flow scope, flash scope, and request scope. In this example a flow scope indicates that the states of the beans is to be available for the entire application flow, also known as a conversation. See the full registration.xml from Rave2.war to see how this is defined.

web.xml

Listing 4 shows the web.xml with the SWF "hooks" added.

Listing 4. Revised web.xml

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/com/javaworld/command/services-config.xml,/WEB-INF/webflow-config.xml</param-value>

</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.faces</url-pattern>
    </servlet-mapping>


Other than the usual JSF-related configuration settings for FacesServlet, you can see some context parameters and Spring's context loader listener. This is the first point at which Spring enters your application infrastructure.

faces-config.xml

Finally, take a look at the evolved faces-config.xml. It has become just few lines, with most of the configuration now routed to other files.

Listing 5. The revised faces-config.xml

<faces-config>
<application>
<navigation-handler>
org.springframework.faces.webflow.FlowNavigationHandler
</navigation-handler>
<variable-resolver>
org.springframework.faces.webflow.el.DelegatingFlowVariableResolver
</variable-resolver>
</application>


<lifecycle>
<phase-listener>
org.springframework.faces.webflow.FlowPhaseListener
</phase-listener>
</lifecycle>
</faces-config>

SWF has intercepted the normal JSF execution with its FlowNavigationHandler, taking most of the flow management associated with JSF out of your hands.

Transitions

If you look at the definition of the flow sequence, namely registration.xml, you may notice that the transition to enterReg state occurs at different times. This happens when the user cancels an operation. You can abstract it out as follows:

<global-transitions>
    <transition on="cancel" to="enterReg"/>
</global-transitions>

This global transition indicates that, at any point in the flow, if there is an outcome named "cancel," the flow will be directed to enterReg state, which is the application's initial state in flow.

Exception handling

Spring Web Flow also provides a method for exception handling while moving from one page to another, shown here:

<view-state id="mystate">
<transition on="confirm" to="enterWebDetails"/>
<transition on-exception="com.jw.UserRegisteredException"
to="errorState"/>
</view-state>

When there is an event/outcome named "confirm", if there is any exception, it will be directed to, say, an error page state with the exceptions shown.

In conclusion

I started the article with an introduction to JSF, some useful tips, and an initial JSF implementation satisfying a small set of requirements. I then showed you how to use Spring Web Flow as a supportive framework for evolving a JSF application as its requirement set grows.

Spring Web Flow is a very powerful open source solution for implementing navigation logic and managing application state, especially in rapidly evolving application scenarios. As I've shown, it integrates very nicely with JSF. It also integrates well with Spring MVC and Struts.

While a detailed introduction to Spring Web Flow was beyond the scope of this article, you should now know enough about it to begin using it and learning about it on your own. See the Resources section for more articles about Spring Web Flow. You can also download the source code that accompanies this article to further explore the examples.

Ravi Shankar is assistant vice president of technology development section, currently working in the financial industry. He is a Sun Certified Programmer and Sun Certified Enterprise Architect with 14 years of industry experience. He was a presenter at JavaOne 2004 and also presented at IIWAS 2004 and IMECS 2006. Ravi served as a technical member on the OASIS Framework for Web Services Implementation Committee. He spends most of his leisure time exploring new technologies.

Learn more about this topic

1 2 3 4 Page 4
Page 4 of 4