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 + -
显示快捷键?