Managing Web Conversations with Spring Web Flow

helpflightInternet and Web Development

Nov 10, 2013 (3 years and 9 months ago)

124 views


Managing Web Conversations
with Spring Web Flow
Keith Donald
http://www.springframework.com
keith@interface21.com

Agenda

History

Motivation

Positioning

Architecture

Walkthrough

Issues and Solutions

Conclusion

Goals:

Understand Spring’s position in the web
framework space

See the value of Spring Web Flow (SWF) in action

History – From Spring’s
Perspective

Today, Struts is still the web framework
leader in terms of existing application
deployments

Despite well-known limitations

Despite many challengers

The pragmatic majority is still waiting for
the next dominant paradigm to emerge
2000
Struts
Spring MVC
2003
2004
Ervacon
Web Flows
Fall 2005
Unified Spring Web Stack:
Servlet MVC, Portlet MVC,
Web Flow (SWF)

Spring’s Web Stack Motivation

To address the Struts pain points that are
hurting our customers

Spring MVC provides a better architecture
without a high level of paradigm shock

To meet customer demand in places
where it is clear Struts does not provide a
solution

Spring has embarked into new territory

With its customers charting the course

Extracting new “whole products” to form a
complete web stack

Product Positioning

A unified web stack, offering a one stop
shop for agile web application
development

Respecting the existing Struts install base

Spring will continue to provide first class
Struts support

Built from a set of modular components

That can be integrated with other
technologies where customers demand

e.g. SWF is usable by JSF customers as a
NavigationHandler

Spring Clarity™
(Build, Test, Deploy)
Spring Web
Spring Web Stack
Servlet MVC
Portlet MVC
Web Flow
Remoting
Spring Middleware Stack
(IOC, AOP, TX, DAO, ORM, MGMT, JCA)
Each product in the stack integrates a number of components


e.g.

Spring MVC supports JSP, Freemarker, PDF, Jasper, and Excel views


Emerging web components include
Valang
for validation and
DWR
for AJAX

Market Expectations

The current fragmentation in the web
framework market will subside

Consolidation will happen


Spring Web” will be a major player in
the post-shakeout, offering:

Maturity and synergy across the full stack

Low switching costs

Breakthrough technology

Professional support

Breakthrough Technology

Architecture

By example

Take a simple use case:

A wizard for a phone operator to use to
sell items to customers

Characteristics:

An “application transaction” that spans
several steps

Some steps solicit user input

Some steps are decision points

Some steps perform calculations

Navigation from step-to-step is controlled

How would you do this today with
Struts?
1.
Create a session-scoped ActionForm to
hold the wizard form data
2.
Define a JSP for each step
3.
Define an Action for each step
4.
Expose each Action at a request URL
5.
Have the form rendered by the JSP
submit to that URL
6.
At the end, delegate to a business
service to commit the transaction

What this looks like
/step1.do
Controller 1
HTTP
Session
storeForm
page1
/step2.do
Controller 2
page2
updateForm
/lastStep.do
Controller 3
confirmationPage
processTx
Business
Service

Issues with this approach

Request centric: no concept of an ongoing
conversation or flow

Brittle dependency on request URLs

Manual state management

Odd new window behavior

Proper back button behavior is difficult


Loose” controlled navigation

Difficult to observe process lifecycle

Controller and command logic are coupled

Heavily tied to HTTP

Consequences

Many lines of custom code are
written to address these issues

As an application grows more complex
maintainability breaks down

Fundamentally, something is missing

Traditional approaches today lack a key
abstraction:
the Flow

A Flow is typically longer than a single
request but shorter than a session

It is a conversation!

Flow Conversation Analogy
Keith (Oslo, Norway)
Friend (Melbourne, Florida)
Friend: Hello?
Keith:
Hi Friend!
Friend: Hi Keith! So, have you
decided to just stay in Europe
now?
Keith:
Life IS great here, huh?

Keith:
Gotta go, bye!

What the SWF approach looks
like
start “sell Item”
Flow
Execution
Storage
store
firstPage

Sell Item”
FlowExecution
submit
nextPage
submit
confirmationPage
load

Significant architectural
differences

One flow drives the entire conversation

When user input is required, the flow
“pauses” and control returns to the client

Clients “signal” events to tell the flow
what happened

The flow responds to events to decide
what to do next

What to do next is fully encapsulated

Flows are modular “black boxes”

Flow Execution State Transition
Diagram
Created
Active
start
user input
needed
Paused
user event
signaled
Resuming
subflow
spawned
Ending
end

Question
Q: How do you program the Flow?
Q: How does it know what to do in
response to user events?
A: You create a Flow definition

Flow Definition Structure

A Flow definition serves as instructions to
a finite state machine

It consists of a set of states that you
define

Each state executes a polymorphic
behavior when entered

View states solicit user input

Action states execute commands

Subflow states spawn child flows

End states terminate flows

Events you define drive state transitions

The “Sell Item” Flow Definition
start
Enter Price
and Item Count
submit
Select Item
Category
Is Shipping
Required?
Enter Shipping
Information
yes
no
Process Sale
submit
submit
Show
Cost Overview
View State
Action State
Decision State
End State

Code Break!

The real “Sell Item” Flow Definition

Demo of the Flow Execution

Advantages

The logical flow is clearly defined, readable

Navigation rules are encapsulated in one place

No dependency on any request URLs

Navigation is strictly enforced

State management is automatic

Flow lifecycle is fully observable

Controller logic is clearly decoupled from
command logic

The Flow is the controller, deciding what state to
enter next

States execute arbitrary behavior when entered

HTTP independent

Flow definitions are extremely toolable

Walkthrough: Spring Air™

The best way to learn is by example

The airline industry:

Trip booking system

This vertical slice must:
1.
Obtain
Trip Information
2.
Suggest
suitable itineraries
3.
Assign
seats
4.
Collect
passenger information
5.
Book
the trip!

Code Break!

The “Booking Agent” business façade

Subsystem boundary

The model context

The façade integration tests

Expressing the booking flow

Building the Booking Flow Definition

First select a
FlowBuilder
strategy

XML, Java-based, Custom

Perhaps with a supplemental drag ‘n drop
tool

Then create the states of the flow

Define the behavior to happen when each
state is entered

Define the supported transitions from one
state to another

Transitions map the
paths
through the Flow

Code Break!

The Booking Flow Definition

The Booking Flow Action

The Action Unit Tests

The Flow Execution Integration Tests

The View Templates

Application Deployment Configuration

The Booking Flow Definition
<webflow id="booking“

start-state=“displayTripForm">

<! – state definitions go here

</webflow>

Rendering the Trip Form

Display the “trip form” so the user can tell the
flow where she wants to go
<view-state id="displayTripForm" view="tripForm">
<entry>
<action bean="bookingFlowActions" method="setupForm"/>
<action bean="formUtilityActions" method="setupDateChooser"/>
</entry>
<transition on="go" to="suggestItineraries">
<action bean="bookingFlowActions" method="bindAndValidate"/>
</transition>
</view-state>

Suggesting Trip Itineraries

Suggest the best itineraries:
<action-state id="suggestItineraries">
<action bean=“bookingActions"/>
<transition on="success“ to="displaySuggestedItineraries"/>
</action-state>

Action states invoke methods on Actions when
entered

Can also directly invoke methods on POJOs

Example:

Entering “suggestItineraries” invokes the
“suggestItineraries” method on the action
identified by “bookingActions”

The Booking Action
Implementation
public class BookingAction extends FormAction {
private BookingAgent bookingAgent;
private BookingAction(BookingAgent agent) {
setFormObjectName("trip");
setFormObjectClass(Trip.class);
this.bookingAgent = agent;
}
public Event suggestItinenaries(RequestContext context) {
Trip trip = (Trip)context.getFlowScope().getAttribute("trip");
Collection<Itinerary> itineraries =

bookingAgent.suggestItineraries(trip);
context.getFlowScope().setAttribute("itineraries", itineraries);
return success();
}
// other action methods related to the booking process…
public Event book(RequestContext context) {

}
}

Selecting an Itinerary

Display the itineraries and let the customer select one:
<view-state id="displaySuggestedItineraries"
view="suggestedItineraries">
<transition on="startOver" to="cancel"/>
<transition on="select" to=“recordSelectedItinerary"/>
</view-state>
<action-state id=“recordSelectedItinerary">
<action bean=“bookingActions"/>
<transition on="success" to="isPassengerInfoRequired"/>
</action-state>

The flow pauses while the view is displayed – user “think time”

It resumes in the same state on the next request to decide where
to go next

Deciding where to go next

Is passenger information required? If so, enter it. If
not, go straight to verification
<action-state id=“isPassengerInfoRequired”>

<transition on=“yes” to=“enterPassengerInformation”/>

<transition on=“no” to=“displayReservationVerification”/>
</action-state>

A logical decision point: “routing state”

A Decision State could have also been used

Entering Passenger Information

Spawn the “enter passenger information” process as
a subflow, passing it the passenger ID if they have
authenticated
<subflow-state id="enterPassengerInformation"
flow="passenger">
<attribute-mapper>
<input value="${requestScope.passenger.id}“ as=“id”/>
</attribute-mapper>
<transition on="finish" to="displayReservationVerification"/>
</subflow-state>

Note: the parent flow suspends while the subflow
executes. When the subflow ends, the parent
responds to its result.

Finalizing the Reservation

On verification, optionally choose seat assignments. Then book the
reservation!
<view-state id="displayReservationVerification"
view="reservationVerification">
<transition on="startOver" to="cancel"/>
<transition on="assignSeats" to="chooseSeatAssignments"/>
<transition on="book" to="book"/>
</view-state>
<action-state id="book">
<action bean=“bookingFlowActions"/>
<transition on="success" to="displayConfirmation"/>
</action-state>
<end-state id="displayConfirmation" view="reservationConfirmation"/>

The end state terminates the flow when entered

All flow resources are automatically cleaned up

Deploying the Flow
<bean name="/springair.htm“
class="org.springframework.web.flow.mvc.FlowController"/>
<bean id="booking“
class="org.springframework.web.flow.config.XmlFlowFactoryBean">

<property name="location“ value="classpath:/flows/booking.xml"/>
</bean>

One Flow Controller can execute all flows for the
application at a single request URL

The views parameterize the controller with flow
launching information

Security would be at the flow level

Example: views launching flows

Using a form:
<form method=“post” action=“springair.htm”/>
<input type=“text” name=“src.airport”/>

<input type=“text” name=“dest.airport”/>


<input type=“hidden” flowId=“booking”/>

<input type=“submit” value=“Submit”/>
</form>

Using an anchor:
<a href="<c:url
value="/springair.htm?_flowId=booking&src.airport=MLB&
dest.airport=ATL"/>">
Launch Booking Flow
</a>

Examples: views participating in
flows

Using a form:
<form method=“post” action=“springair.htm”/>
<input type=“text” name=“firstName”/>
<input type=“text” name=“lastName”/>


<input type=“hidden” name=“_flowExecutionId”
value=“${flowExecutionId}”/>

<input type=“submit” name=“_eventId_submit”/>
</form>

Using an anchor:
<a href="<c:url
value="/springair.htm?_flowExecutionId=${flowExecutionId}&
_eventId=submit&firstName=Keri&lastName=Donald/>“>Enter
Passenger Information</a>

Each flow is assigned a unique identifier made available to the
views for storage

Issues and Solutions

Browser navigation button use, flow storage and
restoration

A stateful system brings challenges in a stateless
environment

Continuations provide a solution

Server-side session-based storage

Client-side seralization using hidden form field

Custom

Duplicate submits

End States are one answer

Redirects are another
<end-state id=“end”
view=“redirect:springair.html?flowId=anotherFlow”/>

TransactionSynchronizer

Token-based implementation relies on a secure token to be
present on the client and in flow scope

Interface is pluggable

Support for compensating transactions is of high interest to
us: ended flow “rollback”

Issues and Solutions

Responding to the lifecycle of an executing flow

Listeners may be attached to executing flows

Callbacks are made on:

Request submitted – good for pre-flow event processing

Session starting – good for precondition checks

Session started -- good for post condition checks

Paused – good for custom view pre-render logic

Resumed – good for pre-flow event processing

State Entering – good for precondition checks

State Entered – good for post condition checks

Ended – good for custom cleanup logic

Request processed – good for post processing logic

Issues and Solutions

Annotating a Flow with metadata

Any flow definition artifact can be annotated:

Flow

State

Transition

An action’s use in a action state

Example:
<action-state=“book”>

<property name=“role” value=“passenger”
type=“grantedAuthority”/>

<action bean=“bookingAction”>

<property name=“caption” value=“Books the
reservation”/>

</action>
</action-state>

Issues and Solutions

Integrating into other environments

Create a specialized FlowController for
that environment

For example:

The FlowAction for Struts

The FlowNavigationHandler for JSF

The PortletFlowController for Portlets

Spring Web Flow is not coupled with any
other web framework

Not even Spring MVC or the Servlet API

Proven in a Portlet environment

Design Tips

What makes a good Web Flow?

Accomplishes some business goal, e.g.

Book a trip

Pay your taxes

Apply for a Loan

Encapsulates that business goal as a reusable
module

A “black box”

Often has multiple paths to support different
scenarios

Paths may vary based on contextual information

Often spawns other Flows as
sub flows

Has a clear, observable lifecycle: Flow executions start,
events happens, they end


What doesn’t make a good Flow?

Index pages

Welcome Pages

Menus

Simple Form Submissions (Mailers, etc.)

Sites with a lot of free navigation

Web flows are best suited for enforcing
controlled navigation to support business
process workflows

As a compliment to traditional controllers

Don’t abuse them
Design Tips

Spring Web Flow Road Map

JSF integration

JMX-enabled flow management

Ajax support

Asynchronous View State Actions

More configuration defaults

Research in the area of compensating
transactions

Research in the area of asynchronous,
parallel sub flows

Resources and Upcoming Events

www.springframework.org

New CMS portal means we now bring you a lot
more content

Web Flow Wiki provides a “Quick Start”

Practical guide

Articles

Web Flow Ships with 7 sample applications

Phone Book (Core sample)

Sell Item (Wizard with Continuations)

Birth Date (Struts integration)

Item List (Transaction Synchronization)

Number Guess (Example of conversation history)

Flow Launcher (How to launch flows)

File Upload (A flow to upload files)

Resources and Upcoming Events

Public Spring Training

4-day “bootcamps” across North America, Europe

www.springframework.com
/training

The Spring Experience

International conference for agile Java developers

http://www.thespringexperience.com

December 7 – 10
th
, 2005, Sheraton Resort, Bal Harbour
Beach Florida

40+ technical sessions across four tracks: Web, Enterprise,
Process, Beyond J2EE

Featuring

Rod Johnson (Spring Founder, i21 CEO)

Juergen Hoeller (Spring Co-Founder, i21 CTO)

Adrian Colyer (AspectJ Founder, i21 Chief Scientist)

Rob Harrop (Author, Pro Spring)


and many more

Super early bird registration period open now

Think Big: The Spring Experience
2005

Conclusion

Spring is a complete, modular, pragmatic
full-stack application framework

It adds serious value in:

The middle tier

The web tier

Spring 1.3 will be a major upgrade to the
Spring web stack

Spring will continue to innovate

Spring will continue to simplify

Questions?