flowexecutionimpl.java
来自「spring的WEB开发插件,支持多状态WEB开发」· Java 代码 · 共 536 行 · 第 1/2 页
JAVA
536 行
/*
* 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.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.webflow.Event;
import org.springframework.webflow.Flow;
import org.springframework.webflow.FlowNavigationException;
import org.springframework.webflow.FlowSession;
import org.springframework.webflow.FlowSessionStatus;
import org.springframework.webflow.RequestContext;
import org.springframework.webflow.State;
import org.springframework.webflow.StateContext;
import org.springframework.webflow.TransitionableState;
import org.springframework.webflow.ViewDescriptor;
import org.springframework.webflow.access.FlowLocator;
import org.springframework.webflow.util.RandomGuid;
/**
* Default implementation of FlowExecution that uses a stack-based data
* structure to manage {@link org.springframework.webflow.FlowSession flow sessions}.
* This class is closely coupled with <code>FlowSessionImpl</code> and
* <code>StateContextImpl</code>. The three classes work together to form a complete
* flow execution implementation.
* <p>
* This implementation of FlowExecution is serializable so it can be safely
* stored in an HTTP session or other persistent store such as a file, database, or
* client-side form field.
* <p>
* Note: this implementation synchronizes both execution entry points
* {@link #start(Event)} and {@link #signalEvent(Event)}. They are locked on a
* per client basis for this flow execution. Synchronization prevents a client
* from being able to signal other events before previously signaled ones have
* processed in-full, preventing possible race conditions.
*
* @see org.springframework.webflow.FlowSession
* @see org.springframework.webflow.execution.FlowSessionImpl
* @see org.springframework.webflow.execution.StateContextImpl
*
* @author Keith Donald
* @author Erwin Vervaet
*/
public class FlowExecutionImpl implements FlowExecution, Serializable {
// static logger because FlowExecutionImpl objects can be serialized
// and then restored
private static final Log logger = LogFactory.getLog(FlowExecutionImpl.class);
/**
* Key identifying this flow execution.
*/
private String key;
/**
* The time at which this object was created.
*/
private long creationTimestamp;
/**
* The execution's root flow; the top level flow that acts as the starting
* point for this flow execution.
*/
private transient Flow rootFlow;
/**
* Set only on deserialization so this object can be fully reconstructed.
*/
private String rootFlowId;
/**
* The id of the last event that was signaled in this flow execution.
* <p>
* Note that we're not storing the event itself because that would cause
* serialisation related issues.
*/
private String lastEventId;
/**
* The timestamp when the last request to manipulate this flow execution was processed.
*/
private long lastRequestTimestamp;
/**
* The stack of active, currently executing flow sessions. As subflows are
* spawned, they are pushed onto the stack. As they end, they are popped off
* the stack.
*/
private Stack executingFlowSessions = new Stack();
/**
* A thread-safe listener list, holding listeners monitoring the lifecycle
* of this flow execution.
*/
private transient FlowExecutionListenerList listenerList = new FlowExecutionListenerList();
/**
* The application transaction synchronization strategy to use.
*/
private transient TransactionSynchronizer transactionSynchronizer;
/**
* Create a new flow execution executing the provided flow.
* @param rootFlow the root flow of this flow execution
*/
public FlowExecutionImpl(Flow rootFlow) {
this(rootFlow, null, new FlowScopeTokenTransactionSynchronizer());
}
/**
* Create a new flow execution executing the provided flow.
* @param rootFlow the root flow of this flow execution
* @param listeners the listeners interested in flow execution lifecycle events
* @param transactionSynchronizer the application transaction synchronization
* strategy to use
*/
public FlowExecutionImpl(Flow rootFlow, FlowExecutionListener[] listeners,
TransactionSynchronizer transactionSynchronizer) {
Assert.notNull(rootFlow, "The root flow definition is required");
Assert.notNull(transactionSynchronizer, "The transaction synchronizer is required");
this.key = new RandomGuid().toString();
this.creationTimestamp = System.currentTimeMillis();
this.rootFlow = rootFlow;
this.getListeners().add(listeners);
this.transactionSynchronizer = transactionSynchronizer;
if (logger.isDebugEnabled()) {
logger.debug("Created new client execution with key: '" + key + "' for flow definition: '" + rootFlow.getId() + "'");
}
}
/**
* Returns the transaction synchronizer in use.
*/
public TransactionSynchronizer getTransactionSynchronizer() {
return transactionSynchronizer;
}
/**
* Set the transaction synchronization strategy to use.
*/
protected void setTransactionSynchronizer(TransactionSynchronizer transactionSynchronizer) {
this.transactionSynchronizer = transactionSynchronizer;
}
// implementing FlowExecutionStatistics
public String getKey() {
return key;
}
public String getCaption() {
StringBuffer caption = new StringBuffer();
if (isActive()) {
caption.append("[").append(getActiveSession().getStatus().getLabel()).append("] execution for flow '");
caption.append(getRootFlow().getId()).append("': [").append(getSessionPath()).append("]");
}
else {
caption.append("Inactive execution for flow '").append(getRootFlow().getId()).append("'");
}
caption.append("; key: '").append(getKey()).append("'");
return caption.toString();
}
/**
* Helper that return a string representation of the current
* flow session stack.
*/
private String getSessionPath() {
if (isActive()) {
StringBuffer qualifiedName = new StringBuffer(128);
Iterator it = executingFlowSessions.iterator();
while (it.hasNext()) {
FlowSession session = (FlowSession)it.next();
qualifiedName.append(session.getFlow().getId());
if (it.hasNext()) {
qualifiedName.append('.');
}
}
return qualifiedName.toString();
}
else {
return "";
}
}
public long getCreationTimestamp() {
return this.creationTimestamp;
}
public long getUptime() {
return System.currentTimeMillis() - this.creationTimestamp;
}
public long getLastRequestTimestamp() {
return this.lastRequestTimestamp;
}
/**
* Update the last request timestamp to now.
*/
protected void updateLastRequestTimestamp() {
this.lastRequestTimestamp = System.currentTimeMillis();
}
public String getLastEventId() {
return lastEventId;
}
/**
* Set the last event processed by this flow execution.
* @param lastEvent the last event to set
*/
protected void setLastEvent(Event lastEvent) {
Assert.notNull(lastEvent, "The last event is required");
this.lastEventId = lastEvent.getId();
}
public boolean isActive() {
return !executingFlowSessions.isEmpty();
}
public boolean isRootFlowActive() {
if (isActive()) {
return getActiveSession().isRoot();
}
else {
return false;
}
}
// implementing FlowExecutionContext
public Flow getRootFlow() {
return rootFlow;
}
public Flow getActiveFlow() {
return getActiveSession().getFlow();
}
public State getCurrentState() {
return getActiveSession().getCurrentState();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?