An alternative to the JavaServer Faces CustomNavigationHandler JavaServer Faces is a powerful framework for component-based Web UI development, but its CustomNavigationHandler introduces more complexity into rules-based navigation than you need. In this article, Ravi Shankar Nair shows you how to integrate a little flow — Spring Web Flow, that is — into an existing JSF application, bringing truly customizable and reusable navigation to your evolving JSF applications.JavaServer Faces (JSF) is a successful technology for component-based Web UI development. One of the main advantages of JSF’s component-based approach is that you need not revamp your application every time client technologies evolve, as they tend to do. The popularity of JSF also is growing with the emergence of JSF extension frameworks like Seam, MyFaces, and ICEfaces.Java Web application development with JSF can be surprisingly easy once you master its intricacies. That said, JSF’s default mechanism for managing workflow is not very powerful in terms of integration with existing technologies. Enterprise systems require more advanced workflow management than JSF provides. JSF falls short when it comes to embedding rules to determine the destination and routing of non-JSF pages, as well as handling exceptions and global transitions. In this article I share my experience of integrating the open source Web application framework Spring Web Flow with JSF. JSF beginners through intermediate developers will benefit from the practical examples, illustrations, and code snippets in the article. You will learn something about JSF and Spring Web Flow, as well as being introduced to an integrated development solution that leverages them both.JSF in briefJavaServer Faces is a Java-based Web application framework that simplifies the development of user interfaces for Java Web applications. Unlike other traditional request-driven MVC Web frameworks, JSF uses a component-based approach. The state of UI components is saved when the client requests a new page and then is restored when the request is returned. Out of the box, JSF uses JavaServer Pages as its display technology. It can also accommodate other display technologies, such as XML User Interface Language. JSF includes the following:A set of APIs for representing UI components and managing their state, handling events and input validation, converting values, defining page navigation, and supporting internationalization and accessibilityA default set of UI componentsTwo JSP custom tag libraries for expressing JSP pagesFaces interface within a JSP pageA server-side event modelState managementManaged Beans (Java beans created with dependency injection)Unified Expression Language for both JSP 2.0 and JSF 1.2The JSF specification was developed under the Java Community Process as JSR 127, which defined JSF 1.0 and JSF 1.1, and JSR 252, which defined JSF 1.2. JSF 2.0 is being developed as JSR 314. JSF’s request processing lifecycleJSF represents an exceptionally sophisticated implementation of the traditional MVC/Model 2 architecture, as shown in Figure 1. Unlike other Model 2 architectures, the controller servlet in JSF (FacesServlet) cannot be extended, because it is a final Java class.Figure 1. JavaServer Faces implements the MVC patternOne of the biggest advantages of JSF is that it automatically assigns form components (such as fields or checkboxes) to the fields/methods of the data model. JSF uses Unified Expression Language for this value/method binding. The innumerable code snippets typically associated with request.getParameter() are simply replaced with these binding expressions.As is the case with any Web application, the primary task is to take requests (mostly instances of HttpRequest) from the client and deliver responses (mostly instances of HttpServletResponse). Client in this case refers to Web browsers such as IE and Firefox. As you see in Figure 1, however, JSF can also render responses from mobile device clients and other sorts of browsers. The process of taking data through the entire request-response lifecycle is divided into a series of steps, or phases, as shown in Figure 2.Figure 2. The JSF request-processing lifecycleFigure 2 depicts the six phases of the JSF lifecycle, which is explained in detail elsewhere on JavaWorld. I’ll just briefly list the phases here:Restore ViewCreates a server-side component tree representing the application UI.Apply Request ValuesIssues a request.Parameter for all fields of the UI (all Strings).Process Validations/ConversionsValidates strings and converts them to data types.Update ModelUpdates model objects with fresh/new data.Invoke ApplicationInvokes application logic (such as a business method of an EJB) and navigates to a new page if necessary.Render ResponseThe response may be rendered in HTML, XUL, or WML, depending on the client device.Setting up the environmentBefore 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: Ensure you have installed JDK 1.5 and your Java home environment variable points to it.Download and install apache-tomcat-6.0.14 from the Apache homepage.Make sure that the following files are available in your Tomcat 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.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.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 applicationWe’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. 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..Figure 5. Course Registration application flowWhen 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. 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> Handling new requirementsFor a while the customer seems happy with the application. Then one day he invites you in for another meeting: “My Company is introducing two kinds of courses starting next month,” he says. “There will be Web-based courses and classroom-based courses. The topics for each class may be the same or different. All Web-based courses are free for employees. Classroom-based courses are not. I want to incorporate these extra requirements into the existing application. Can you do it quickly?”At the internal design meeting everyone agrees that this customer may come back in another two months with even more new requirements — for instance, a new type of course called “in-house training.” You will have to be prepared to adapt the application for these changing requirements. For this you will need a more configurable workflow management solution. Ideally, you want a rule-based solution that will let you easily handle new requirements.Custom navigation in JSFThe next step is to create a solution that will allow you to configure rules in your existing JSF application. The luminaries behind JSF have given us a native method for incorporating custom navigation handling into JSF applications. Rather than relying on JSF’s default NavigationHandler, you can write a CustomNavigationHandler. Figure 7 illustrates the process of incorporating custom navigation into an existing JSF application. Figure 7. Incorporating custom navigation in JSFAs you can see, the process involves writing a CustomNavigationHandler and registering it in your faces-config.xml file. You can do whatever you like with this custom handler — it even allows for navigation to non-JSF pages like those created using Struts 2 or a custom framework.The thing is, you’re on a short deadline now. Do you really want to write a custom workflow manager when you could leverage an existing open source framework famous for resolving just this sort of scenario?Introducing Spring Web FlowSpring Web Flow (SWF) allows you to represent a Web application’s workflow in a clear and simple way. Spring Web Flow’s reusable controller modules are completely configurable using XML, very much like JSF components but with more features. In Spring Web Flow, a Web flow (or flow) is composed of a set of states. A state is a point in the flow where something happens: for instance, showing a view or executing an action. Each state has one or more transitions that are used to move to another state. A transition is triggered by an event. In Spring Web Flow, states, transitions, and events collaborate to move the user across your UI from page to page. In Spring Web Flow, adding customer requirements is reduced to writing a few lines of XML and then developing the new pages. If you design properly, you may avoid writing anything in your Java bean at all!Consider the advantages of using flows rather than JSF’s CustomNavigationHandler:Flows can be designed to be self contained. This allows you to see a part of your application as a module and reuse it in multiple situations.Flows can define any reasonable UI flow in a Web application, always using the same consistent technique. You’re not forced into using specialized controllers for particular situations.It seems that Spring Web Flow may be the ideal solution to satisfy your customer’s new requirements. In fact, Figure 8 is a flow diagram illustrating how you could use Spring Web Flow to incorporate the new requirements into the Course Registration application. Figure 8. New requirements captured in a flow diagramThe above diagram consists of a start state, where the Spring Web Flow transitions begin; a decision state, where the flow needs to take a decision based on a value; and an end state, denoting the end of transitions. Note that if the user selects a Web-based training, there is no need for a payment. If the selection is classroom-based the user is sent to the payment screen.Spring Web Flow in your development environmentYou’ll need to set up your environment to use Spring Web Flow before continuing. You can start by creating a new directory under the Tomcat webapps directory, called Rave1. Spring Web Flow is a component of the Spring Framework’s Web stack focused on the definition and execution of UI flow within a Web application. It has been architected as a self-contained flow engine with few required dependencies or third-party APIs. All dependencies are carefully managed.At a minimum, to use Spring Web Flow you need to download and install the following from the Spring Web Flow homepage: spring-webflow (the framework)spring-core (miscellaneous utility classes used internally by the framework)spring-binding (the Spring data binding framework, used internally)commons-logging (a simple logging facade, used internally)OGNL (the default expression language)XhtmlHelper and ShaleXhtmlHelper is a helper bean for rendering links to download resources commonly used in HTML and XHTML pages. Shale is a Web application framework fundamentally based on JavaServer Faces. Spring includes Shale-related jars to allow seamless integration between different architectures and frameworks. For my development environment (which you should reproduce) I have used the latest releases available at the time of writing this article, mainly Spring Framework 2.1 and Spring Web Flow 2.0. In my Rave1WEB-INFlib directory I have all of the above files except the commons-logging file. I already had the logging-related files in my Tomcat directory, so didn’t need to recopy them here. To avoid compilation issues due to an Apache XhtmlHelper class, I also have some Shale-related files in my lib directory. Figure 9 is a snapshot of my Rave1WEB-INFlib directory.Figure 9. Files required for working with Spring Web FlowIntegrating SWF with the Course Registration applicationYou’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 workflowLooking 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"> <b><if test="${flowScope.UserBean.webBased}" then="enterWebDetails" else="enterClassDetails" /></b> </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.xmlListing 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.xmlFinally, 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.TransitionsIf 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 handlingSpring 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 conclusionI 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. Open SourceWeb DevelopmentJavaSoftware DevelopmentLibraries and Frameworks