Chapter 5. Flow executors

5.1. Introduction

Flow executors are the highest-level entry points into the Spring Web Flow system, responsible for driving the execution of flows across a variety of environments.

In this chapter, you will learn how to execute flows within Spring MVC, Struts, and Java Server Faces (JSF) based applications.

5.2. FlowExecutor

org.springframework.webflow.executor.FlowExecutor is the central facade interface external systems use to drive the execution of flows. This facade acts as a simple, convenient service entry-point into the Spring Web Flow system that is reusable across environments.

The FlowExecutor interface is shown below:

    public interface FlowExecutor {
        ResponseInstruction launch(String flowDefinitionId, ExternalContext context);
        ResponseInstruction resume(String flowExecutionKey, String eventId, ExternalContext context);
        ResponseInstruction refresh(String flowExecutionKey, ExternalContext context);
    }    	
    	

As you can see there are three central use-cases fulfilled by this interface:

  1. Launch (start) a new execution of a flow definition.

  2. Resume a paused flow execution by signaling an event against its current state.

  3. Request that the last response issued by a flow execution be re-issued. Unlike start and signalEvent, the refresh operation is an idempotent operation that does not change the state of a flow execution.

Each operation accepts an ExternalContext that provides normalized access to properties of an external system that has called into Spring Web Flow. This context allows access to environment-specific request parameters as well as externally-managed request, session, and application-level attributes.

Each operation returns a ResponseInstruction, which the calling system is expected to use to issue a suitable response.

These relationships are shown graphically below:

Flow executor

As you can see, an ExternalContext implementation exists for each of the environments Spring Web Flow supports. If a flow artifact such as an Action needs to access native constructs of the calling environment it can downcast a context to its specific implementation. The need for such downcasting is considered a corner case.

5.2.1. FlowExecutorImpl

The default executor implementation is org.springframework.webflow.executor.FlowExecutorImpl. It allows for configuration of a FlowDefinitionLocator responsible for loading the flow definitions to execute, as well as the FlowExecutionRepository strategy responsible for persisting flow executions that remain active beyond a single request into the server.

The configurable FlowExecutorImpl properties are shown below:

Table 5.1. FlowExecutorImpl properties

Property nameDescriptionCardinality
definitionLocatorThe service for loading flow definitions to be executed, typically a FlowDefinitionRegistry1
executionFactoryThe factory for creating new flow executions.1
executionRepositoryThe repository for saving and loading persistent (paused) flow executions1

5.2.2. A typical flow executor configuration with Spring 2.0

    <?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"/>

        <!-- Creates the registry of flow definitions for this application -->
        <flow:registry id="flowRegistry">
            <flow:location path="/WEB-INF/flows/**/*-flow.xml"/>
        </flow:registry>
        
    </beans>
	        

This instructs Spring to create a flow executor that can execute all XML-based flow definitions contained within the /WEB-INF/flows directory. The default flow execution repository, continuation, is used.

5.2.3. A flow executor using a simple execution repository

    <flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="simple"/>
	    	

This executor is configured with a simple repository that manages execution state in the user session.

5.2.4. A flow executor using a client-side continuation-based execution repository

    <flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="client"/>
	    	

This executor is configured with a continuation-based repository that serializes continuation state to the client using no server-side state.

5.2.5. A flow executor using a single key execution repository

    <flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="singleKey"/>>
	    	

This executor is configured with a simple repository that assigns a single flow execution key per conversation. The key, once assigned, never changes for the duration of the conversation.

5.2.6. A flow executor setting custom conversation management attributes

    <flow:executor id="flowExecutor" registry-ref="flowRegistry">
        <flow:repository type="continuation" max-conversations="5" max-continuations="30" conversation-manager-ref="conversationManager"/>
    </flow:executor>

    <bean id="conversationManager" class="example.MyCustomConversationalStateManager"/>
	    	

This executor is configured with a continuation repository configured with custom settings for:

  1. The maximum number of active conversations per user session (5)

  2. The maximum number of restorable flow execution snapshots (continuations) per conversation (30)

  3. Where conversational state will be stored (via a custom conversationManager)

The flow:repository child element is the more flexible form for configuring the flow execution repository. Use it or the convenient repository-type attribute, not both.

5.2.7. A flow executor setting system execution attributes

    <flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="continuation">
        <flow:execution-attributes>
            <flow:alwaysRedirectOnPause value="false"/>
            <flow:attribute name="foo" value="bar"/>
        </flow:execution-attributes>
    </flow-executor>
			

This executor is configured to set two flow execution system attributes alwaysRedirectOnPause=false and foo=bar.

[Note]Note

The alwaysRedirectOnPause attribute determines if a flow execution redirect occurs automatically each time an execution pauses (automated POST+REDIRECT+GET behavior). Setting this attribute to false will disable the default 'true' behavior.

5.2.8. A flow executor setting custom execution listeners

    <flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="continuation">
        <flow:execution-listeners>
            <flow:listener ref="listener" criteria="order-flow"/>
        </flow:execution-listeners>
    </flow-executor>

    <!-- A FlowExecutionListener to observe the lifecycle of order-flow executions -->
    <bean id="listener" class="example.OrderFlowExecutionListener"/>
			

This executor is configured to apply the execution listener to the "order-flow".

5.2.9. A Spring 1.2 compatible flow executor configuration

    <?xml version="1.0" encoding="UTF-8"?>	    	
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
	    "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    
        <!-- Launches new flow executions and resumes existing executions: Spring 1.2 config version -->
        <bean id="flowExecutor" class="org.springframework.webflow.config.FlowExecutorFactoryBean">
            <property name="definitionLocator" ref="flowRegistry"/>
            <property name="executionAttributes">
                <map>
                    <entry key="alwaysRedirectOnPause">
                        <value type="java.lang.Boolean">false</value>
                    </entry>
                </map>
            </property>
            <property name="repositoryType" value="CONTINUATION"/>
        </bean>
        
        <!-- Creates the registry of flow definitions for this application: Spring 1.2 config version -->
        <bean id="flowRegistry"
           class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
            <property name="flowLocations">
                <list>
                    <value>/WEB-INF/flows/**/*-flow.xml</value>
                </list>
            </property>
        </bean>
	
    </beans>
	        

This achieves similar semantics as the Spring 2.0 version above. The 2.0 version is more concise, provides stronger validation, and encapsulates internal details such as FactoryBean class names. The 1.2 version is Spring 1.2 or > compatible and digestable by Spring IDE 1.3.

5.3. Spring MVC integration

Spring Web Flow integrates with both Servlet and Portlet MVC which ship with the core Spring Framework. Use of Portlet MVC requires Spring 2.0.

For both Servlet and Portlet MVC, a FlowController acts as an adapter between Spring MVC and Spring Web Flow. As an adapter, this controller has knowledge of both systems and delegates to a flow executor for driving the execution of flows. One controller typically executes all flows of an application, relying on parameterization to determine what flow to launch or what flow execution to resume.

5.3.1. A single flow controller executing all flows in a Servlet MVC environment

    <bean name="/flowController.htm" class="org.springframework.webflow.executor.mvc.FlowController">
        <property name="flowExecutor" ref="flowExecutor"/>
    </bean>
	    	

This controller, exported at the context-relative /flowController.htm URL, delegates to the configured flow executor for driving flow executions in a Spring Servlet MVC environment.

5.3.2. A single portlet flow controller executing a flow within a Portlet

    <bean id="portletModeControllerMapping"
             class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
        <property name="portletModeMap">
            <map>
                <entry key="view" value-ref="flowController"/>
            </map>
        </property>
    </bean>

    <bean id="flowController" class="org.springframework.webflow.executor.mvc.PortletFlowController">
        <property name="flowExecutor" ref="flowExecutor"/>
        <property name="defaultFlowId" ref="search-flow"/>
    </bean>
	    	

This controller, exported for access with the configured portlet mode, delegates to the configured flow executor for driving flow executions in a Spring Portlet MVC environment (by default, an execution of the search-flow will be launched).

5.4. Flow executor parameterization

Spring Web Flow allows for full control over how flow executor method arguments such as the flowDefinitionId, flowExecutionKey, and eventId are extracted from an incoming controller request with the org.springframework.webflow.executor.support.FlowExecutorArgumentExtractor strategy.

The next several examples illustrate strategies for parameterizing flow controllers from the browser to launch and resume flow executions:

5.4.1. Request parameter-based flow executor argument extraction

The default executor argument extractor strategy is request-parameter based. The default request parameters are:

Table 5.2. Extractor request parameter names

Parameter nameDescription
_flowIdThe flow definition id, needed to launch a new flow execution.
_flowExecutionKeyThe flow execution key, needed to resume and refresh an existing flow execution.
_eventIdThe id of an event that occured, needed to resume an existing flow execution.

5.4.1.1. Launching a flow execution - parameter-style anchor

	<a href="flowController.htm?_flowId=myflow">Launch My Flow</a>
		    	

5.4.1.2. Launching a flow execution - form

    <form action="flowController.htm" method="post">
        <input type="submit" value="Launch My Flow"/>
        <input type="hidden" name="_flowId" value="myflow">
    </form>
	    		

5.4.1.3. Resuming a flow execution - anchor

    <a href="flowController.htm?_flowExecutionKey=${flowExecutionKey}&_eventId=submit">
        Submit
    </a>
	    		

5.4.1.4. Resuming a flow execution - form

    <form action="flowController.htm" method="post">
        ...
        <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}">
        <input type="hidden" name="_eventId" value="submit"/>
        <input type="submit" class="button" value="Submit">
    </form>
		    	

5.4.1.5. Resuming a flow execution - multiple form buttons

    <form action="flowController.htm" method="post">
        ...
        <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}">
        <input type="submit" class="button" name="_eventId_submit" value="Submit">
        <input type="submit" class="button" name="_eventId_cancel" value="Cancel">
    </form>
		    	
[Note]Note

In this case, the eventId is determined by parsing the name of the button that was pressed.

5.4.1.6. Refreshing a flow execution

    <a href="flowController.htm?_flowExecutionKey=${flowExecutionKey}">Refresh</a>
	    		

5.4.2. Request path based flow executor argument extraction

The request-path based argument extractor strategy relies on executor arguments being path elements as much as possible. This results in friendlier REST-style URLs such as http://host/app/myflow, instead of http://host/app?_flowId=myflow.

5.4.2.1. A flow controller with a request-path based argument extractor

    <bean name="/flowController.htm" class="org.springframework.webflow.executor.mvc.FlowController">
        <property name="flowExecutor" ref="flowExecutor"/>
        <property name="argumentHandler">
            <bean class="org.springframework.webflow.executor.support.RequestPathFlowExecutorArgumentHandler"/>
        </property>        
    </bean>
		    	

5.4.2.2. Launching a flow execution - REST-style anchor

	<a href="flowController/myflow"/>Launch My Flow</a>
		    	

5.4.2.3. Resuming a flow execution - multiple form buttons

    <form action="${flowExecutionKey}" method="post">
        ...
        <input type="submit" class="button" name="_eventId_submit" value="Submit">
        <input type="submit" class="button" name="_eventId_cancel" value="Cancel">
    </form>
		    	

5.4.2.4. Refreshing a flow execution

    <a href="flowController/k/${flowExecutionKey}">Refresh</a>
	    		

5.5. Struts integration

Spring Web Flow integrates with Struts 1.x or >. The integration is very similiar to Spring MVC where a single front controller (FlowAction) drives the execution of all flows for the application by delegating to a configured flow executor.

5.5.1. A single flow action executing all flows

    <form-beans>
        <form-bean name="actionForm" type="org.springframework.web.struts.SpringBindingActionForm"/>
    </form-beans>
	    	
    <action-mappings>
        <action path="/flowAction" name="actionForm" scope="request"
                type="org.springframework.webflow.executor.struts.FlowAction"/>
    </action-mappings>
	    	

5.6. Java Server Faces (JSF) integration

Spring Web Flow provides strong integration with 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 to 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 a custom VariableResolver to access flow execution attributes from JSF components.

5.6.1. Adding Spring Web Flow extensions to faces-config.xml

Using Spring Web Flow in a JSF environment requires adding these custom artifacts to the application's faces-config.xml file:

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

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

The FlowPhaseListener is required to manage 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 is required to continue a flow on an action outcome from a JSF view participating in the flow. Outcome strings are treated as events signaled against the current view state of the flow execution automatically.

The DelegatingFlowVariableResolver resolves JSF a 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.

5.6.2. Configuring the Web Flow system

The artifacts defined in the faces-config.xml 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"/>

    <!-- Creates the registry of flow definitions for this application -->
    <flow:registry id="flowRegistry">
        <flow:location path="/WEB-INF/flows/**/*-flow.xml"/>
    </flow:registry>
        
</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.

5.6.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.

[Tip]Tip

By default, an action outcome prefixed with flowId: will be treated as a flow definition identifier. The flow id prefix respected by the FlowNavigationHandler is configurable. See the API documentation for more information.

5.6.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.faces?_flowId=myflow">Go</a>
	    	

This example link assumes *.faces has been mapped to the FacesServlet defined within web.xml. The format of a flow definition URL is configurable on the FlowPhaseListener.

5.6.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="displayNextView"/>
    </view-state>

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

</flow>				
			

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

In general, it is recommended views selected by view states follow the standard JSF view identifier format, which requires a leading forward-slash and ends in a prefix. How Spring Web Flow view names are mapped to JSF view ids is configurable. See the FlowPhaseListener API documentation for more information.

5.6.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.

5.6.7. Spring Web Flow JSF Integration Samples

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

5.6.8. A pre Spring Web Flow 1.0.2 faces-config.xml file

[Note]Note

The following three sections apply only to those using Spring Web Flow's JSF integration before release 1.0.2.

Before release 1.0.2, Spring Web Flow only supported resolving variables in flow scope (and not the other scopes such as flash and conversation shown above). This configuration is still supported for backwards compatibility reasons:

<faces-config>
    <application>
        <navigation-handler>org.springframework.webflow.executor.jsf.FlowNavigationHandler</navigation-handler>
        <variable-resolver>org.springframework.webflow.executor.jsf.FlowVariableResolver</variable-resolver>
        <property-resolver>org.springframework.webflow.executor.jsf.FlowPropertyResolver</property-resolver>
    </application>

    <lifecycle>
        <phase-listener>org.springframework.webflow.executor.jsf.FlowPhaseListener</phase-listener>
    </lifecycle>
</faces-config>
	    	
[Note]Note

With 1.0.2 DelegatingFlowVariableResolver is now the recommended default resolver, as it allows full access to all flow execution scopes transparently from the point of view of the JSF view developer.

5.6.9. A pre Spring Web Flow 1.0.2 Web Flow system configuration

Before release 1.0.2, Spring Web Flow did not support the configuration of a flowExecutor in a JSF environment. Those who needed to customize Web Flow services such as the flow execution repository or registry deployed those beans individually with special bean names. This configuration is still supported for backwards compatability reasons. However, it is recommended that existing users of Spring Web Flow's JSF integration use the standard <flow:executor/> tag in the webflow-config namespace for consistency and simplicity.

5.6.10. Resuming a flow execution - pre Spring Web Flow 1.0.2

Before release 1.0.2, the flow execution key had to be tracked manually in JSF views participating in a flow execution. This configuration is still supported for backwards compatibility reasons. However, it is highly recommended that existing users of Spring Web Flow's JSF integration update their views to be just plain JSF.

<f:view>
    <h:form id="form">
        ...
        <h:inputText id="propertyName" value="#{flowScope.aFlowScopeAttribute}"/>
        ...
        <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}">
        <h:commandButton type="submit" value="Next" action="submit"/>
    </h:form>
</f:view>
	    	

The hidden form field above can now be safely removed. In addition, the new variable resolver can be plugged in to gain access to other scopes such as flash and conversation.