flowexecutionmanager.java
来自「spring的WEB开发插件,支持多状态WEB开发」· Java 代码 · 共 577 行 · 第 1/2 页
JAVA
577 行
/*
* 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.execution;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.binding.convert.ConversionService;
import org.springframework.core.style.StylerUtils;
import org.springframework.util.Assert;
import org.springframework.util.CachingMapDecorator;
import org.springframework.util.StringUtils;
import org.springframework.webflow.Event;
import org.springframework.webflow.Flow;
import org.springframework.webflow.FlowExecutionContext;
import org.springframework.webflow.ViewDescriptor;
import org.springframework.webflow.access.BeanFactoryFlowServiceLocator;
import org.springframework.webflow.access.FlowLocator;
import org.springframework.webflow.convert.FlowConversionService;
/**
* A manager for the executing flows of the application. This object is responsible for
* creating new flow executions as requested by the client, as well as signaling events
* for processing by existing, paused executions (that are waiting to be resumed in response
* to a user event).
* <p>
* The {@link #onEvent(Event)} method implements the following algorithm:
* <ol>
* <li>Look for a flow execution id in the event (in a parameter named
* "_flowExecutionId").</li>
* <li>If no flow execution id is found, a new flow execution is created.
* The top-level flow for which the execution is created is determined
* by first looking for a flow id specified in the event using the "_flowId"
* parameter. If this parameter is present the specified flow will be
* used, after lookup using a flow locator. If no "_flowId" parameter is
* present, the default top-level flow configured for this manager is used.</li>
* <li>If a flow execution id is found, the previously saved flow execution
* with that id is loaded from the storage.</li>
* <li>If a new flow execution was created in the previous steps, it is
* started.</li>
* <li>If an existing flow execution was loaded from storage, the current state id
* ("_currentStateId") and event id ("_eventId") parameter values are
* extracted from the event. The event is then signaled in that state, and
* the executing flow is resumed in that state.</li>
* <li>If the flow execution is still active after event processing, it
* is saved in storage. This process generates a unique flow execution
* id that will be exposed to the caller for reference on subsequent events.
* The caller will also be given access to the flow execution context and
* any data placed in request or flow scope.</li>
* </ol>
* <p>
* By default, this class will use the flow execution implementation provided
* by the <code>FlowExecutionImpl</code> class. If you would like to use a
* different implementation, just override the {@link #createFlowExecution(Flow)}
* method in a subclass.
*
* @see org.springframework.webflow.execution.FlowExecution
* @see org.springframework.webflow.execution.FlowExecutionStorage
*
* @author Erwin Vervaet
* @author Keith Donald
*/
public class FlowExecutionManager implements BeanFactoryAware, FlowExecutionListenerLoader {
/**
* Clients can send the id (name) of the flow to be started
* using an event parameter with this name ("_flowId").
*/
public static final String FLOW_ID_PARAMETER = "_flowId";
/**
* Clients can send the flow execution id using an event
* parameter with this name ("_flowExecutionId").
*/
public static final String FLOW_EXECUTION_ID_PARAMETER = "_flowExecutionId";
/**
* The id of the flow execution will be exposed to the view in a model
* attribute with this name ("flowExecutionId").
*/
public static final String FLOW_EXECUTION_ID_ATTRIBUTE = "flowExecutionId";
/**
* The flow context itself will be exposed to the view in a model
* attribute with this name ("flowExecutionContext").
*/
public static final String FLOW_EXECUTION_CONTEXT_ATTRIBUTE = "flowExecutionContext";
/**
* The current state of the flow execution will be exposed to the view in a
* model attribute with this name ("currentStateId").
*/
public static final String CURRENT_STATE_ID_ATTRIBUTE = "currentStateId";
/**
* Event id value indicating that the event has not been set ("@NOT_SET@").
*/
public static final String NOT_SET_EVENT_ID = "@NOT_SET@";
protected final Log logger = LogFactory.getLog(FlowExecutionManager.class);
private Flow flow;
private FlowLocator flowLocator = new BeanFactoryFlowServiceLocator();
/**
* A map of all know flow execution listeners (the key) and their associated
* flow execution listener criteria objects (a list -- the value).
*/
private CachingMapDecorator flowExecutionListeners = new CachingMapDecorator() {
protected Object create(Object key) {
return new LinkedList();
}
};
private FlowExecutionStorage storage;
private TransactionSynchronizer transactionSynchronizer = new FlowScopeTokenTransactionSynchronizer();
private ConversionService conversionService = new FlowConversionService();
private BeanFactory beanFactory;
/**
* Create a new flow execution manager. Before use, the manager should
* be appropriately configured using setter methods. At least the flow
* execution storage strategy should be set!
*
* @see #setFlow(Flow)
* @see #setFlowLocator(FlowLocator)
* @see #setListener(FlowExecutionListener)
* @see #setListener(FlowExecutionListener, FlowExecutionListenerCriteria)
* @see #setListenerMap(Map)
* @see #setListeners(Collection)
* @see #setListeners(Collection, FlowExecutionListenerCriteria)
* @see #setStorage(FlowExecutionStorage)
* @see #setTransactionSynchronizer(TransactionSynchronizer)
* @see #setConversionService(ConversionService)
*/
public FlowExecutionManager() {
}
/**
* Returns the flow whose executions are managed by this manager.
* Could be <code>null</code> if there is no preconfigured flow and
* the id of the flow for which executions will be managed is sent
* in an event parameter "_flowId".
*/
protected Flow getFlow() {
return flow;
}
/**
* Set the flow whose executions will be managed if there is no alternate
* flow id specified in a "_flowId" event parameter.
*/
public void setFlow(Flow flow) {
this.flow = flow;
}
/**
* Returns the flow locator to use for lookup of flows specified using the
* "_flowId" event parameter.
*/
protected FlowLocator getFlowLocator() {
return flowLocator;
}
/**
* Set the flow locator to use for lookup of flows specified using the
* "_flowId" event parameter.
*/
public void setFlowLocator(FlowLocator flowLocator) {
this.flowLocator = flowLocator;
}
/**
* Returns the array of flow execution listeners for specified flow.
* @param flow the flow definition associated with the execution to be listened to
* @return the flow execution listeners
*/
public FlowExecutionListener[] getListeners(Flow flow) {
Assert.notNull(flow, "The Flow to load listeners for cannot be null");
List listeners = new LinkedList();
for (Iterator entryIt = flowExecutionListeners.entrySet().iterator(); entryIt.hasNext(); ) {
Map.Entry entry = (Map.Entry)entryIt.next();
for (Iterator criteriaIt = ((List)entry.getValue()).iterator(); criteriaIt.hasNext(); ) {
FlowExecutionListenerCriteria criteria = (FlowExecutionListenerCriteria)criteriaIt.next();
if (criteria.applies(flow)) {
// the criteria 'guarding' this flow execution listener is
// telling us that the listener applies to the flow
listeners.add((FlowExecutionListener)entry.getKey());
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + listeners.size() + " of possible " + flowExecutionListeners.size() + " listeners to this execution request for flow: '" + flow.getId()
+ "', the listeners to attach are: " + StylerUtils.style(listeners));
}
return (FlowExecutionListener[])listeners.toArray(new FlowExecutionListener[listeners.size()]);
}
/**
* Set the flow execution listener that will be notified of managed
* flow executions.
*/
public void setListener(FlowExecutionListener listener) {
setListeners(Collections.singleton(listener));
}
/**
* Set the flow execution listener that will be notified of managed
* flow executions for the flows that match given criteria.
*/
public void setListener(FlowExecutionListener listener, FlowExecutionListenerCriteria criteria) {
setListeners(Collections.singleton(listener), criteria);
}
/**
* Sets the flow execution listeners that will be notified of managed
* flow executions.
*/
public void setListeners(Collection listeners) {
setListeners(listeners, FlowExecutionListenerCriteriaFactory.allFlows());
}
/**
* Sets the flow execution listeners that will be notified of managed
* flow executions for flows that match given criteria.
*/
public void setListeners(Collection listeners, FlowExecutionListenerCriteria criteria) {
for (Iterator it = listeners.iterator(); it.hasNext(); ) {
FlowExecutionListener listener = (FlowExecutionListener)it.next();
List registeredCriteria = (List)flowExecutionListeners.get(listener);
registeredCriteria.add(criteria);
}
}
/**
* Sets the flow execution listeners that will be notified of managed
* flow executions. The map keys may be individual flow execution listener instances or
* collections of execution listener instances. The map values can either
* be string encoded flow execution listener criteria or direct
* <code>FlowExecutionListenerCriteria</code> objects.
*/
public void setListenerMap(Map listenerCriteriaMap) {
Iterator it = listenerCriteriaMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
FlowExecutionListenerCriteria criteria;
if (entry.getValue() instanceof FlowExecutionListenerCriteria) {
criteria = (FlowExecutionListenerCriteria)entry.getValue();
}
else {
// string encoded
criteria =
(FlowExecutionListenerCriteria)getConversionService().
getConversionExecutor(String.class, FlowExecutionListenerCriteria.class).execute(entry.getValue());
}
if (entry.getKey() instanceof Collection) {
setListeners((Collection)entry.getKey(), criteria);
}
else {
setListener((FlowExecutionListener)entry.getKey(), criteria);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?