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'll learn how to execute flows within Spring MVC, Struts, and Java Server Faces (JSF) based applications.

5.2. FlowExecutor

org.springframework.webflow.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 start(String flowId, ExternalContext context);
        ResponseInstruction signalEvent(String eventId, FlowExecutionKey flowExecutionKey, ExternalContext context);
        ResponseInstruction getCurrentResponseInstruction(Serializable conversationId, ExternalContext context);
    }    	
    	

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

  1. Start a new flow execution.

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

  3. Request that the last response issued by an active conversation be re-issued. Unlike start and signalEvent, this is an idempotent operation that does not affect the state of the flow.

Each operation accepts an ExternalContext that provides normalized access to properties of an external system that has called into Spring Web Flow, allowing access to environment-specific request parameters as well as 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 the context to the specific implementation. The need for such downcasting is considered a special case.

5.2.1. FlowExecutorImpl

The default executor implementation is org.springframework.webflow.executor.FlowExecutorImpl. It allows for configuration of the flow locator responsible for loading the flow definitions to execute, as well as the flow execution repository 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 nameDescriptionCardinalityDefault value
flowLocatorThe service for loading flow definitions to be executed, typically a flow registry1 
repositoryFactoryThe factory for loading repositories to create, save, and restore flow executions1SimpleFlowExecutionRepositoryFactory

5.2.2. A typical flow executor configuration

    <bean id="flowExecutor" class="org.springframework.webflow.executor.FlowExecutorImpl">
        <constructor-arg ref="flowRegistry"/>
    </bean>
		
    <bean id="flowRegistry" class="org.springframework.webflow.registry.XmlFlowRegistryFactoryBean">
        <property name="flowLocations" value="/WEB-INF/flows/**/*-flow.xml"/>
    </bean>
	    	

This instructs Spring to create a flow executor that can execute all XML-based flow definitions contained within the /WEB-INF/flows directory.

5.2.3. A flow executor with a custom repository factory

    <bean id="flowExecutor" class="org.springframework.webflow.executor.FlowExecutorImpl">
        <constructor-arg ref="repositoryFactory"/>
    </bean>

    <bean id="repositoryFactory" class="org.springframework.webflow.execution.repository.continuation.ContinuationFlowExecutionRepositoryFactory">
        <constructor-arg ref="flowRegistry"/>
    </bean>
				
    <bean id="flowRegistry" class="org.springframework.webflow.registry.XmlFlowRegistryFactoryBean">
        <property name="flowLocations" value="/WEB-INF/flows/**/*-flow.xml"/>
    </bean>
	    	

This executor is configured with a continuation-based repository factory, which accesses stateful continuation repositories managed in the user session.

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">
        <constructor-arg 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">
        <constructor-arg 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).

5.4. Flow executor parameterization

Spring Web Flow allows for full control over how flow executor method parameters such as the flowId, flowExecutionKey, eventId, and conversationId are extracted from an incoming controller request with the org.springframework.webflow.executor.support.FlowExecutorParameterExtractor strategy. The default strategy is request-parameter based. Support for request path-based parameter extraction (REST-style URLs) is also provided.

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

5.4.1. Launching a flow execution - parameter-style anchor

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

5.4.2. Launching a flow execution - REST-style anchor

	<a href="flowController/myflow"/>
	    	

5.4.3. Launching a flow execution - form

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

5.4.4. Resuming a flow execution - anchor

    <a href="flowController.htm?_flowExecutionId=${flowExecutionId}&eventId=submit"/>
	    	

The string-encoded _flowExecutionId parameter is parsed into a FlowExecutionKey identity object automatically, using a FlowExecutionKeyFormatter by default.

5.4.5. Resuming a flow execution - form

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

The string-encoded _flowExecutionId parameter is parsed into a FlowExecutionKey identity object automatically, using a FlowExecutionKeyFormatter by default.

5.4.6. Resuming a flow execution - multiple form buttons

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

The string-encoded _flowExecutionId parameter is parsed into a FlowExecutionKey identity object automatically, using a FlowExecutionKeyFormatter by default. The eventId is determined by parsing the parameter name of the button that was pressed.

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, 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 integrates with JSF. The JSF integration relies on custom implementations of core JSF artifacts such as navigation handler and phase listener to drive the execution of flows.

5.6.1. A typical faces-config.xml file

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

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

5.6.2. Launching a flow execution - command link

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

5.6.3. Resuming a flow execution - form

    <h:form id="form">
        ...
        <h:inputText id="propertyName" value="#{flowScope.managedBeanName.propertyName}"/>
        ...
        <input type="hidden" name="_flowExecutionId" value="${flowExecutionId}">
        <h:commandButton type="submit" value="Next" action="submit"/>
    </h:form>
	    	

5.7. Sample applictions

It is recommended that you review the Spring Web Flow sample applications included in the release distribution for best-practice illustrations of the features of this framework. A description of each sample is provided below:

  1. Phonebook - the central sample demonstrating most features (including subflows).

  2. Sellitem - demonstrates a wizard with conditional transitions, conversational scope, and continuations.

  3. Flowlauncher - demonstrates all the possible ways to launch and resume flows.

  4. Itemlist - demonstrates REST-style URLs, conversational redirects, and inline flows.

  5. Shippingrate - demonstrates Spring Web Flow together with Ajax technology.

  6. Birthdate - demonstrates Struts integration and the MultiAction.

  7. Fileupload - demonstrates multipart file upload.

  8. Phonebook-Portlet - the phonebook sample in a Portlet environment (notice how the flow definitions do not change)

  9. Sellitem-JSF - the sellitem sample in a JSF environment (notice how the flow definition does not change)