Transcript Document

Spring Web Flow
Introduction
• Spring Web Flow is a subproject of the popular
Spring Framework
http://www.springframework.org/webflow
Introduction
• Spring Web Flow allows to build high-level,
reusable, self-contained controller modules called
flows that are runnable in any environment
Flows
• A flow defines a user dialog that responds to user
events to drive the execution of application code
to complete a business goal
• Flows are defined
declaratively using a
rich domain-specific
language, like
XML (XSD)
Spring Web Flow
motivation
Motivation [part1 - flow definition]
• Traditionally, defining the UI flow in a web
application has been a less than intuitive process
• Frameworks like Spring
Web MVC force to cut the
UI flow into individual
controllers and views
• Disadvantage: the overall UI flow is not at all
clear from looking at the controller definitions
Motivation [part1 - flow definition]
• The Spring Web MVC offers a slightly higher
level of functionality - form controllers that
implement a predefined work flow:
• SimpleFormController
• AbstractWizardFormController
• However, these are still hard coded examples of a
more general work flow concept
Spring Web Flow
Spring Web Flow solution
• Allows to represent the UI flow in a web
application in a clear and simple way
•
The UI flow is clearly visible by looking at the web
flow definition (XML file)
•
Web Flows can be designed to be self-contained 
modular design and reuse
•
Consistent web flow definition technique 
you're not forced into using specialized controllers
for very particular situations
Motivation [part2 - navigation]
• Typical web application have a mix of
navigation requirements
• Free navigations
• Controlled flows
• Each case bring their own design
challenges
Free navigation
• A set of pages connected by links
•
Accessing a link renders a public resource
• Examples
•
•
Kursa lekciju saraksts:
• http://www.webkursi.lv/java-eim/de/index_lectures_lu.html
Otrais praktiskais darbs:
• http://www.webkursi.lv/java-eim/de/lab_mvc_portal.html
• Users can access resources directly
• Can bookmark or send to a friend
Controlled flows
• A user task that spans more than one request
• The task is the public resource
• Examples
•
•
Registration
E-shop ordering
• Accessing the task URL starts a new “task
execution”
•
Local to the current user’s session
• Intermediate steps of an execution are not
bookmarked
Effect on design
• Free navigation
•
•
Stateless
When invoked:
• Does work
• Selects a view to render
•
All in one request
• A controlled flow is more complex
•
•
•
Stateful
Guides the user through a task with a linear
progression
Renders a view to solicit task input as required
Motivation [part3 - scopes]
• Three different Servlet scopes that dictate
the visibility and location of objects and
attributes that are associated with request
processing:
• Request
• Session
• Application
Request scope
• Has the smallest lifetime
• Is unique to each request from a browser
• Will be discarded when the view is returned to
the browser
• Typically contains data sent from the browser
•
•
browser headings
request parameters
Session scope
• Starts as soon as each unique browser accesses
the server
• Ends if the server hasn’t received a request within
a specified timeout or if explicitly destroyed
• This scope allows objects to live across requests
• Typically contains e.g. information about the
current user
•
•
user details
authentication
Application scope
• Lives for the duration of the web
application deployment
• Contains shared application components
and configuration elements
The problem with scopes
• Many use cases do not fit into the Servlet scopes
• Use case span more than one page but do not
require the longevity of the session
• The Servlet specification is missing the concept
of a conversational scope to support the
execution of use cases that span multiple pages
Use cases and scopes
Session scope?
Why not store everything in the session and
manually perform cleanups when the
conversation ends?
• Server affinity
• Greatly increased memory footprint per user
• Name space clashes
• No vocabulary for process modelling
Spring solution
• Spring Web Flow treats conversational scope as
a first-level citizen
• The core artefact within Spring Web Flow is
the flow (or conversation)
• Conversations can execute in parallel without
intruding on each other
• When the conversation has finished, all
allocated resources are automatically cleaned up
Spring Web Flow
characteristics
Spring Web Flow characteristics
• Implementation agnostic
• Abstracted away from the Servlet
specification
• Nothing web-specific about a flow definition
• Developer is not presented with an
HttpServletRequest or an
HttpServletResponse
Spring best practices
• Develop against interfaces  plug in the most
appropriate implementation
• Favor integration with established technologies
• Allow reusability from within other established
web frameworks
•
Integrates with Struts, JSF and Portlet MVC
• Facilitate test-driven development
Spring Web Flow characteristics
• Low adoption overhead
• SWF is self-contained  little impact when
introducing it on existing projects
• Spring Web Flow is another Controller
tool in the MVC toolbox
• A major design goal of Spring Web Flow
was to do one thing and do it well
Spring Web Flow
architectural overview
Integration options
•
Spring Web Flow is very self-contained 
the entry points to other frameworks are consistent
Inside the SWF System
• A central FlowExecutionManager façade is
responsible for launching executions of flows on
behalf of clients
• Flow executions = new user conversations with
the server
• Each conversation is given its own local data
structure, called flow scope
Where is flow scope stored?
• Flow scope is stored in a repository
• A number of repository implementations to support
different usage scenarios:
•
SimpleFlowExecutionRepository
•
ContinuationFlowExecutionRepository
•
ClientContinuationFlowExecutionRepository
http://en.wikipedia.org/wiki/Continuation
Building Blocks
• With Spring Web Flow, the primary challenge for
developers is the design and implementation of a
flow definition
• Web flow is composed of a set of states
• Each state has one or more transitions that
are used to move to another state
• A transition is triggered by an event
Flows
• A flow defines a conversation, or dialogue,
between users and the server
States
The steps of a flow are called states.
Five core types of states:
1. Action state
•
Executes application code, typically delegating to a
business service in the middle tier
2. View state
•
Renders a view allowing the user to participate in the
flow by entering data or viewing a message
States
3. Subflow state
• Spawns another flow as a subflow
4. Decision state
• Evaluates a condition to drive a transition to a
new state
5. End state
• Terminates a flow
Transitions
• All states (except end states) are transtionable and
maintain a set of one or more transitions that
define “allowed paths” to other states
• A transition is triggered on the occurrence of an
event
Events
• Nothing more than “something that happens”
within a state
• An event is treated as a state outcome that
captures the logical result of a state’s execution
• From the previous slide:
•
•
The “submit” event communicates that a submit
button was pressed as the outcome of a view state
The “yes” event communicates that a “true” result
was returned when evaluating a condition as the
outcome of a decision state
Deterministic finite automata
http://www.u.arizona.edu/~miller/webthesis/mthesis/node8.html
Sample Application
Sample Application - Phonebook
•
•
Allows to locate an employee of the company using
some search criteria
Once the right person is found, it is possible to
consult detailed information (phone, colleagues)
http://www.ervacon.com/products/swf/intro/index.html
Sources and deployed sample
Sources:
\spring-webflow-1.0.5\projects\spring-webflow-samples\phonebook
Deployed sample:
http://spring.ervacon.com/swf-phonebook/
Phonebook domain objects
• Person - A simple JavaBean containing person details
• SearchCriteria - A query object representing a search in
the phonebook
• SearchCriteriaValidator - A validator to validate a
SearchCriteria object
• Phonebook - Main business facade interface
•
•
public List<Person> search(SearchCriteria criteria);
•
public Person getPerson(Long id);
The StubPhonebook implementation of the Phonebook
interface just hard-codes some dummy data
Spring Web MVC Setup
Need to configure /WEB-INF/web.xml
1. ContextLoaderListener - initializes the
Spring Framework when web application is
loaded by the servlet engine
2. DispatcherServlet - handles all requests
matching the URL pattern *.htm
ContextLoaderListener
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:org/springframework/webflow/samples/phonebook/stub
/services-config.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
The root application context will be loaded from the
services-config.xml classpath resource
services-config.xml
The root web application context, defined in
services-config.xml configures business facade:
the phonebook bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="phonebook" class="org.springframework.webflow.
samples.phonebook.stub.StubPhonebook"/>
</beans>
DispatcherServlet
<servlet>
<servlet-name>phonebook</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/phonebook-servlet-config.xml
/WEB-INF/phonebook-webflow-config.xml
</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>phonebook</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
ViewResolver
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="viewResolver"
class="org.springframework.web.servlet.
view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
Spring Web MVC
is configured!
Next let’s integrate
Spring Web Flow!
The Web Flow Controller
• The component that does integration is:
org.springframework.webflow.executor.mvc.
FlowController
• This controller will handle all things Web Flow on
behalf of the application
• Configure in phonebook-servlet-config.xml:
<bean name="/phonebook.htm" class=
"org.springframework.webflow.executor.mvc.FlowController">
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
Flow executor
• All flow execution management responsibilities
will be delegated to flow executor
• phonebook-webflow-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ... >
<flow:executor id="flowExecutor"
registry-ref="flowRegistry"/>
<flow:registry id="flowRegistry">
<flow:location
path="/WEB-INF/flows/**-flow.xml"/>
</flow:registry>
</beans>
Flow registry
• The flow registry will load flows from XML files
found in the /WEB-INF/flows/ directory that
have the -flow.xml suffix
• The search flow defined in search-flow.xml
will be assigned the id search-flow
• The detail flow defined in detail-flow.xml
will receive the id detail-flow
Request parameters
• Web Flow controller is invoked by the dispatcher
servlet to handle a request
• It examines the following request parameters to
determine what to do:
• _flowId
• _flowExecutionKey
• _eventId
_flowId
• Id of a flow for which a new execution should be
launched
• Possible values in a sample application are
• search-flow and detail-flow
• If "_flowExecutionKey" parameter is not present,
the flow controller launches a new flow execution
• The new execution will be assigned a unique key
<a href="phonebook.htm?_flowId=search-flow">Phonebook</a>
_flowExecutionKey
• The unique id of an ongoing flow execution
• When present in a request, the flow controller
will restore the ongoing flow execution and
resume it
• The flow execution key is available in the request
outcome model using the name "flowExecutionKey”
<input type="hidden"
name="_flowExecutionKey“ value="${flowExecutionKey}"/>
_eventId
• The event that will be triggered in the current
state of the flow
• Is required when accessing an ongoing flow
execution
• Not used when launching a new flow execution
<input type="submit" class="button"
name="_eventId_search" value="Search"/>
Now all the
infrastructure is in place!
Let's look at Web Flows and
what they can do for us!
Web Flow schema
• Technically, a Web Flow is nothing more than an
XML file representation of the UI flow
• Schema reference to indicate that an XML file
contains a Web Flow definition:
<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">
Web Flow states
• The Web Flow schema defines that a flow is
composed of a set of states
• Each state will have a unique id in the flow
• Supported state types:
•
•
•
•
•
•
start-state
action-state
view-state
decision-state
subflow-state
end-state
Event signaling
The way a state signals events depends on the state type
• View state
•
Event is based on user input submitted to the controller
using the "_eventId" request parameter
• Action state
•
The executed actions signal events
• Subflow state
•
Event is based on the outcome of the subflow they
spawned
Search Flow (initial version)
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns=...>
<start-state idref="enterCriteria"/>
<view-state id="enterCriteria" view="searchCriteria">
<transition on="search" to="displayResults"/>
</view-state>
<view-state id="displayResults" view="searchResults">
<transition on="newSearch" to="enterCriteria"/>
<transition on="select" to="...detail module..."/>
</view-state>
</flow>
Note: flow does not define an end state!
Detail Flow (initial version)
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns=...>
<start-state idref="displayDetails" />
<view-state id="displayDetails" view="details">
<transition on="back" to="finish" />
<transition on="select" to="...detail module..." />
</view-state>
<end-state id="finish" />
</flow>
In this case there is an end state since we need to end this
flow and return to the calling flow when going back
Views
•
Web Flow definitions reference three views:
•
"searchCriteria“

/WEB-INF/jsp/searchCriteria.jsp
•
"searchResults"

/WEB-INF/jsp/searchResults.jsp
•
"details“

/WEB-INF/jsp/details.jsp
•
Implementing SWF views is similar to any other Spring
Web MVC application
•
The point of interest is linking back to the flow controller
and signaling an event
searchCriteria.jsp
<form:form commandName="searchCriteria" method="post">
<table>
<tr><td>Search Criteria</td></tr><tr><td colspan="2"><hr/></td></tr>
<spring:hasBindErrors name="searchCriteria">
<tr><td colspan="2">
<div class="error">Please provide valid search criteria</div>
</td></tr>
</spring:hasBindErrors>
<tr><td>First Name</td><td><form:input path="firstName" /></td></tr>
<tr><td>Last Name</td><td><form:input path="lastName" /></td></tr>
<tr><td colspan="2"><hr/></td></tr>
<tr><td colspan="2" class="buttonBar">
<input type="hidden"
name="_flowExecutionKey" value="${flowExecutionKey}"/>
<input type="submit"
class="button" name="_eventId_search" value="Search"/>
</td></tr>
</table>
</form:form>
Views (continued)
• The "searchResults" view and the "details" view are
very similar
• Example from the "details" view that uses an anchor
to submit the "select" event in the detail-flow
<a href="phonebook.htm?
_flowExecutionKey=${flowExecutionKey}&
_eventId=select&
id=${colleague.id}">
${colleague.firstName} ${colleague.lastName}<br/>
</a>
Actions
• So far Web Flows just navigate between pages
• To do some actual processing in a Web Flow, we
need actions
• Typical form processing:
•
•
Pre-render logic: prepare form before display (load)
Submit or postback logic: actions than need to be
executed on submit (bind, validate)
• “Backing form object” object that will be edited
in the form
Action interface
• An action is a Java class implementing the
org.springframework.webflow.execution.Action
interface
public interface Action {
public Event execute(RequestContext context) throws Exception;
}
• Out-of-the-box action with HTML form handling
functionality:
org.springframework.webflow.action.FormAction
Action Execution Points
• Action can be executed at the following points
within the flow life cycle:
•
On flow start
•
On flow end
•
On state enter
•
On state exit
•
Before transition
FormAction
• Functionality is similar to the Spring
BaseCommandController
•
Methods:
•
setupForm()
• prepare the Spring form handling machinery to
properly display the form
•
bindAndValidate()
• bind incoming request parameters to the form
backing object and validate them
Adding actions to enterCriteria state
<flow ...>
....
<view-state id="enterCriteria" view="searchCriteria">
<render-actions>
<action bean="formAction" method="setupForm"/>
</render-actions>
<transition on="search" to="displayResults">
<action bean="formAction" method="bindAndValidate"/>
</transition>
</view-state>
...
<import resource="search-flow-beans.xml"/>
</flow>
Need to configure “formAction” bean in search-flow-beans.xml
formAction bean configuration
<beans xmlns=...>
<bean id="formAction"
class="org.springframework.webflow.action.FormAction">
<property name="formObjectClass"
value="org.springframework.
webflow.samples.phonebook.SearchCriteria"/>
<property name="validator">
<bean class="org.springframework.webflow.samples.
phonebook.SearchCriteriaValidator"/>
</property>
</bean>
</beans>
•
By default the form action will:
•
•
store the form backing object in flow scope
assign it a name based on the class name: "searchCriteria"
Form backing object
is configured!
Next need to invoke service
to perform the search!
Invoking service method
• Spring Web Flow allows to directly call methods on
any Spring managed bean from inside a Web Flow
<view-state id="displayResults" view="searchResults">
<render-actions>
<bean-action bean="phonebook" method="search">
<method-arguments>
<argument expression="flowScope.searchCriteria"/>
</method-arguments>
<method-result name="results"/>
</bean-action>
</render-actions>
<transition on="newSearch" to="enterCriteria"/>
<transition on="select" to="...detail module..."/>
</view-state>
Subflows
• While the subflow is active, execution of the
parent flow session is suspended and the subflow
handles all requests
• When the subflow reaches an end state, execution
continues in the parent flow
• The event signalled to continue the parent flow is
the id of the end state that was reached in the
subflow
Sample application subflows
• There are two modules:
•
search module and a detail module
•
Search flow will use the detail flow as a subflow to
show person details
•
Detail flow will also use itself as a subflow to show
colleague details
• Detail flow is packaged as a reusable web
application module  can be reused easily
Subflow definition in search flow
<flow xmlns=...>
...
<view-state id="displayResults" view="searchResults">
...
<transition on="select" to="browseDetails"/>
</view-state>
<subflow-state id="browseDetails" flow="detail-flow">
<attribute-mapper>
<input-mapper>
<mapping source="requestParameters.id"
target="id" from="string" to="long"/>
</input-mapper>
</attribute-mapper>
<transition on="finish" to="displayResults"/>
</subflow-state>
...
</flow>
Detail flow definition
<flow xmlns=...>
<input-mapper>
<input-attribute name="id"/>
</input-mapper>
...
<view-state id="displayDetails" view="details">
...
<transition on="select" to="browseColleagueDetails" />
</view-state>
<subflow-state id="browseColleagueDetails" flow="detail-flow">
<attribute-mapper><input-mapper>
<mapping source="requestParameters.id" target="id"
from="string" to="long" />
</input-mapper></attribute-mapper>
<transition on="finish" to="displayDetails" />
</subflow-state>
...
</flow>
Attribute mapper
• Map model data from a parent flow to a subflow
and back again
• Mapping data to the subflow happens before the
subflow session is started
• Mapping data back is done when the subflow
completes and the parent flow session resumes
Sample application
COMPLETED!
Unit testing the flow execution
• Spring Web Flow provides flow unit testing
support classes
• This support includes
•
Convenient base classes for implementing flow
execution tests
• AbstractXmlFlowExecutionTests
•
Mock implementations of core Web Flow constructs
such as the RequestContext to support unit
testing flow artifacts such as Actions in isolation
Example: flow unit test
public class SearchFlowExecutionTests extends
AbstractXmlFlowExecutionTests {
@Override
protected FlowDefinitionResource getFlowDefinitionResource() {
return createFlowDefinitionResource(
"src/main/webapp/WEB-INF/flows/search-flow.xml");
}
public void testStartFlow() {
ApplicationView view = applicationView(startFlow());
assertCurrentStateEquals("enterCriteria");
assertViewNameEquals("searchCriteria", view);
assertModelAttributeNotNull("searchCriteria", view);
}
...
}
Spring IDE Web Flow Visualizer
• The Spring IDE Web Flow support allows
developers to edit XML-based flow definitions
graphically
• Phonebook flow visualized
with the Spring IDE Web Flow
editor:
http://www.springframework.org/node/429
Spring IDE Web Flow Visualizer
• Auto-complete for state identifiers
http://www.springframework.org/node/429
Spring IDE Web Flow Visualizer
• Auto-complete for beans in web and application
service layers
http://www.springframework.org/node/429
Conclusion
• Spring Web Flows important benefits:
•
•
•
•
•
capture the UI flow in a clear and easily readable way
provide a consistent manner to model navigation
throughout a web application
handle all navigational control, making sure
applications works correctly even when the user uses
back/refresh
allow to package a part of a web application as a selfcontained, reusable module
offer sophisticated state management, providing
several new scopes for conversation related data
References
• Spring Web Flow Home
http://www.springframework.org/webflow
• Spring Web Flow - A Practical Introduction
http://www.ervacon.com/products/swf/intro/index.html
• Book “Expert Spring MVC and Web Flow”
http://www.amazon.com/Expert-Spring-MVC-WebFlow/dp/159059584X
• Spring IDE Web Flow Visualizer
http://www.springframework.org/node/429