📄 abstractflowbuilder.java
字号:
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.webflow.config;
import java.util.HashMap;
import java.util.Map;
import org.springframework.util.StringUtils;
import org.springframework.webflow.Action;
import org.springframework.webflow.ActionState;
import org.springframework.webflow.AnnotatedAction;
import org.springframework.webflow.EndState;
import org.springframework.webflow.Flow;
import org.springframework.webflow.FlowAttributeMapper;
import org.springframework.webflow.SubflowState;
import org.springframework.webflow.Transition;
import org.springframework.webflow.TransitionCriteria;
import org.springframework.webflow.TransitionCriteriaFactory;
import org.springframework.webflow.ViewDescriptorCreator;
import org.springframework.webflow.ViewState;
import org.springframework.webflow.access.AutowireMode;
import org.springframework.webflow.access.FlowServiceLocator;
import org.springframework.webflow.access.ServiceLookupException;
import org.springframework.webflow.action.DelegatingAction;
import org.springframework.webflow.action.MultiAction;
import org.springframework.webflow.support.ActionTransitionCriteria;
/**
* Base class for flow builders that programmatically build flows in Java
* configuration code.
* <p>
* To give you an example of what a simple Java-based web flow builder
* definition might look like, the following example defines the 'dynamic' web
* flow roughly equivalent to the work flow statically implemented in Spring
* MVC's simple form controller:
*
* <pre>
* public class CustomerDetailFlowBuilder extends AbstractFlowBuilder {
* protected String flowId() {
* return "customerDetails";
* }
*
* public void buildStates() {
* // get customer information
* addActionState("getDetails",
* action(GetCustomerAction.class, AutowireMode.BY_TYPE),
* on(success(), "displayDetails"));
* // view customer information
* addViewState("displayDetails", "customerDetails",
* on(submit(), "bindAndValidate");
* // bind and validate customer information updates
* addActionState("bindAndValidate",
* method("bindAndValidate", action("customerAction")),
* new Transition[] {
* on(error(), "displayDetails"),
* on(success(), "finish")
* });
* // finish
* addEndState("finish");
* }
* }
* </pre>
*
* What this Java-based FlowBuilder implementation does is add four states to a
* flow identified as "customerDetails". These include a "get"
* <code>ActionState</code> (the start state), a <code>ViewState</code>
* state, a "bind and validate" <code>ActionState</code>, and an end marker
* state (<code>EndState</code>).
*
* The first state, an action state, will be assigned the indentifier
* <code>getDetails</code>. This action state will automatically be
* configured with the following defaults:
* <ol>
* <li>An autowired action instance of <code>GetCustomerDetails.class</code>. This is
* the <code>Action</code> implementation that will execute when this state is
* entered. In this example, that <code>Action</code> will go out to the DB,
* load the Customer, and put it in the Flow's request context.
* <li>A <code>success</code> transition to a default view state, called
* <code>displayDetails</code>. This means when the get <code>Action</code>
* returns a <code>success</code> result event (aka outcome), the <code>displayDetails</code>
* state will be entered.
* <li>It will act as the start state for this flow (by default, the first
* state added to a flow during the build process is treated as the start
* state).
* </ol>
*
* The second state, a view state, will be identified as <code>displayDetails</code>.
* This view state will automatically be configured with the following defaults:
* <ol>
* <li>A view name called <code>customerDetails</code> -- this is the
* logical name of a view resource. This logical view name gets mapped to a
* physical view resource (jsp, etc.) by the calling front controller (via a
* Spring view resolver, or a Struts action forward, for example).
* <li>A <code>submit</code> transition to a bind and validate action state,
* indentified by the default id <code>bindAndValidate</code>. This means
* when a <code>submit</code> event is signaled by the view (for example, on a
* submit button click), the bindAndValidate action state will be entered and
* the <code>bindAndValidate</code> method of the
* <code>customerAction</code> <code>Action</code> implementation
* will be executed.
* </ol>
*
* The third state, an action state, will be indentified as <code>
* bindAndValidate</code>. This action state will automatically be configured
* with the following defaults:
* <ol>
* <li>An action bean named <code>customerAction</code> --
* this is the name of the <code>Action</code> implementation exported in the application
* context that will execute when this state is entered. In this example, the
* <code>Action</code> has a "bindAndValidate" method that
* will bind form input in the HTTP request to a backing Customer form
* object, validate it, and update the DB.
* <li>A <code>success</code> transition to a default end state, called
* <code>finish</code>. This means if the <code>Action</code> returns a
* <code>success</code> result, the <code>finish</code> end state will be
* transitioned to and the flow will terminate.
* <li>An <code>error</code> transition back to the form view. This means if
* the <code>Action</code> returns an <code>error</code> event, the <code>
* displayDetails</code> view state will be transitioned back to.
* </ol>
*
* The fourth and last state, an end state, will be indentified with the default
* end state id <code>finish</code>. This end state is a marker that signals
* the end of the flow. When entered, the flow session terminates, and if this
* flow is acting as a root flow in the current flow execution, any
* flow-allocated resources will be cleaned up. An end state can optionally be
* configured with a logical view name to forward to when entered. It will also
* trigger a state transition in a resuming parent flow if this flow was
* participating as a spawned 'subflow' within a suspended parent flow.
*
* @author Keith Donald
* @author Erwin Vervaet
*/
public abstract class AbstractFlowBuilder extends BaseFlowBuilder {
/**
* Create an instance of a abstract flow builder; default constructor.
*/
protected AbstractFlowBuilder() {
super();
}
/**
* Create an instance of an abstract flow builder, using the specified
* service locator to obtain needed flow services during configuation.
* @param flowServiceLocator the service locator
*/
protected AbstractFlowBuilder(FlowServiceLocator flowServiceLocator) {
super(flowServiceLocator);
}
public final Flow init() throws FlowBuilderException {
Flow flow = getFlowServiceLocator().createFlow(AutowireMode.DEFAULT);
flow.setId(flowId());
flow.setProperties(flowProperties());
setFlow(flow);
return flow;
}
/**
* Returns the id (name) of the flow built by this builder. Subclasses
* should override to return the unique flowId.
* @return the unique flow id
*/
protected abstract String flowId();
/**
* Hook subclasses may override to provide additional properties about the flow built by
* this builder. Returns <code>null</code> by default.
* @return additional properties describing the flow being built
*/
protected Map flowProperties() {
return null;
}
public void dispose() {
setFlow(null);
}
/**
* Adds a <code>ViewState</code> to the flow built by this builder. A view
* state triggers the rendering of a view template when entered.
* @param stateId the <code>ViewState</code> id; must be locally unique
* to the flow built by this builder
* @param viewName the name of the logical view to render; this name
* will be mapped to a physical resource template such as a JSP when
* the ViewState is entered and control returns to the front
* controller
* @param transition a single supported transition for this state, mapping a
* path from this state to another state (triggered by an event)
* @return the view state
* @throws IllegalArgumentException the stateId was not unique
*/
protected ViewState addViewState(String stateId, String viewName, Transition transition)
throws IllegalArgumentException {
return new ViewState(getFlow(), stateId, view(viewName), transition);
}
/**
* Adds a <code>ViewState</code> to the flow built by this builder. A view
* state triggers the rendering of a view template when entered.
* @param stateId the <code>ViewState</code> id; must be unique in the
* context of the flow built by this builder
* @param viewName the name of the logical view to render; this name
* will be mapped to a physical resource template such as a JSP when
* the ViewState is entered and control returns to the front
* controller
* @param transitions the supported transitions for this state, where each
* transition maps a path from this state to another state (triggered
* by an event)
* @return the view state
* @throws IllegalArgumentException the stateId was not unique
*/
protected ViewState addViewState(String stateId, String viewName, Transition[] transitions)
throws IllegalArgumentException {
return new ViewState(getFlow(), stateId, view(viewName), transitions);
}
/**
* Adds a <code>ViewState</code> to the flow built by this builder. A view
* state triggers the rendering of a view template when entered.
* @param stateId the <code>ViewState</code> id; must be unique in the
* context of the flow built by this builder
* @param viewName the name of the logical view to render; this name
* will be mapped to a physical resource template such as a JSP when
* the ViewState is entered and control returns to the front
* controller
* @param transitions the supported transitions for this state, where each
* transition maps a path from this state to another state (triggered
* by an event)
* @param properties additional properties describing the state
* @return the view state
* @throws IllegalArgumentException the stateId was not unique
*/
protected ViewState addViewState(String stateId, String viewName, Transition[] transitions, Map properties)
throws IllegalArgumentException {
return new ViewState(getFlow(), stateId, view(viewName), transitions, properties);
}
/**
* Turn given view name into a corresponding view descriptor creator.
* @param viewName the view name (might be encoded)
* @return the corresponding view descriptor creator
*/
protected ViewDescriptorCreator view(String viewName) {
return (ViewDescriptorCreator)fromStringTo(ViewDescriptorCreator.class).execute(viewName);
}
/**
* Adds a <code>ViewState</code> to the flow built by this builder. A view
* state triggers the rendering of a view template when entered.
* @param stateId the <code>ViewState</code> id; must be unique in the
* context of the flow built by this builder
* @param creater the factory to produce a descriptor noting the name
* of the logical view to render; this name will be mapped to a physical
* resource template such as a JSP when the ViewState is entered and control
* returns to the front controller
* @param transitions the supported transitions for this state, where each
* transition maps a path from this state to another state (triggered
* by an event)
* @param properties additional properties describing the state
* @return the view state
* @throws IllegalArgumentException the stateId was not unique
*/
protected ViewState addViewState(String stateId, ViewDescriptorCreator creater, Transition[] transitions, Map properties)
throws IllegalArgumentException {
return new ViewState(getFlow(), stateId, creater, transitions, properties);
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -