reference manual updates
60
spring-webflow/docs/reference/src/defining-flows.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="defining-flows">
|
||||
<title>Defining Flows</title>
|
||||
<sect1 id="introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
This chapter begins the Users Section of this guide.
|
||||
It shows how to implement flows using the flow definition language.
|
||||
By the end of this chapter, you should have a good understanding of language constructs and capable of authoring a flow definition.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="flow-overview">
|
||||
<title>What is a Flow?</title>
|
||||
<para>
|
||||
A flow encapsulates a reusable sequence of steps that can execute in different contexts.
|
||||
Below is a <ulink url="http://www.jjg.net/ia/visvocab/">Garrett Information Architecture</ulink> diagram illustrating a reference to a flow that encapsulates the steps of a hotel booking process:
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/hotels-site.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/hotels-site.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>A BookHotel Flow Definition</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</sect1>
|
||||
<sect1 id="flow-makeup">
|
||||
<title>What is the makeup of a typical Flow?</title>
|
||||
<para>
|
||||
In Spring Web Flow, a flow consists of a series of steps called "states".
|
||||
Entering a state typically results in a page being displayed to the user.
|
||||
On the page, user events occur that are handled by that state.
|
||||
These events can trigger transitions to other states which result in page navigations.
|
||||
</para>
|
||||
<para>
|
||||
The example below shows the structure of the book hotel flow referenced in the previous diagram:
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/hotels-site-bookhotel-flow.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/hotels-site-bookhotel-flow.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>Hotels Site Diagram that references a "Book Hotel" flow</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</sect1>
|
||||
<sect1 id="flow-definition">
|
||||
<title>How are Flows authored?</title>
|
||||
<para>
|
||||
Flows are authored by web application developers using a XML-based flow definition language.
|
||||
The next steps of this guide will walk you through the elements of this language.
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
@@ -1,247 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="flow-execution-repository">
|
||||
<title>Flow execution repositories</title>
|
||||
<sect1 id="repository-intro">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
A flow execution represents an executing flow <emphasis>at a point in time</emphasis>.
|
||||
At runtime there can be any number of flow executions active in parallel. A single user
|
||||
can even have multiple executions active at the same time (for example, when a user is
|
||||
operating multiple windows or tabs within their browser).
|
||||
</para>
|
||||
<para>
|
||||
Many of these flow executions span multiple requests into the server and therefore
|
||||
must be saved so they can be resumed on subsequent requests. This presents technical
|
||||
challenges, as there must exist a stable mechanism for a new request to be associated
|
||||
with an existing execution in the view state that matches what the user expects. This problem
|
||||
is more difficult when you consider that many applications require use of browser
|
||||
navigational buttons, and use of these buttons involves updating local history without
|
||||
notifying the server.
|
||||
</para>
|
||||
<para>
|
||||
The problem of flow execution persistence is addressed by Spring Web Flow's <emphasis>flow
|
||||
execution repository subsystem</emphasis>. In this chapter, you will learn how to use the system
|
||||
to manage the storage of active web conversations in a stable manner.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="repository-architecture-overview">
|
||||
<title>Repository architecture overview</title>
|
||||
<para>
|
||||
Recall the following bullet points noting what happens when a flow execution enters a ViewState:
|
||||
</para>
|
||||
<para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When a flow execution reaches a <literal>ViewState</literal> it is said to have <emphasis>paused</emphasis>,
|
||||
where it waits in that state for user input to be provided so it can continue. After pausing, the
|
||||
<literal>ViewSelection</literal> returned is used to issue a response to the user
|
||||
that provides a vehicle for collecting the required user input.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
User input is provided by <emphasis>signaling an event</emphasis> that
|
||||
<emphasis>resumes</emphasis> the flow execution in the paused view state.
|
||||
The input event communicates what user action was taken.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
Each time an active flow execution is <emphasis>paused</emphasis>, it is saved out to a
|
||||
repository. When the next request comes in for that flow execution, it is restored
|
||||
from the repository, <emphasis>resumed</emphasis>, and continued. This process continues
|
||||
until the flow execution reaches an end state, at which time it is removed from the repository.
|
||||
</para>
|
||||
<para>
|
||||
This process is demonstrated over the next two graphics:
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/flowexecution-persistence.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/flowexecution-persistence.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>Request one (1) - Paused flow execution persistence</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/flowexecution-restoration.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/flowexecution-restoration.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>Request two (2) - Paused flow execution restoration, removal on end</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</sect1>
|
||||
<sect1 id="repository-entry-identity">
|
||||
<title>Flow execution identity</title>
|
||||
<para>
|
||||
When a new flow execution is created, it marks the start of a new conversation between a browser
|
||||
and the server. A new flow execution that is still active after startup
|
||||
processing indicates the start of a conversation that will span more than one request
|
||||
and needs to be persisted. When this is the case, that flow execution is assigned
|
||||
an <emphasis>persistent identifer</emphasis> by the repository. By default, the
|
||||
structure of this identifier consists of a two-part composite key. This key is used
|
||||
by clients to restore the flow execution on subsequent requests.
|
||||
</para>
|
||||
<sect2 id="conversationId">
|
||||
<title>Conversation identifier</title>
|
||||
<para>
|
||||
The first part of a flow execution's persistent identity is a
|
||||
unique <emphasis>conversation identifier</emphasis>. This serves as an index into
|
||||
the <emphasis>logical</emphasis> conversation between the browser and the server that
|
||||
has just started.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="continuationId">
|
||||
<title>Continuation identifier</title>
|
||||
<para>
|
||||
The second part of a flow execution's persistent identity is a <emphasis>continuation identifier</emphasis>.
|
||||
This identifier serves as an index into a flow execution representing the state of the conversation
|
||||
<emphasis>at this point in time</emphasis>.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="flowExecutionKey">
|
||||
<title>Flow execution key</title>
|
||||
<para>
|
||||
Together the conversation id plus the continuation id make up the unique two-part
|
||||
<emphasis>flow execution key</emphasis> that identifies a state
|
||||
of a conversation <emphasis>at a point in time</emphasis>. By submitting this key
|
||||
in a subsequent request, a browser can restore the conversation at that point
|
||||
and <emphasis>continue</emphasis> from there.
|
||||
</para>
|
||||
<para>
|
||||
So on a subsequent request, the conversation is resumed by restoring a flow execution
|
||||
from the repository using the two-part key. After event processing, if the
|
||||
flow execution is still active it is saved back out to the repository.
|
||||
At this time a new flow execution key is generated. By default, that key
|
||||
retains the same <emphasis>conversation identifier</emphasis>, as the same logical
|
||||
conversation is in progress; however the <emphasis>continuation identifier</emphasis>
|
||||
changes to provide an index into the state of the flow execution
|
||||
at <emphasis>this new point in time</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
By submitting this new key in a subsequent request, a browser can
|
||||
restore the conversation at that point and <emphasis>continue</emphasis> from there.
|
||||
This process continues until a flow execution reaches an end state during event processing
|
||||
signaling the end of the conversation.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1 id="conversation-ending">
|
||||
<title>Conversation ending</title>
|
||||
<para>
|
||||
When a flow execution reaches an end state it terminates. If the flow execution was associated
|
||||
with a logical conversation that spanned more than on request, it is removed from the
|
||||
repository. More specifically, the entire conversation is <emphasis>ended</emphasis>,
|
||||
resulting in any flow execution continuations associated with the conversation being purged.
|
||||
</para>
|
||||
<para>
|
||||
Once a conversation has ended, the conversation identifier is no longer valid
|
||||
and can never be used again.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="repository-implementations">
|
||||
<title>Flow execution repository implementations</title>
|
||||
<para>
|
||||
The next section looks at the repository implementations that are available for use
|
||||
with Spring Web Flow out-of-the-box.
|
||||
</para>
|
||||
<sect2 id="repository-simple">
|
||||
<title>Simple flow execution repository</title>
|
||||
<para>
|
||||
The simplest possible repository (<literal>SimpleFlowExecutionRepository</literal>).
|
||||
This repository stores <emphasis>exactly one</emphasis> flow execution instance per conversation
|
||||
in the user's session, invalidating it when its end state is reached.
|
||||
This repository implementation has been designed with minimal storage overhead in mind.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
It is important to understand that use of this repository consistently prevents
|
||||
duplicate submission when using the back button. If you attempt to go back
|
||||
and resubmit, the continuation id stored in your browser history will not
|
||||
match the current continuation id needed to access the flow execution and
|
||||
access will be disallowed.
|
||||
</para>
|
||||
</note>
|
||||
<note>
|
||||
<para>
|
||||
This repository implementation should generally be used when you do not have to
|
||||
support browser navigational button use; for example, when you lock down the browser and
|
||||
require that all navigation events to be routed through Spring Web Flow.
|
||||
</para>
|
||||
</note>
|
||||
</sect2>
|
||||
<sect2 id="repository-continuation">
|
||||
<title>Continuation flow execution repository</title>
|
||||
<para>
|
||||
This repository (<literal>ContinuationFlowExecutionRepository</literal>) stores <emphasis>one to many</emphasis> flow
|
||||
execution instances per conversation in the user's session, where each flow execution represents a
|
||||
paused and restorable state of the conversation at a point in time. This repository implementation is
|
||||
considerably more flexible than the simple one, but incurs more storage overhead.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
It is important to understand that use of this repository allows resubmission when
|
||||
using the back button. If you attempt to go back and resubmit while the conversation
|
||||
is active, the continuation id stored in your browser history will match the
|
||||
continuation id of a previous flow execution in the repository. Access to
|
||||
that flow execution representing the state of the conversation at that point in
|
||||
time will be granted.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
Like the simple implementation, this repository implementation provides support for <emphasis>conversation
|
||||
invalidation after completion</emphasis> where once a logical
|
||||
conversation completes (by one of its FlowExecutions reaching an end state),
|
||||
the entire conversation is invalidated. This prevents the possibility of
|
||||
resubmission after completion.
|
||||
</para>
|
||||
<para>
|
||||
This repository is more elaborate than the default repository, offering
|
||||
more power (by enabling multiple continuations to exist per conversation),
|
||||
but incurring more storage overhead. This repository implementation should be
|
||||
considered when you do have to support browser navigational button use.
|
||||
This implementation is the default.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="repository-client">
|
||||
<title>Client continuation flow execution repository</title>
|
||||
<para>
|
||||
This repository is entirely stateless and its use entails no server-side state
|
||||
(<literal>ClientContinuationFlowExecutionRepository</literal>).
|
||||
</para>
|
||||
<para>
|
||||
This is achieved by encoding a serialized flow execution directly into the
|
||||
flow execution continuation key that is sent in the response.
|
||||
</para>
|
||||
<para>
|
||||
When asked to load a flow execution by its key on a subsequent request, this
|
||||
repository decodes and deserializes the flow execution, restoring it to
|
||||
the state it was in when it was serialized.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
This repository implementation does not currently support
|
||||
<emphasis>conversation invalidation after completion</emphasis>, as
|
||||
this capability requires tracking active conversations using some
|
||||
form of centralized storage, like a database table.
|
||||
</para>
|
||||
</note>
|
||||
<note>
|
||||
<para>
|
||||
Storing state (a flow execution continuation) on the client
|
||||
entails a certain security risk that should be evaluated. Furthermore, it
|
||||
puts practical constraints on the size of the flow execution.
|
||||
</para>
|
||||
</note>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
@@ -1,673 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="flow-execution">
|
||||
<title>Flow execution</title>
|
||||
<sect1 id="execution-intro">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
Once a flow has been defined, any number of executions of it can be launched in parallel
|
||||
at runtime. Execution of a flow is carried out by a dedicated system that
|
||||
is based internally on a state machine that runs atop the Java VM. As the life of a
|
||||
flow execution can span more than one request into the server, this system
|
||||
is also responsible for persisting execution state across requests.
|
||||
</para>
|
||||
<para>
|
||||
This chapter documents Spring Web Flow's flow execution system. You will
|
||||
learn the core constructs of the system and how to execute flows out-of-container
|
||||
within a JUnit test environment.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="execution">
|
||||
<title>FlowExecution</title>
|
||||
<para>
|
||||
A <literal>org.springframework.webflow.execution.FlowExecution</literal> is a runtime instantiation of a flow definition.
|
||||
Given a single <literal>FlowDefinition</literal>, any
|
||||
number of independent flow executions may be created.
|
||||
These executions are typically created by a <literal>FlowExecutionFactory</literal>.
|
||||
</para>
|
||||
<para>
|
||||
A flow execution carries out the execution of program instructions defined within
|
||||
its definition in response to user events.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>
|
||||
It may be helpful to think of a flow definition as analagous to a Java <literal>Class</literal>, and a
|
||||
flow execution as analagous to an object instance of that <literal>Class</literal>. Signaling
|
||||
an execution event can be considered analagous to sending an object a message.
|
||||
</emphasis>
|
||||
</para>
|
||||
<sect2 id="execution-creation">
|
||||
<title>Flow execution creation</title>
|
||||
<programlisting>
|
||||
FlowDefinition definition = ...
|
||||
FlowExecutionFactory factory = ...
|
||||
FlowExecution execution = factory.createFlowExecution(definition);
|
||||
</programlisting>
|
||||
<para>
|
||||
Once created, a new flow execution is initially inactive, waiting to be started. Once
|
||||
started, a flow execution becomes active by entering its <literal>startState</literal>.
|
||||
From there, it continues executing until it enters a state where user input is required
|
||||
to continue or it terminates.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="execution-start">
|
||||
<title>Flow execution startup</title>
|
||||
<programlisting>
|
||||
ExternalContext context = ...
|
||||
execution.start(context);
|
||||
</programlisting>
|
||||
<para>
|
||||
When a flow execution reaches a state where input is required to continue, it is said to have <emphasis>paused</emphasis>,
|
||||
where it waits in that state for user input to be provided.
|
||||
</para>
|
||||
<para>
|
||||
User input is provided by <emphasis>signaling an event</emphasis> that
|
||||
<emphasis>resumes</emphasis> the flow execution by communicating what user action was taken.
|
||||
Attributes of the signal event request form the basis for user input. The flow execution
|
||||
resumes by consuming the event.
|
||||
</para>
|
||||
<para>
|
||||
Once a flow execution has resumed, it continues executing until it again enters a
|
||||
state where more input is needed or it terminates. Once a flow execution has terminated
|
||||
it becomes inactive and cannot be resumed.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="execution-resume">
|
||||
<title>Flow execution resume</title>
|
||||
<programlisting>
|
||||
ExternalContext context = ...
|
||||
execution.resume(context);
|
||||
if (execution.isActive()) {
|
||||
// still active but paused
|
||||
} else {
|
||||
// has ended
|
||||
}
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="execution-lifecycle">
|
||||
<title>Flow execution lifecycle</title>
|
||||
<para>
|
||||
As outlined, a flow execution can go through a number of phases throughout its lifecycle;
|
||||
for example, <emphasis>created</emphasis>, <emphasis>active</emphasis>, <emphasis>paused</emphasis>,
|
||||
<emphasis>ended</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
Spring Web Flow gives you the ability to observe the lifecycle of an
|
||||
executing flow by implementing a <literal>FlowExecutionListener</literal>.
|
||||
</para>
|
||||
<para>
|
||||
The different phases of a flow execution are shown graphically below:
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/flowexecution-statediagram.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/flowexecution-statediagram.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>Flow execution lifecycle</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</sect2>
|
||||
<sect2 id="execution-properties">
|
||||
<title>Flow execution properties</title>
|
||||
<para>
|
||||
The Spring Web Flow flow execution implementation is <literal>org.springframework.webflow.engine.impl.FlowExecutionImpl</literal>,
|
||||
typically created by a <literal>FlowExecutionImplFactory</literal> (a <literal>FlowExecutionFactory</literal> implementation).
|
||||
The configurable properties of this flow execution implementation are summarized below:
|
||||
</para>
|
||||
<table>
|
||||
<title>Flow Execution properties</title>
|
||||
<tgroup cols="4">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Property name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Cardinality</entry>
|
||||
<entry>Default value</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>definition</entry>
|
||||
<entry>The flow definition to be executed.</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>listeners</entry>
|
||||
<entry>The set of observers observing the lifecycle of this flow execution.</entry>
|
||||
<entry>
|
||||
<emphasis>0..*</emphasis>
|
||||
</entry>
|
||||
<entry>Empty</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>attributes</entry>
|
||||
<entry>Global system attributes that can be used to affect flow execution behavior</entry>
|
||||
<entry>
|
||||
<emphasis>0..*</emphasis>
|
||||
</entry>
|
||||
<entry>Empty</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>
|
||||
The configurable constructs related to flow execution are shown graphically below:
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/flowexecution-classdiagram.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/flowexecution-classdiagram.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>Flow execution</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</sect2>
|
||||
<sect2 id="execution-impl-creation">
|
||||
<title>Flow execution impl creation</title>
|
||||
<programlisting>
|
||||
FlowExecutionFactory factory = new FlowExecutionImplFactory();
|
||||
factory.setExecutionListeners(...);
|
||||
factory.setExecutionAttributes(...);
|
||||
FlowExecution execution = factory.createFlowExecution(definition);
|
||||
</programlisting>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1 id="execution-context">
|
||||
<title>Flow execution context</title>
|
||||
<para>
|
||||
Once created, a flow execution, representing the state of a flow at a point in time,
|
||||
maintains contextual state about itself that can be reasoned upon by clients. In addition,
|
||||
a flow execution exposes several data structures, called scopes, that allow clients to set
|
||||
arbitrary attributes that are managed by the execution.
|
||||
</para>
|
||||
<para>
|
||||
The contextual properties associated with a flow execution are summarized below:
|
||||
</para>
|
||||
<table>
|
||||
<title>Flow Execution Context properties</title>
|
||||
<tgroup cols="4">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Property name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Cardinality</entry>
|
||||
<entry>Default value</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>active</entry>
|
||||
<entry>
|
||||
A flag indicating if the flow execution is active.
|
||||
An inactive flow execution has either ended or has never been started.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>definition</entry>
|
||||
<entry>
|
||||
The definition of the flow execution. The flow definition serves as
|
||||
the blueprint for the program. <emphasis>It may be helpful to think of a flow
|
||||
definition as like a <literal>Class</literal> and a
|
||||
flow execution as like an instance of that <literal>Class</literal></emphasis>.
|
||||
This method may always be safely called.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>activeSession</entry>
|
||||
<entry>
|
||||
The active flow session, tracking the flow that is currently executing
|
||||
and what state it is in. The active session can change over the life of the
|
||||
flow execution because a flow can spawn another flow as a subflow.
|
||||
This property can only be queried while the flow execution is active.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>conversationScope</entry>
|
||||
<entry>
|
||||
A data map that forms the basis for "conversation scope". Arbitrary attributes placed in this map will be retained
|
||||
for the life of the flow execution and correspond to the length of the logical conversation.
|
||||
This map is <emphasis>shared</emphasis> by all flow sessions.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>
|
||||
As a flow execution is manipulated by clients its contextual state changes. Consider how
|
||||
contextual state is effected when the following events occur:
|
||||
</para>
|
||||
<table>
|
||||
<title>An ordered set of events and their effects on flow execution context</title>
|
||||
<tgroup cols="3">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Flow Execution Event</entry>
|
||||
<entry>Active?</entry>
|
||||
<entry>Value of the <literal>activeSession</literal> property</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>created</entry>
|
||||
<entry>false</entry>
|
||||
<entry>Throws an IllegalStateException</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>started</entry>
|
||||
<entry>true</entry>
|
||||
<entry>
|
||||
A <literal>FlowSession</literal> whose <literal>definition</literal>
|
||||
is the top-level flow definition and whose <literal>state</literal> is the definition's start state.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>state entered</entry>
|
||||
<entry>true</entry>
|
||||
<entry>
|
||||
A <literal>FlowSession</literal> whose <literal>definition</literal>
|
||||
is the top-level flow definition and whose <literal>state</literal> is the newly entered state.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>subflow spawned</entry>
|
||||
<entry>true</entry>
|
||||
<entry>
|
||||
A <literal>FlowSession</literal> whose <literal>definition</literal>
|
||||
is the subflow definition and whose <literal>state</literal> is the subflow's start state.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>subflow ended</entry>
|
||||
<entry>true</entry>
|
||||
<entry>
|
||||
A <literal>FlowSession</literal> whose <literal>definition</literal> is back to the
|
||||
top-level flow definition and whose <literal>state</literal> is the resuming state.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ended</entry>
|
||||
<entry>false</entry>
|
||||
<entry>Throws an IllegalStateException</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>
|
||||
As you can see, the <literal>activeSession</literal> of a flow execution changes when a subflow
|
||||
is spawned. Each flow execution maintains a stack of flow sessions, where each flow session
|
||||
represents a spawned instance of a flow definition. When a flow execution starts, the session stack initially
|
||||
consists of one (1) entry, an instance dubbed the <emphasis>root session</emphasis>.
|
||||
When a subflow is spawned, the stack increases to two (2) entries. When the subflow ends,
|
||||
the stack decreases back to one (1) entry. The active session is always
|
||||
the session at the top of the stack.
|
||||
</para>
|
||||
<para>
|
||||
The contextual properties associated with a <literal>FlowSession</literal> are summarized below:
|
||||
</para>
|
||||
<table>
|
||||
<title>Flow Session properties</title>
|
||||
<tgroup cols="4">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Property name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Cardinality</entry>
|
||||
<entry>Default value</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>definition</entry>
|
||||
<entry>
|
||||
The definition of the flow the session is an instance of.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>state</entry>
|
||||
<entry>
|
||||
The current state of the session.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>status</entry>
|
||||
<entry>
|
||||
A status indicator describing what the session is currently doing.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>scope</entry>
|
||||
<entry>
|
||||
A data map that forms the basis for <emphasis>flow scope</emphasis>.
|
||||
Arbitrary attributes placed in this map will be retained for the scope
|
||||
of the flow session. This map is <emphasis>local</emphasis> to the session.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>flashMap</entry>
|
||||
<entry>
|
||||
A data map that forms the basis for <emphasis>flash scope</emphasis>.
|
||||
Attributes placed in this map will be retained until the next
|
||||
external user event is signaled in the session.
|
||||
</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>
|
||||
The following graphic illustrates an example flow execution context and flow
|
||||
session stack:
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/flowexecution-sessionstack.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/flowexecution-sessionstack.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>Flow execution context</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
<para>
|
||||
In this illustration, a flow execution has been created for the <literal>Book Flight</literal> flow.
|
||||
The execution is currently active and the <literal>activeSession</literal> indicates it
|
||||
is in the <literal>Display Seating Chart</literal> state of the <literal>Assign Seats</literal> flow,
|
||||
which was spawned as a subflow from the <literal>Enter Seat Assignments</literal> state.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Note how the active session status is <literal>paused</literal>, indicating the flow execution
|
||||
is currently waiting for user input to be provided to continue. In this case, it is
|
||||
expected the user will choose a seat for their flight.
|
||||
</para>
|
||||
</note>
|
||||
</sect1>
|
||||
<sect1 id="execution-scopes">
|
||||
<title>Flow execution scopes</title>
|
||||
<para>
|
||||
As alluded to, a flow execution manages several containers called <emphasis>scopes</emphasis>,
|
||||
which allow arbitrary attributes to be stored for a period of time. There are four scope
|
||||
types, each with different storage management semantics:
|
||||
</para>
|
||||
<table>
|
||||
<title>Flow execution scope types</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Scope type name</entry>
|
||||
<entry>Management Semantics</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>request</entry>
|
||||
<entry>
|
||||
Eligible for garbage collection when a single call into the flow execution completes.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>flash</entry>
|
||||
<entry>
|
||||
Cleared when the next user event is signaled into the flow session; eligible for garbage collection when the flow session ends.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>flow</entry>
|
||||
<entry>
|
||||
Eligible for garbage collection when the flow session ends.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>conversation</entry>
|
||||
<entry>
|
||||
Eligible for garbage collection when the root session of the governing flow execution (logical conversation) ends.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
<sect1 id="execution-testing">
|
||||
<title>Flow execution testing</title>
|
||||
<para>
|
||||
Spring Web Flow provides support within the <literal>org.springframework.webflow.test</literal>
|
||||
package for testing flow executions with JUnit. This support is provided as convenience but is
|
||||
entirely optional, as a flow execution is instantiable in any environment with the standard
|
||||
Java <literal>new</literal> operator.
|
||||
</para>
|
||||
<para>
|
||||
The general strategy for testing flows follows:
|
||||
</para>
|
||||
<para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Your own implementations of definitional artifacts used by a flow such as actions,
|
||||
attribute mappers, and exception handlers should be unit tested in isolation.
|
||||
Spring Web Flow ships convenient stubs to assist with this, for instance
|
||||
<literal>MockRequestContext</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The execution of a flow should be tested as part of a system integration test.
|
||||
Such a test should exercise all possible paths of the flow, asserting that
|
||||
the flow responds to events as expected.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
A flow execution integration test typically selects mock or stub implementations of application
|
||||
services called by the flow, though it may also exercise production implementations.
|
||||
Both are useful, supported system test configurations.
|
||||
</para>
|
||||
</note>
|
||||
<sect2 id="execution-testing-example">
|
||||
<title>Flow execution test example</title>
|
||||
<para>
|
||||
To help illustrate testing a flow execution, first consider the following flow definition
|
||||
to search a phonebook for contacts:
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/flow-search.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/flow-search.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>Phonebook Search Flow - State Diagram</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
<para>
|
||||
The corresponding XML-based flow definition implementation:
|
||||
</para>
|
||||
<programlisting>
|
||||
<?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-2.0.xsd">
|
||||
|
||||
<start-state idref="enterCriteria"/>
|
||||
|
||||
<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>
|
||||
|
||||
<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="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>
|
||||
</programlisting>
|
||||
<para>
|
||||
Above you see a flow with three (3) states that execute these behaviors, respectively:
|
||||
</para>
|
||||
<para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The first state <literal>enterCriteria</literal> displays a search criteria form so the user can enter who
|
||||
he or she wishes to search for.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
On form submit and successful data binding and validation, the search is executed.
|
||||
After search execution a results view is displayed.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
From the results view, the user may select a result they wish to browse additional details on
|
||||
or they may request a new search. On select, the "detail" flow is spawned and
|
||||
when it finishes the search is re-executed and it's results redisplayed.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
From this behavior narrative the following assertable test scenarios can be extracted:
|
||||
</para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
That when a flow execution starts, it enters the <literal>enterCriteria</literal> state and
|
||||
makes a <literal>searchCriteria</literal> view selection containing a <emphasis>form object</emphasis>
|
||||
to be used as the basis for form field population.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
That on submit with valid input, the search is executed and a <literal>searchResults</literal> view selection is made.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
That on submit with invalid input, the <literal>searchCriteria</literal> view is reselected.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
That on newSearch, the <literal>searchCriteria</literal> view is selected.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
That on select, the <literal>detail</literal> flow is spawned and passed the <literal>id</literal> of the selected result as expected.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>
|
||||
To assist with writing these assertions, Spring Web Flow ships with JUnit-based flow execution
|
||||
test support within the <literal>org.springframwork.webflow.test</literal> package.
|
||||
These base test classes are indicated below:
|
||||
</para>
|
||||
<table>
|
||||
<title>Flow execution test support hierarchy</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="3*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Class name</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>AbstractFlowExecutionTests</entry>
|
||||
<entry>The most generic base class for flow execution tests.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>AbstractExternalizedFlowExecutionTests</entry>
|
||||
<entry>The base class for flow execution tests whose flow is defined within an externalized resource, such as a file.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>AbstractXmlFlowExecutionTests</entry>
|
||||
<entry>The base class for flow execution tests whose flow is defined within an externalized XML resource.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
@@ -1,230 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="flow-executor">
|
||||
<title>Flow executors</title>
|
||||
<sect1 id="executor-intro">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
In this chapter, you will learn how to execute flows within Spring MVC, Struts,
|
||||
and Java Server Faces (JSF) based applications.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="executor">
|
||||
<title>FlowExecutor</title>
|
||||
<para>
|
||||
<literal>org.springframework.webflow.executor.FlowExecutor</literal> 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.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>FlowExecutor</literal> interface is shown below:
|
||||
</para>
|
||||
<programlisting>
|
||||
public interface FlowExecutor {
|
||||
public void executeFlowRequest(ExternalContext context);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
Execution typically consists of either:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Launching (start) a new execution of a flow definition.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Resuming a paused flow execution by signaling an event against its current state.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
The ExternalContext 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.
|
||||
</para>
|
||||
<para>
|
||||
<literal>ExternalContext</literal> implementations exist 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.
|
||||
</para>
|
||||
<sect2 id="flowexecutor-impl">
|
||||
<title>FlowExecutorImpl</title>
|
||||
<para>
|
||||
The default executor implementation is <literal>org.springframework.webflow.executor.FlowExecutorImpl</literal>.
|
||||
It allows for configuration of a <literal>FlowDefinitionLocator</literal> responsible for loading the flow definitions to execute, as well as
|
||||
the <literal>FlowExecutionRepository</literal> strategy responsible for persisting flow executions that remain
|
||||
active beyond a single request into the server.
|
||||
</para>
|
||||
<para>
|
||||
The configurable <literal>FlowExecutorImpl</literal> properties are shown below:
|
||||
</para>
|
||||
<table>
|
||||
<title>FlowExecutorImpl properties</title>
|
||||
<tgroup cols="3">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c3" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Property name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Cardinality</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>definitionLocator</entry>
|
||||
<entry>The service for loading flow definitions to be executed, typically a <literal>FlowDefinitionRegistry</literal></entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>executionFactory</entry>
|
||||
<entry>The factory for creating new flow executions.</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>executionRepository</entry>
|
||||
<entry>The repository for saving and loading persistent (paused) flow executions</entry>
|
||||
<entry>
|
||||
<emphasis>1</emphasis>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect2>
|
||||
<sect2 id="executor-simple">
|
||||
<title>A typical flow executor configuration with Spring 2.0</title>
|
||||
<programlisting>
|
||||
<?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:web="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-2.0.xsd">
|
||||
|
||||
<!-- Launches new flow executions and resumes existing executions. -->
|
||||
<web:flow-executor id="flowExecutor" registry-ref="flowRegistry"/>
|
||||
|
||||
<!-- Creates the registry of flow definitions for this application -->
|
||||
<web:flow-registry id="flowRegistry">
|
||||
<web:flow-location path="/WEB-INF/flows/**/*-flow.xml"/>
|
||||
</web:flow-registry>
|
||||
|
||||
</beans>
|
||||
</programlisting>
|
||||
<para>
|
||||
This instructs Spring to create a flow executor that can execute all XML-based flow definitions
|
||||
contained within the <literal>/WEB-INF/flows</literal> directory. The default flow execution
|
||||
repository, <literal>continuation</literal>, is used.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-custom-repo">
|
||||
<title>A flow executor using a simple execution repository</title>
|
||||
<programlisting>
|
||||
<web:flow-executor id="flowExecutor" registry-ref="flowRegistry" repository-type="simple"/>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured with a simple repository that manages
|
||||
execution state in the user session.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-custom-repo2">
|
||||
<title>A flow executor using a client-side continuation-based execution repository</title>
|
||||
<programlisting>
|
||||
<web:flow-executor id="flowExecutor" registry-ref="flowRegistry" repository-type="client"/>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured with a continuation-based repository that serializes
|
||||
continuation state to the client using no server-side state.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-custom-repo3">
|
||||
<title>A flow executor using a single key execution repository</title>
|
||||
<programlisting>
|
||||
<web:flow-executor id="flowExecutor" registry-ref="flowRegistry" repository-type="singleKey"/>>
|
||||
</programlisting>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-custom-repo4">
|
||||
<title>A flow executor setting custom conversation management attributes</title>
|
||||
<programlisting>
|
||||
<web:flow-executor id="flowExecutor" registry-ref="flowRegistry">
|
||||
<web:flow-repository type="continuation" max-conversations="5" max-continuations="30" conversation-manager-ref="conversationManager"/>
|
||||
</web:flow-executor>
|
||||
|
||||
<bean id="conversationManager" class="example.MyCustomConversationalStateManager"/>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured with a continuation repository configured with custom settings for:
|
||||
<orderedlist>
|
||||
<listitem><para>The maximum number of active conversations per user session (5)</para></listitem>
|
||||
<listitem><para>The maximum number of restorable flow execution snapshots (continuations) per conversation (30)</para></listitem>
|
||||
<listitem><para>Where conversational state will be stored (via a custom conversationManager)</para></listitem>
|
||||
</orderedlist>
|
||||
The <literal>flow:repository</literal> child element is the more flexible form for configuring the flow execution repository.
|
||||
Use it or the convenient <literal>repository-type</literal> attribute, not both.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-excution-attributes">
|
||||
<title>A flow executor setting system execution attributes</title>
|
||||
<programlisting>
|
||||
<web:flow-executor id="flowExecutor" registry-ref="flowRegistry" repository-type="continuation">
|
||||
<web:flow-execution-attributes>
|
||||
<web:alwaysRedirectOnPause value="false"/>
|
||||
<web:attribute name="foo" value="bar"/>
|
||||
</flow:execution-attributes>
|
||||
</web:flow-executor>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured to set two flow execution system attributes
|
||||
<literal>alwaysRedirectOnPause=false</literal> and <literal>foo=bar</literal>.
|
||||
</para>
|
||||
<para>
|
||||
<note>
|
||||
<para>
|
||||
The <literal>alwaysRedirectOnPause</literal> attribute determines if
|
||||
a flow execution redirect occurs automatically each time an execution pauses
|
||||
(automated <literal>POST+REDIRECT+GET</literal> behavior).
|
||||
Setting this attribute to false will disable the <emphasis>default 'true' behavior</emphasis>.
|
||||
</para>
|
||||
</note>
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-excution-listeners">
|
||||
<title>A flow executor setting custom execution listeners</title>
|
||||
<programlisting>
|
||||
<web:flow-executor id="flowExecutor" registry-ref="flowRegistry" repository-type="continuation">
|
||||
<web:flow-execution-listeners>
|
||||
<web:flow-listener ref="listener" criteria="order-flow"/>
|
||||
</web:flow-execution-listeners>
|
||||
</web:flow-executor>
|
||||
|
||||
<!-- A FlowExecutionListener to observe the lifecycle of order-flow executions -->
|
||||
<bean id="listener" class="example.OrderFlowExecutionListener"/>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured to apply the execution listener to the "order-flow".
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 14 KiB |
BIN
spring-webflow/docs/reference/src/images/hotels-site.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
@@ -3,20 +3,14 @@
|
||||
"../lib/docbook-dtd/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY overview SYSTEM "overview.xml">
|
||||
<!ENTITY flow-definition SYSTEM "flow-definition.xml">
|
||||
<!ENTITY flow-execution SYSTEM "flow-execution.xml">
|
||||
<!ENTITY flow-execution-repository SYSTEM "flow-execution-repository.xml">
|
||||
<!ENTITY flow-executor SYSTEM "flow-executor.xml">
|
||||
<!ENTITY spring-faces SYSTEM "spring-faces.xml">
|
||||
<!ENTITY practical SYSTEM "practical.xml">
|
||||
<!ENTITY defining-flows SYSTEM "defining-flows.xml">
|
||||
]>
|
||||
|
||||
<book>
|
||||
|
||||
<bookinfo>
|
||||
<title>Spring Web Flow</title>
|
||||
<subtitle>Reference Documentation</subtitle>
|
||||
<releaseinfo>Version 2.0-m4</releaseinfo>
|
||||
<releaseinfo>Version 2.0 M4</releaseinfo>
|
||||
<pubdate>March 2008</pubdate>
|
||||
<authorgroup>
|
||||
<author>
|
||||
@@ -54,11 +48,6 @@
|
||||
<toc />
|
||||
|
||||
&overview;
|
||||
&flow-definition;
|
||||
&flow-execution;
|
||||
&flow-execution-repository;
|
||||
&flow-executor;
|
||||
&spring-faces;
|
||||
&practical;
|
||||
&defining-flows;
|
||||
|
||||
</book>
|
||||
@@ -2,630 +2,50 @@
|
||||
<preface id="preface">
|
||||
<title>Preface</title>
|
||||
<para>
|
||||
Many web applications consist of a mix of free browsing,
|
||||
where the user is allowed to navigate a web site as they please,
|
||||
and controlled navigations where the user is guided through
|
||||
a series of steps towards completion of a business goal.
|
||||
</para>
|
||||
<para>
|
||||
Consider the typical shopping cart application. While a user is
|
||||
shopping, she is freely browsing available products, adding her
|
||||
favorites to her cart while skipping over others. This is a good
|
||||
"free browsing" use case. However, when the user decides to
|
||||
checkout, a controlled workflow begins--the checkout process.
|
||||
Such a process represents a single user conversation that takes
|
||||
place over a series of steps, and navigation from step-to-step
|
||||
is controlled. The entire process represents an discrete
|
||||
application transaction that must complete exactly once
|
||||
or not at all.
|
||||
Many web applications require the same sequence of steps to execute in different contexts.
|
||||
Often these sequences are merely components of a larger task the user is trying to accomplish.
|
||||
Such a reusable sequence is called a flow.
|
||||
</para>
|
||||
<para>
|
||||
Consider some other good examples of "controlled navigations":
|
||||
applying for a loan, paying your taxes on-line,
|
||||
booking a trip reservation, registering an account, or
|
||||
updating a warehouse inventory.
|
||||
Consider a typical shopping cart application.
|
||||
User registration, login, and cart checkout are all examples of flows that can be invoked from several places in this type of application.
|
||||
</para>
|
||||
<para>
|
||||
Traditional approaches to modeling and enforcing such controlled
|
||||
navigations or "flows" fall flat, and fail to express the Flow as a
|
||||
first class concept. Spring Web Flow (SWF) is a component of the
|
||||
Spring Framework's web stack focused on solving this problem
|
||||
in a productive and powerful manner.
|
||||
Spring Web Flow (SWF) is the module of Spring that focuses on being the definitive solution for implementing flows.
|
||||
The Web Flow engine plugs into the Spring Web MVC platform and provides declarative flow definition language.
|
||||
This reference guide shows you how to use and extend Spring Web Flow.
|
||||
</para>
|
||||
</preface>
|
||||
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
<sect1 id="introduction-overview">
|
||||
<title>Overview</title>
|
||||
<sect1 id="manual-overview">
|
||||
<title>What this guide covers</title>
|
||||
<para>
|
||||
Spring Web Flow (SWF) is a component of the
|
||||
Spring Framework's web stack focused on the
|
||||
definition and execution of UI flow within
|
||||
a web application.
|
||||
</para>
|
||||
<para>
|
||||
The system allows you to capture a logical flow
|
||||
of your web application as a self-contained module
|
||||
that can be reused in different situations. Such
|
||||
a flow guides a single user through the implementation
|
||||
of a business task, and represents a single user
|
||||
<emphasis>conversation</emphasis>.
|
||||
Flows often execute across HTTP requests,
|
||||
have state, exhibit transactional characteristics,
|
||||
and may be dynamic and/or long-running in nature.
|
||||
</para>
|
||||
<para>
|
||||
Spring Web Flow exists at a higher level of abstraction, integrating
|
||||
as a self-contained <emphasis>flow engine</emphasis> within
|
||||
base frameworks such as Struts, Spring MVC, Portlet MVC, and JSF.
|
||||
SWF provides you the capability to capture your
|
||||
application's UI flow explicitly in a declarative,
|
||||
portable, and manageable fashion. SWF is
|
||||
a powerful controller framework based on a finite-state machine,
|
||||
fully addressing the "C" in MVC.
|
||||
This guide covers all aspects of Spring Web Flow.
|
||||
It is organized into two major sections, a Users Section followed by an Architects Section.
|
||||
The Users Section covers implementing flows in end-user applications and working with the feature set.
|
||||
The Architects Section covers extending the framework and the overall architectural model.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="introduction-architecture-overview">
|
||||
<title>Architecture overview</title>
|
||||
<sect1 id="system-requirements">
|
||||
<title>What Web Flow requires to run</title>
|
||||
<para>
|
||||
Spring Web Flow has been architected as a self-contained <emphasis>flow engine</emphasis>
|
||||
with few required dependencies on third-party APIs. All dependencies are
|
||||
carefully managed.
|
||||
Java 1.4 or higher
|
||||
</para>
|
||||
<para>
|
||||
At a minimum, to use Spring Web Flow you need:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>spring-webflow (the framework)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>spring-core (miscellaneous utility classes used internally by the framework)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>spring-binding (the Spring data binding framework, used internally)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>commons-logging (a simple logging facade, used internally)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>OGNL (the default expression language)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Most users will embed SWF as a component within a larger web application development
|
||||
framework, as SWF is a focused <emphasis>controller technology</emphasis> that expects a
|
||||
calling system to care for request mapping and response rendering. In this case, those users
|
||||
will depend on a thin integration piece for their environment. For example, those executing
|
||||
flows within a Servlet environment might use the Spring MVC integration to care for dispatching
|
||||
requests to SWF and rendering responses for SWF view selections. Spring Web Flow ships
|
||||
convenient Spring MVC, Struts Classic, and JSF integration out of the box.
|
||||
</para>
|
||||
<para>
|
||||
<note>
|
||||
<para>
|
||||
Spring Web Flow, like Spring, is a <emphasis>layered</emphasis> framework,
|
||||
packaged in a manner that allows teams to use the parts they need and nothing else.
|
||||
For example, one team might use Spring Web Flow in a Servlet environment with Spring MVC
|
||||
and thus require the Spring MVC integration. Another team might use SWF in a Portlet
|
||||
environment, and thus require the Portlet MVC integration. Another team might mix and match.
|
||||
A major benefit of SWF is that it allows you to define reusable, self-contained controller
|
||||
modules that can execute in <emphasis>any</emphasis> environment.
|
||||
</para>
|
||||
</note>
|
||||
Spring 2.5.2 or higher
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="introduction-structure-layer-diagram">
|
||||
<title>Architectural layers</title>
|
||||
<sect1 id="support">
|
||||
<title>Where to get additional support</title>
|
||||
<para>
|
||||
Spring Web Flow is a layered framework. A diagram of Spring Web Flow's layered architecture is
|
||||
shown below:
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/architecture-layer-diagram.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/architecture-layer-diagram.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>Spring Web Flow layer diagram</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</sect1>
|
||||
<sect1 id="introduction-structure-layer-description">
|
||||
<title>Layer descriptions</title>
|
||||
<para>
|
||||
Each layer is partitioned into one or more subsystems that together
|
||||
carry out the layer's role within the overall system. This section notes
|
||||
the purpose of each layer and describes each subsystem in the following format:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Subsystem name</emphasis> - The name of a layer subsystem.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Description</emphasis> - The purpose of the subsystem.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Packages</emphasis> - The Java packages that contain the source code for
|
||||
the subsystem. The packages are rooted at the <literal>org.springframework.webflow</literal>
|
||||
root package in the package hierarchy.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Subsystem interfaces</emphasis> - Central API elements exposed by the subsystem,
|
||||
typically through Java interfaces.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Internal dependencies</emphasis> - Dependencies of the subsystem. These could be
|
||||
other subsystems of the layer or external libraries.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<sect2 id="layer-execution-core">
|
||||
<title>The Execution Core Layer (Bottom Layer)</title>
|
||||
<para>
|
||||
Defines core flow definition and execution public APIs. As the "bottom layer", this
|
||||
layer is highly stable with no dependencies on any other layer.
|
||||
</para>
|
||||
<table>
|
||||
<title>Execution Core Subsystems</title>
|
||||
<tgroup cols="5">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c3" colwidth="2*" />
|
||||
<colspec colname="c4" colwidth="2*" />
|
||||
<colspec colname="c5" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Subsystem name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Packages</entry>
|
||||
<entry>Subsystem interfaces</entry>
|
||||
<entry>Internal dependencies</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Core</entry>
|
||||
<entry>
|
||||
Foundational, generic types usable by all other subsystems.
|
||||
Contains the default expression parser (OGNL-based) and
|
||||
core collection types (AttributeMap and company).
|
||||
</entry>
|
||||
<entry>
|
||||
core,
|
||||
core.collection
|
||||
</entry>
|
||||
<entry>None</entry>
|
||||
<entry>None</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Util</entry>
|
||||
<entry>
|
||||
Low level utilities used by all other parts of the system.
|
||||
</entry>
|
||||
<entry>
|
||||
util
|
||||
</entry>
|
||||
<entry>None</entry>
|
||||
<entry>None</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Flow Definition</entry>
|
||||
<entry>
|
||||
Central abstractions for modeling flow definitions.
|
||||
These abstractions include <literal>FlowDefinition</literal>,
|
||||
<literal>StateDefinition</literal>, and <literal>TransitionDefinition</literal>
|
||||
that form the domain language for describing flows.
|
||||
</entry>
|
||||
<entry>
|
||||
definition
|
||||
</entry>
|
||||
<entry>
|
||||
FlowDefinition
|
||||
</entry>
|
||||
<entry>Core</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Flow Definition Registry</entry>
|
||||
<entry>
|
||||
Support for working with registries of flow definitions. Flow
|
||||
definitions eligible for execution are typically stored in
|
||||
a registry that provides lookup services.
|
||||
</entry>
|
||||
<entry>
|
||||
definition.registry
|
||||
</entry>
|
||||
<entry>
|
||||
FlowDefinitionRegistry,
|
||||
FlowDefinitionLocator
|
||||
</entry>
|
||||
<entry>
|
||||
Core,
|
||||
Flow Definition
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>External Context</entry>
|
||||
<entry>
|
||||
Provides normalized access to a client environment that has called into Spring Web Flow.
|
||||
</entry>
|
||||
<entry>
|
||||
context,
|
||||
context.servlet,
|
||||
context.portlet
|
||||
</entry>
|
||||
<entry>
|
||||
ExternalContext
|
||||
</entry>
|
||||
<entry>
|
||||
Core,
|
||||
context.servlet requires Servlet API 2.4,
|
||||
context.portlet requires Portlet API 1.0 in addition to Servlet API 2.4
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Conversation</entry>
|
||||
<entry>
|
||||
Manages the creation and cleanup of conversational state. Used by
|
||||
the execution repository system to begin new user conversations and
|
||||
track execution state.
|
||||
</entry>
|
||||
<entry>
|
||||
conversation,
|
||||
conversation.impl
|
||||
</entry>
|
||||
<entry>
|
||||
ConversationManager
|
||||
</entry>
|
||||
<entry>
|
||||
Core,
|
||||
Util,
|
||||
External Context
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Flow Execution</entry>
|
||||
<entry>
|
||||
Stable runtime abstractions that define the flow definition
|
||||
execution model. For executing flow definitions
|
||||
and representing execution state.
|
||||
</entry>
|
||||
<entry>
|
||||
execution,
|
||||
execution.support,
|
||||
execution.factory
|
||||
</entry>
|
||||
<entry>
|
||||
FlowExecution
|
||||
</entry>
|
||||
<entry>
|
||||
Core,
|
||||
External Context,
|
||||
Flow Definition
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Flow Execution Repository</entry>
|
||||
<entry>
|
||||
For persisting paused flow executions beyond a single request
|
||||
into the server.
|
||||
</entry>
|
||||
<entry>
|
||||
execution.repository,
|
||||
execution.repository.support,
|
||||
execution.repository.continuation
|
||||
</entry>
|
||||
<entry>
|
||||
FlowExecutionRepository
|
||||
</entry>
|
||||
<entry>
|
||||
Core,
|
||||
Util,
|
||||
Flow Definition,
|
||||
Conversation,
|
||||
Flow Execution
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Action</entry>
|
||||
<entry>
|
||||
Reusable action implementations.
|
||||
</entry>
|
||||
<entry>
|
||||
action,
|
||||
action.portlet
|
||||
</entry>
|
||||
<entry>
|
||||
None
|
||||
</entry>
|
||||
<entry>
|
||||
Core,
|
||||
Util,
|
||||
Flow Definition,
|
||||
External Context,
|
||||
Flow Execution
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect2>
|
||||
<sect2 id="layer-execution-engine">
|
||||
<title>The Execution Engine Layer</title>
|
||||
<para>
|
||||
Defines an implementation of the flow execution core API, forming the basis
|
||||
of the state machine or "engine" implementation. More volatile, as it contains
|
||||
specific implementations of stable execution abstractions.
|
||||
</para>
|
||||
<para>
|
||||
Depends On: Execution Core
|
||||
</para>
|
||||
<table>
|
||||
<title>Execution Engine Subsystems</title>
|
||||
<tgroup cols="5">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Subsystem name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Packages</entry>
|
||||
<entry>Subsystem interfaces</entry>
|
||||
<entry>Internal dependencies</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Engine Implementation</entry>
|
||||
<entry>
|
||||
The implementation of the flow execution engine based on a finite state machine.
|
||||
</entry>
|
||||
<entry>
|
||||
engine,
|
||||
engine.support,
|
||||
engine.impl
|
||||
</entry>
|
||||
<entry>None</entry>
|
||||
<entry>None</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Flow Definition Builder</entry>
|
||||
<entry>
|
||||
Abstractions used at configuration-time for building and assembling Flow definitions
|
||||
executable by this engine implementation. Flows are typically defined
|
||||
in externalized resources such as XML files.
|
||||
</entry>
|
||||
<entry>
|
||||
engine.builder,
|
||||
engine.builder.xml
|
||||
</entry>
|
||||
<entry>
|
||||
<literal>FlowBuilder</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
Engine Implementation,
|
||||
Spring Beans 2.0,
|
||||
Spring Context 2.0,
|
||||
<literal>builder.xml</literal> requires JDK 1.5 or Xerces for XSD support
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect2>
|
||||
<sect2 id="layer-execution-test">
|
||||
<title>The Test Layer</title>
|
||||
<para>
|
||||
Support for unit testing flow artifacts and system testing flow executions.
|
||||
</para>
|
||||
<para>
|
||||
Depends On: Execution Engine, Execution Core
|
||||
</para>
|
||||
<table>
|
||||
<title>Test Subsystems</title>
|
||||
<tgroup cols="5">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Subsystem name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Packages</entry>
|
||||
<entry>Subsystem interfaces</entry>
|
||||
<entry>Internal dependencies</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Engine Artifact Unit Test Support</entry>
|
||||
<entry>
|
||||
Support for unit testing implementations such as Actions in isolation.
|
||||
</entry>
|
||||
<entry>
|
||||
test
|
||||
</entry>
|
||||
<entry>None</entry>
|
||||
<entry>JUnit 3.8.1</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Flow Execution Test Support</entry>
|
||||
<entry>
|
||||
Support for testing Flow Executions out-of-container.
|
||||
</entry>
|
||||
<entry>
|
||||
test.execution
|
||||
</entry>
|
||||
<entry>None</entry>
|
||||
<entry>
|
||||
Spring Beans 2.0,
|
||||
JUnit 3.8.1
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect2>
|
||||
<sect2 id="layer-executor">
|
||||
<title>The Executor Layer</title>
|
||||
<para>
|
||||
Stable higher-level layer for driving and coordinating the execution of flow definitions.
|
||||
This layer is decoupled from the more-volatile engine implementation.
|
||||
</para>
|
||||
<para>
|
||||
Depends On: Execution Core
|
||||
</para>
|
||||
<table>
|
||||
<title>Executor Subsystems</title>
|
||||
<tgroup cols="5">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Subsystem name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Packages</entry>
|
||||
<entry>Subsystem interfaces</entry>
|
||||
<entry>Internal dependencies</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Core</entry>
|
||||
<entry>
|
||||
Generic flow executor abstractions and support.
|
||||
</entry>
|
||||
<entry>
|
||||
executor,
|
||||
executor.support
|
||||
</entry>
|
||||
<entry>
|
||||
<literal>FlowExecutor</literal>
|
||||
</entry>
|
||||
<entry>None</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Spring MVC</entry>
|
||||
<entry>
|
||||
The integration between Spring Web Flow and the Spring MVC framework.
|
||||
</entry>
|
||||
<entry>executor.mvc</entry>
|
||||
<entry>None</entry>
|
||||
<entry>
|
||||
Core,
|
||||
Spring Web MVC 2.0
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Struts</entry>
|
||||
<entry>
|
||||
The integration between Spring Web Flow and the Struts Classic framework.
|
||||
</entry>
|
||||
<entry>
|
||||
executor.struts
|
||||
</entry>
|
||||
<entry>None</entry>
|
||||
<entry>
|
||||
Core,
|
||||
Struts 1.1
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect2>
|
||||
<sect2 id="layer-config">
|
||||
<title>The System Configuration Layer (Top Layer)</title>
|
||||
<para>
|
||||
The top-most layer for configuring the overall Spring Web Flow system for use
|
||||
within an application. As the top layer, this layer depends on the most.
|
||||
</para>
|
||||
<para>
|
||||
Depends On: Executor, Execution Engine, Execution Core
|
||||
</para>
|
||||
<table>
|
||||
<title>System Configuration Subsystems</title>
|
||||
<tgroup cols="5">
|
||||
<colspec colname="c1" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="4*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<colspec colname="c2" colwidth="2*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Subsystem name</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Packages</entry>
|
||||
<entry>Subsystem interfaces</entry>
|
||||
<entry>Internal dependencies</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Spring Configuration Support</entry>
|
||||
<entry>
|
||||
For configuring Spring Web Flow using Spring 1.x and 2.x.
|
||||
</entry>
|
||||
<entry>
|
||||
config
|
||||
</entry>
|
||||
<entry>None</entry>
|
||||
<entry>
|
||||
Spring Beans 1.2.7,
|
||||
<literal>spring-webflow-config-1.0</literal> XSD support requires Spring 2.0
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>
|
||||
<note>
|
||||
<para>
|
||||
As described above, some subsystem packages are optional depending on your use of the
|
||||
subsystem. For example, use of Spring Web Flow in a Servlet environment entails use of
|
||||
the <literal>ExternalContext</literal> context.servlet package which requires the
|
||||
Servlet API to be in the classpath. In this case, the context.portlet package is not
|
||||
used and the Portlet API is not required.
|
||||
</para>
|
||||
</note>
|
||||
</para>
|
||||
<para>
|
||||
For the exact list of dependencies, as well as supported product usage configurations,
|
||||
see the Ivy dependency manager descriptor located within the SWF distribution.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1 id="introduction-support">
|
||||
<title>Support</title>
|
||||
<para>
|
||||
Spring Web Flow 1.x is supported on Spring Framework 1.2.7 or > for the 1.x series, and
|
||||
supported on 2.0 or > for the 2.x series.
|
||||
Professional "from the source" support on Spring Web Flow is available from
|
||||
SpringSource, the company behind Spring, and
|
||||
Ervacon, operated by Web Flow project co-founder Erwin Vervaet
|
||||
</para>
|
||||
<para>
|
||||
XML-based flow building requires Xerces 2 or JDK 5.0 (for XSD support).
|
||||
</para>
|
||||
<para>
|
||||
Our active community support forum is located at http://forum.springframework.org.
|
||||
Spring Community support is available at www.springframework.org
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
@@ -1,382 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="spring-faces">
|
||||
<title>Spring Faces</title>
|
||||
<sect1 id="spring-faces-intro">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
Spring Faces is the home of the new Spring Web Flow + JSF 1.2 integration layer, as well as a number of additional value adds specific
|
||||
to a JSF environment. These value adds include:
|
||||
</para>
|
||||
<para>
|
||||
Unified EL Integration - A separate implementation of the <classname>ExpressionParser</classname> from Spring Binding that uses
|
||||
the new Unified EL from JSF 1.2 and JSP 2.1. This allows for JSF users to use the same expression language in their flow definitions
|
||||
as in their JSF views.
|
||||
</para>
|
||||
<para>
|
||||
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 Dojo javascript framework by default, with an alternate set of tags
|
||||
based on Ext also available.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="jsf-webflow">
|
||||
<title>Web Flow Java Server Faces (JSF) integration</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The JSF integration relies on custom implementations of core JSF artifacts to drive the execution of flows. In addition,
|
||||
it relies on custom ELResolvers to access flow execution attributes from JSF components.
|
||||
</para>
|
||||
<sect2 id="executor-jsf-simple">
|
||||
<title>Adding Spring Web Flow extensions to a JSF application.</title>
|
||||
<para>
|
||||
Using Spring Web Flow in a JSF environment does not require any additions to the application's faces-config.xml. The Spring Faces
|
||||
jar just needs to be on the classpath and all of the custom JSF artifacts provided by spring-faces will be picked
|
||||
up by JSF automatically. Ideally, when building new applications from the start with Spring Faces, a faces-config.xml should
|
||||
not be needed at all in preference for having all beans managed by Spring.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-simple-webflow-setup">
|
||||
<title>Configuring the Web Flow system</title>
|
||||
<para>
|
||||
The artifacts configured by Spring Faces use Spring to access the Web Flow system configuration.
|
||||
This requires the Spring Web Servlet to be configured in the web.xml deployment descriptor:
|
||||
</para>
|
||||
<programlisting>
|
||||
<!-- The front controller of the Spring Web application, responsible for handling all application requests -->
|
||||
<servlet>
|
||||
<servlet-name>Spring Web Servlet</servlet-name>
|
||||
<servlet-class>org.springframework.webflow.servlet.SpringWebServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>configLocations</param-name>
|
||||
<param-value>/WEB-INF/config/web-application-config.xml</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<!-- Map all /spring/* requests to the Spring Web Servlet for handling -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>Spring Web Servlet</servlet-name>
|
||||
<url-pattern>/spring/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
</programlisting>
|
||||
<para>
|
||||
The application context bootstrapped by the Spring Web Servlet should contain the Web Flow system configuration.
|
||||
The example <literal>webflow-config.xml</literal> below shows a typical Web Flow configuration for a JSF environment:
|
||||
</para>
|
||||
<programlisting>
|
||||
<?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:web="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-2.0.xsd">
|
||||
|
||||
<!-- Imports the "application-layer" definining business logic and data access services -->
|
||||
<import resource="application-layer-config.xml"/>
|
||||
|
||||
<web:flow-executor id="flowExecutor" flow-registry="flowRegistry">
|
||||
<web:flow-execution-listeners>
|
||||
<web:listener ref="jpaFlowExecutionListener" criteria="*"/>
|
||||
</web:flow-execution-listeners>
|
||||
</web:flow-executor>
|
||||
|
||||
<web:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
|
||||
<web:flow-location path="flow/main/main.xml" />
|
||||
<web:flow-location path="flow/booking/booking.xml" />
|
||||
<web:flow-builder class="org.springframework.faces.ui.resource.ResourcesFlowBuilder" />
|
||||
</web:flow-registry>
|
||||
|
||||
<bean id="flowBuilderServices" class="org.springframework.webflow.engine.builder.support.FlowBuilderServices">
|
||||
<property name="expressionParser">
|
||||
<bean class="org.springframework.webflow.core.expression.el.WebFlowELExpressionParser">
|
||||
<constructor-arg >
|
||||
<bean class="org.jboss.el.ExpressionFactoryImpl"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="viewFactoryCreator">
|
||||
<bean class="org.springframework.faces.webflow.JsfViewFactoryCreator"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
</programlisting>
|
||||
<para>
|
||||
A bean named <literal>flowExecutor</literal> must be configured and linked with a flow definition registry
|
||||
that contains the flows eligible for execution. Note the <literal>flowExecutor</literal> bean name is significant,
|
||||
as that is bean name the Web Flow JSF extensions will expect.
|
||||
</para>
|
||||
<para>
|
||||
Any flow executor property such as the flow execution repository type is configurable here, consistent
|
||||
with the other environments Spring Web Flow supports.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>flowRegistry</literal> bean definition shows the registration of two XML based flow definitions, as well
|
||||
as a special java-based FlowBuilder that installs a special flow for serving the javascript and CSS resources needed
|
||||
by the Spring Faces custom JSF components.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>flowBuilderServices</literal> provides a number of JSF-specific services to the <literal>flowRegistry</literal>, including the
|
||||
<literal>WebFlowELExpressionParser</literal> that allows Web Flow to use the Unified EL for parsing expressions in flow definitions.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Configuring the FacesServlet</title>
|
||||
<para>
|
||||
Even in an ideal scenario where the <literal>SpringWebServlet</literal> is handling all incoming requests, the <literal>FacesServlet</literal>
|
||||
must still be configured in web.xml in order for JSF to bootstrap properly:
|
||||
</para>
|
||||
<programlisting>
|
||||
<!-- Here so the JSF implementation can initialize, not used at runtime -->
|
||||
<servlet>
|
||||
<servlet-name>Faces Servlet</servlet-name>
|
||||
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<!-- Mapping for faces initialization -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>Faces Servlet</servlet-name>
|
||||
<url-pattern>*.faces</url-pattern>
|
||||
</servlet-mapping>
|
||||
</programlisting>
|
||||
<para>
|
||||
This configuration also allows for the mixing of legacy pure JSF request handling with the request handling of Spring Web Flow for easier
|
||||
page-by-page migration.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-launch-normal-anchor">
|
||||
<title>Launching a flow execution - normal HTML anchor</title>
|
||||
<para>
|
||||
The preferred way of launching a flow from an external system, such as a normal JSF view is by accessing flow definition
|
||||
URLs directly using a bookmark or normal HTML link:
|
||||
</para>
|
||||
<programlisting>
|
||||
<a href="/spring/main">Go</a>
|
||||
</programlisting>
|
||||
<para>
|
||||
This link would launch the "main" flow, assuming /spring/* has been mapped to the <literal>SpringWebServlet</literal> defined within web.xml.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-launch-commandlink">
|
||||
<title>Launching a flow execution - JSF command link component</title>
|
||||
<para>
|
||||
Before going this route, it should be considered whether the same effect can be achieved with a normal REST-ful URL link in combination perhaps
|
||||
in combination with a custom Web Flow <literal>action</literal> in order to execute specialized logic. If it is an absolute requirement to use
|
||||
a JSF UICommand component, then the recommended approach is to programmatically have JSF forward the request to the flow execution URL from within
|
||||
a JSF ActionListener.
|
||||
</para>
|
||||
<programlisting>
|
||||
public void myActionListener(ActionEvent event) {
|
||||
// Execute any required processing and then forward to the flow execution
|
||||
|
||||
facesContext.getCurrentInstance().getExternalContext().dispatch("/spring/main/");
|
||||
facesContext.getCurrentInstance().responseComplete();
|
||||
}
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-sampleflow">
|
||||
<title>Flow definitions in a JSF environment</title>
|
||||
<para>
|
||||
Flow definitions in a JSF environment are just plain Spring Web Flow definitions:
|
||||
</para>
|
||||
<programlisting>
|
||||
<?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>
|
||||
</programlisting>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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 optional in the expression when referencing "myBean".
|
||||
</para>
|
||||
<para>
|
||||
Views selected by view states are specified using paths relative to the current flow definition. In the above example, it is
|
||||
expected that myview.jsp and mynextview.jsp are both located in the same directory as the flow definition.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-resume-form">
|
||||
<title>Resuming a flow execution - form bound to flow execution variables</title>
|
||||
<para>
|
||||
Views participating in flows are just plain JSF views. They may also incorporate other
|
||||
JSF view technologies such as Facelets and Ajax4JSF.
|
||||
</para>
|
||||
<programlisting>
|
||||
<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>
|
||||
</programlisting>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="spring-faces-components">
|
||||
<title>Spring Faces JSF Components</title>
|
||||
<para>
|
||||
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. The default implementation
|
||||
of these components use the Dojo javascript library to provide this validation behavior. Dojo was chosen due to their increased
|
||||
attention to accessibility concerns compared to other javascript frameworks. An alternate implementation based on the Ext library
|
||||
is also provided. Though Ext does not address accessibility issues, it can still be attractive for use in internal corporate
|
||||
intranet style applications.
|
||||
</para>
|
||||
<sect3>
|
||||
<title>Spring Faces Component Configuration</title>
|
||||
<para>
|
||||
The Spring Faces components are currently provided as Facelets tags. In order to utilize them, the
|
||||
following namespace declaration must be added to the header of a Facelets view template:
|
||||
</para>
|
||||
<programlisting>
|
||||
xmlns:sf="http://www.springframework.org/tags/faces"
|
||||
</programlisting>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>Spring Faces Resource Loading</title>
|
||||
<para>
|
||||
Spring Faces requires the installation of a special flow for loading javascript and CSS resources, as shown in the configuration
|
||||
example. This special stateless flow serves up resources corresponding to URLs such as "/spring/resources/dojo/dojo.js". This flow
|
||||
searches for the corresponding resource as follows:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
1) Look for the resource in the web app root using the context-relative path "/dojo/dojo.js", and serve the resource if found.
|
||||
</listitem>
|
||||
<listitem>
|
||||
2) If not found in the web app root, try and load the resource from the classpath using the path "/META-INF/dojo/dojo.js" and
|
||||
serve the resource if found.
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
For convenience, the external javascript libraries that the Spring Faces components depend on are made available in seperate
|
||||
jar files, and will be automatically loaded by the components when needed using the proper resource URLs. Since the resource loading
|
||||
mechanism checks in the web app classpath first it is possible to, for example, override the provided resources with a custom build of the
|
||||
Dojo or Ext library that is optimized for the particular application.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>Using The Spring Faces Client Side Validation Components</title>
|
||||
<para>
|
||||
Spring Faces provides three different client-side validator components:
|
||||
</para>
|
||||
<para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<sf:clientTextValidator> - Provides validation with customizable error messages for text fields.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<sf:clientNumberValidator> - Provides validation and input filtering with customizable error messages for numeric
|
||||
fields.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<sf:clientDateValidator> - Provides validation and a rich popup date picker control with customizable error
|
||||
messages for date fields.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<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.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>
|
||||
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:
|
||||
</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
<sf:clientDateValidator required="true">
|
||||
<h:inputText id="checkinDate" value="#{booking.checkinDate}" required="true">
|
||||
<f:convertDateTime pattern="yyyy-MM-dd" timeZone="EST"/>
|
||||
</h:inputText>
|
||||
</sf:clientDateValidator>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
In general, each of the available validations has a corresponding sensible default error message. The error messages
|
||||
can be overridden via the component's "invalidMessage" attribute. All of the customizable message attributes are
|
||||
value-binding aware so that expressions may be used to bind to keys in the application message bundle if so desired.
|
||||
</para>
|
||||
<para>
|
||||
Please refer to the javadocs of the component classes to see all of the attributes for the components. More
|
||||
extensive taglib docs will be available with the final release of Spring Web Flow 2.0.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>Using Ext Version of The Spring Faces Client Side Validation Components</title>
|
||||
<para>
|
||||
An alternate version of the components based on the Ext library is provided under a separate tag namespace.
|
||||
In order to utilize them, the following namespace declaration must be added to the header of a Facelets view template:
|
||||
</para>
|
||||
<programlisting>
|
||||
xmlns:sfe="http://www.springframework.org/tags/faces-ext"
|
||||
</programlisting>
|
||||
<para>
|
||||
The basic behavior of the Ext versions of the components is the same, but the tags have different attributes that correspond with the attributes
|
||||
of the underlying Ext widgets. Please refer to the javadocs of the component classes to see all of the attributes for the components. More
|
||||
extensive taglib docs will be available with the final release of Spring Web Flow 2.0.
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-sample">
|
||||
<title>Spring Web Flow JSF Integration Samples</title>
|
||||
<para>
|
||||
See the booking-jsf sample that provides a complete example of Spring Web Flow
|
||||
operating in a JSF environment, including use of flow-managed persistence, EL integration, and the
|
||||
client-side JSF validator components of Spring Faces.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||