|
From: Keith D. <ke...@in...> - 2005-04-25 06:26:57
|
The SWF team has gotten closer to finalizing the major new features for PR3.
After debating these vigorously this weekend, we're pretty happy with
them-but are seeking additional feedback.
Here they are, all available now in CVS:
- Transition actions: on the occurrence of an event, this provides the
ability to execute an action after a state transition is matched but before
the transition is executed. In this case, the action result event is
adapted to a boolean expression--if true, the transition to the target state
proceeds, if false, the current state is re-entered. By default a 'success'
action result is mapped to true, anything else is mapped to false.
The biggest use-case for this is in executing so-called 'cross-cutting'
actions that have a logical 'success' or 'error' result -- like
bindAndValidate.
Here's an example:
Code:
<view-state id="enterPriceAndItemCount" view="priceAndItemCountForm">
<transition on="submit" to="enterCategory">
<action bean="sellItemAction" method="bindAndValidate">
<property name="validatorMethod"
value="validatePriceAndItemCount"/>
</action>
</transition>
</view-state>
This reduces flow def LoC substantially in the typical 'wizard' flow cases,
as previously you were forced to define a separate action state for each
ViewState needing 'on submit' bindAndValidate behaivior.
- Enhanced FlowExecutionListener lifecycle callbacks, including new
'flowStarting', and 'stateEntering' and 'stateEntered' methods. The first
two can be used to test state preconditions (invariants that must hold true
for a new state to be allowed to enter). 'stateEntered' can be used to test
state postconditions (invariants that must hold true after a state has
entered). The new 'StateConditionTester' strategy makes this easily
pluggable behind a simple facade interface. 'Sell item' demonstrates this in
CVS now-specifically, treating a user role-security-check as a state
precondition.
- State properties. States can now have arbitrary property metadata, just
like actions. For example:
Code:
<action-state id="setupForm">
<action bean="sellItemAction"/>
<transition on="success" to="enterPriceAndItemCount"/>
<property name="role" value="manager"/>
</action-state>
The above example assigns the 'role' property to the 'setupForm' state with
value 'manager'.
State properties can be reasoned on by StateConditionTesters, views, or
actions. For example, the SellItemStateConditionTester checks the 'role'
property for the state that has been requested to enter and verifies the
authenticated user has that role before allowing the state transition to
complete.
- A decision state and a decision action. These constructs allow you to
evaluate one or more expressions to decide "where to go next" in a reusable
way:
The decision state:
Code:
<decision-state id="requiresShipping">
<if test="${flowScope.sale.shipping}" then="enterShippingDetails"
else="showCostOverview"/>
</decision-state>
The equivalent decision action:
Code:
<action-state id="requiresShipping">
<action class="org.springframework.web.flow.action.DecisionAction">
<property name="criteria" value="${flowScope.sale.shipping}"/>
</action>
<transition on="true" to="enterShippingDetails"/>
<transition on="false" to="showCostOverview"/>
</action-state>
Erwin and I have debated whether we really need first class support for the
decision state (as you could use the DecisionAction from a action state),
but it just seems so elegant and sexy and flexible, with little introduced
complexity--so right now we feel its a keeper. Please let us know if you
agree or disagree.
Putting it all together, from sell item:
Before new PR3 features:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE webflow PUBLIC "-//SPRING//DTD WEBFLOW//EN"
"http://www.springframework.org/dtd/spring-webflow.dtd">
<webflow id="sellItem" start-state="setupForm">
<action-state id="setupForm">
<action bean="sellItemAction"/>
<transition on="success" to="enterPriceAndItemCount"/>
</action-state>
<view-state id="enterPriceAndItemCount" view="priceAndItemCountForm">
<transition on="submit" to="bindAndValidatePriceAndItemCount"/>
</view-state>
<action-state id="bindAndValidatePriceAndItemCount">
<action bean="sellItemAction" method="bindAndValidate">
<property name="validatorMethod"
value="validatePriceAndItemCount"/>
</action>
<transition on="success" to="enterCategory"/>
<transition on="error" to="enterPriceAndItemCount"/>
</action-state>
<view-state id="enterCategory" view="categoryForm">
<transition on="submit" to="bindAndValidateCategory"/>
</view-state>
<action-state id="bindAndValidateCategory">
<action bean="sellItemAction" method="bindAndValidate"/>
<transition on="${#result == 'success' and flowScope.sale.shipping}"
to="enterShippingDetails"/>
<transition on="${#result == 'success' and !flowScope.sale.shipping}"
to="showCostOverview"/>
<transition on="error" to="enterCategory"/>
</action-state>
<view-state id="enterShippingDetails" view="shippingDetailsForm">
<transition on="submit" to="bindAndValidateShippingDetails"/>
</view-state>
<action-state id="bindAndValidateShippingDetails">
<action bean="sellItemAction" method="bindAndValidate"/>
<transition on="success" to="showCostOverview"/>
<transition on="error" to="enterShippingDetails"/>
</action-state>
<end-state id="showCostOverview" view="costOverview"/>
</webflow>
After New PR3 Features:
Code:
<webflow id="sellItem" start-state="setupForm">
<action-state id="setupForm">
<action bean="sellItemAction"/>
<transition on="success" to="enterPriceAndItemCount"/>
<property name="role" value="manager"/>
</action-state>
<view-state id="enterPriceAndItemCount" view="priceAndItemCountForm">
<transition on="submit" to="enterCategory">
<action bean="sellItemAction" method="bindAndValidate">
<property name="validatorMethod"
value="validatePriceAndItemCount"/>
</action>
</transition>
</view-state>
<view-state id="enterCategory" view="categoryForm">
<transition on="submit" to="requiresShipping">
<action bean="sellItemAction" method="bindAndValidate"/>
</transition>
</view-state>
<decision-state id="requiresShipping">
<if test="${flowScope.sale.shipping}" then="enterShippingDetails"
else="showCostOverview"/>
</decision-state>
<view-state id="enterShippingDetails" view="shippingDetailsForm">
<transition on="submit" to="showCostOverview">
<action bean="sellItemAction" method="bindAndValidate"/>
</transition>
</view-state>
<end-state id="showCostOverview" view="costOverview"/>
</webflow>
_________________
Keith Donald
Interface21 - http://www.springframework.com - Spring Training, Consulting,
and Support - "From the Source"
|