Chapter 6. Spring Faces

6.1. Introduction

Spring Faces is the home of the Spring Web Flow + JSF integration layer, as well as a number of additional value adds specific to a JSF environment. These value adds include:

Unified EL Integration - A separate implementation of the ExpressionParser from Spring Binding that uses the new Unified EL from JSF 1.2 and JSP 2.1. Both JSF 1.1 and 1.2 implementations are provided. This allows for JSF users to use the same expression language in their flow definitions as in their JSF views, and to have access to the full chain of JSF resolvers for expression evaluation.

Client Side Validator Components - A small set of JSF components that work as "advisors" on regular JSF inputText components. These components make use of the rich validation capabilities of the Ext javascript framework.

6.2. Web Flow Java Server Faces (JSF) integration

The Spring Faces module provides strong integration between Spring Web Flow and Java Server Faces (JSF). When used with JSF, Spring Web Flow takes responsibility for view navigation handling and managing model state, adding power and simplicity beyond JSF's default navigation system and object scopes. Plain JSF views and components continue to work just as before, and are able to participate in flows with full access to flow state. In addition, other view technologies such as Facelets continue to plug-in normally.

The JSF integration relies on custom implementations of core JSF artifacts such as the PhaseListener and NavigationHandler to drive the execution of flows. In addition, it relies on custom VariableResolvers to access flow execution attributes from JSF components and to be able to reference any JSF-managed beans using expressions in the Flow Definition.

6.2.1. Adding Spring Web Flow extensions to a JSF application.

Using Spring Web Flow in a JSF environment does not require any additions to your application's faces-config.xml. You just need to have the Spring Faces jar on your classpath and everything will be picked up by JSF automatically. The following classes are automatically configured for you:

The FlowPhaseListener manages the overall flow execution lifecycle in a JSF environment. It handles launching new flows accessed by browsers via direct URLs, and also handles restoring flow executions on postback and browser refreshes.

The FlowNavigationHandler handles selecting the appropriate view in a flow based on an action event outcome from a JSF view participating in the flow. Outcome strings from JSF ActionSource components (i.e., commandButton or commandLink) are treated as events signaled against the current view state of the flow execution.

The DelegatingFlowVariableResolver resolves a JSF value binding expression like #{someBean.someProperty} to a flow execution attribute. This resolver searches flash, flow, and conversation scope in that order until it finds a match. If no match is found, this resolver delegates to the next resolver in the chain. You can take advantage of this in combination with Web Flow's Spring 2.0 custom scopes in order to have on-demand instantiation and configuration of flow-managed beans the first time the expression for such a bean is encountered. This corresponds to the standard behavior of JSF-managed beans.

The DelegatingVariableResolver resolves JSF value binding expressions against the configured Spring Web Application Context. This can be taken advantage of in combination with Web Flow's Spring 2.0 custom scopes in order to have on-demand instantiation and configuration of flow-managed beans the first time the expression for such a bean is encountered. This corresponds to the standard behavior of JSF-managed beans.

6.2.2. Configuring the Web Flow system

The artifacts configured by Spring Faces use Spring to access the Web Flow system configuration. This requires a Spring Web Application Context to be bootstrapped using a ContextLoaderListener in the web.xml deployment descriptor:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/webflow-config.xml
    </param-value>
</context-param>

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

This context should contain the Web Flow system configuration. The example webflow-config.xml below shows a typical Web Flow configuration for a JSF environment:

<?xml version="1.0" encoding="UTF-8"?>	    	
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:flow="http://www.springframework.org/schema/webflow-config"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/webflow-config
           http://www.springframework.org/schema/webflow-config/spring-webflow-config-1.0.xsd">
           	    	
    <!-- Launches new flow executions and resumes existing executions. -->
    <flow:executor id="flowExecutor" registry-ref="flowRegistry">
		<flow:execution-attributes>
			<flow:alwaysRedirectOnPause value="false"/>
		</flow:execution-attributes>
	</flow:executor>

    <!-- Creates the registry of flow definitions for this application -->
    <bean id="flowRegistry" class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
        <property name="expressionParser" ref="jsfExpressionParser"/>
		<property name="flowLocations">
			<list>
				<value>/WEB-INF/flows/**/*-flow.xml</value>
			</list>
		</property>
	</bean>
	
	<!-- Configures the ELExpressionParser for use in place of the default OGNL -->
	<bean id="jsfExpressionParser" class="org.springframework.faces.el.Jsf12ELExpressionParser">
		<constructor-arg >
			<bean class="org.jboss.el.ExpressionFactoryImpl"/>
		</constructor-arg>
	</bean>
    
        
</beans>
	        

A bean named flowExecutor must be configured and linked with a flow definition registry that contains the flows eligible for execution. Note the flowExecutor bean name is significant, as that is bean name the Web Flow JSF extensions will expect.

Any flow executor property such as the flow execution repository type is configurable here, consistent with the other environments Spring Web Flow supports.

A full bean definition is currently required for the XmlFlowRegistryFactoryBean in order to configure it with the Jsf12ELExpressionParser instead of the default OGNL parser. (There is also a Jsf11ExpressionParser for those using JSF 1.1) This expression parser allows JSF developers to use the same expression language in their flow definitions that they are already accustomed to with JSF.

6.2.3. Launching a flow execution - JSF command link component

Flows can be launched by firing JSF action outcomes that adhere to a special format:

<h:commandLink value="Go" action="flowId:myflow"/>
	    	

The command link above says launch 'myflow' when clicked. 'myflow' is expected to be a valid id of a flow definition registered in the configured registry.

6.2.4. Launching a flow execution - normal HTML anchor

Flows can also be launched simply by accessing flow definition URLs directly using a bookmark or normal HTML link:

<a href="app.spring?_flowId=myflow">Go</a>
	    	

This example link assumes *.spring has been mapped to the FacesServlet defined within web.xml.

6.2.5. Flow definitions in a JSF environment

Flow definitions in a JSF environment are just plain Spring Web Flow definitions:

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow
                        http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">

    <var name="myBean" class="example.ManagedBeanImpl" scope="conversation" />
	
    <start-state idref="displayView" />

    <view-state id="displayView" view="/myview.jsp">
        <transition on="submit" to="prepareNextView"/>
    </view-state>
    
    <action-state id="prepareNextView" >
    	<bean-action bean="myService" method="loadMyModel">
    		<method-arguments>
    			<argument expression="#{myBean.foo}"/>
    		</method-arguments>
    	</bean-action>
    	<transition on="success" to="displayNextView"/>
    </action-state>

    <view-state id="displayNextView" view="/mynextview.jsp" />

</flow>				
			

A primary benefit of using JSF is it is a rich UI component framework, and UI components have both data and behavior. As JSF components typically handle data binding and field-level validation behaviors, the actual flow definition logic is often simpler and more focused as a result.

An important difference to note in the above example is the difference in using EL expressions versus Web Flow's traditional OGNL expressions. When using the ELExpressionParser, the chain of configured resolvers will automatically resolve an expression against the correct scope, so the "conversationScope" identifier is not included in the expression when referencing "myBean".

Views selected by view states must follow the standard JSF view identifier format, which requires a leading forward-slash and ends in a suffix such as .jsp or .xhtml.

6.2.6. Resuming a flow execution - form bound to flow execution variables

Views participating in flows are just plain JSF views. They may also incorporate other JSF view technologies such as Facelets and Ajax4JSF.

<f:view>		
    <h:form id="form">
        ...
        <h:inputText id="propertyName" value="#{someBean.someProperty}"/>
        ...
        <h:commandButton type="submit" value="Next" action="submit"/>
    </h:form>
</f:view>		
	    	

As shown above, there is nothing Spring Web Flow specific here. The flow execution key is automatically tracked by a special UI component in the view root, so there is no need to track it manually. Action outcomes are automatically mapped to Spring Web Flow event identifiers signaled against the current state.

6.2.7. Spring Faces JSF Components

Spring Faces provides some lightweight JSF components that act in an "advisor" role to provide rich client-side validation capabilities to standard inputText components. These can be used in place of server-side JSF validators to provide immediate validation feedback to the end user without the overhead of another fine-grained call to the server. These components use the Ext javascript library to provide this validation behavior.

6.2.7.1. Spring Faces Component Configuration

In order for the Spring Faces library to correctly serve the resources from the Ext library, you must have the *.spring extension mapped to the FacesServlet in web.xml.

The Spring Faces components are currently provided as Facelets tags. In order to utilize them, you simply need to add the following namespace declaration to the header of your Facelets view template:

xmlns:sf="http://www.springframework.org/faces"
    	    	

6.2.7.2. Using The Spring Faces Client Side Validation Components

Spring Faces provides three different client-side validator components:

  1. <sf:clientTextValidator> - Provides validation with customizable error messages for text fields.

  2. <sf:clientNumberValidator> - Provides validation and input filtering with customizable error messages for numeric fields.

  3. <sf:clientDateValidator> - Provides validation and a rich popup date picker control with customizable error messages for date fields.

  4. <sf:validateAllOnClick> - When wrapped around a UICommand component such as <h:commandButton> or <h:commandLink> fires all client-side validators when the UICommand component is clicked and prevents the form from being submitted if any of the validations fail.

The validator components must be wrapped around an <h:inputText> component (or any other component that renders an HTML text input). For example, see the following snippet from the Booking sample application:

<sf:clientDateValidator allowBlank="false" msgDisplay="block" msgClass="errors">
	<h:inputText id="checkinDate" value="#{booking.checkinDate}" required="true">
		<f:convertDateTime pattern="MM/dd/yy" timeZone="EST"/>
	</h:inputText>
</sf:clientDateValidator>
    				

In general, each of the available validations has a corresponding sensible default error message. If you want to override the error message, you can do so via the validation's corresponding "Text" attribute. All of the customizable error message attributes are value-binding aware so that you can use expressions to bind to keys in your message bundle if so desired.

A trimmed down version of the Ext javascript library and its corresponding stylesheet will be served automatically by the components in order to provide the validation behavior. If you would like to include Ext yourself in order to take advantage of more features of the library, then all of the components have an includeExtScript and includeExtStyles attribute that can be utilized.

Please refer to the javadocs of the component classes to see all of the attributes for the components.

6.2.8. Spring Web Flow JSF Integration Samples

See the sellitem-jsf sample that illustrates Spring Web Flow operating in a JSF environment.

See the booking-jsf sample that provides a more complex example of Spring Web Flow operating in a JSF environment, including use of flow-managed persistence, Spring 2.0 custom scopes, EL integration, and the client-side JSF validator components of Spring Faces.