flowexecutionimpl.java
来自「spring的WEB开发插件,支持多状态WEB开发」· Java 代码 · 共 536 行 · 第 1/2 页
JAVA
536 行
}
public FlowSession getActiveSession() {
return getActiveSessionInternal();
}
/**
* Check that this flow execution is active and throw an exception if it's not.
*/
protected void assertActive() throws IllegalStateException {
if (!isActive()) {
throw new IllegalStateException(
"No active flow sessions executing - this flow execution has ended (or has never been started)");
}
}
// methods implementing FlowExecution
public synchronized ViewDescriptor start(Event sourceEvent) throws IllegalStateException {
Assert.state(!isActive(), "This flow is already executing -- you cannot call start more than once");
updateLastRequestTimestamp();
if (logger.isDebugEnabled()) {
logger.debug("Start event signaled: " + sourceEvent);
}
StateContext context = createStateContext(sourceEvent);
getListeners().fireRequestSubmitted(context);
try {
ViewDescriptor viewDescriptor = context.spawn(rootFlow.getStartState(), new HashMap());
if (isActive()) {
getActiveSessionInternal().setStatus(FlowSessionStatus.PAUSED);
getListeners().firePaused(context);
}
return viewDescriptor;
}
finally {
getListeners().fireRequestProcessed(context);
}
}
public synchronized ViewDescriptor signalEvent(Event sourceEvent) throws FlowNavigationException, IllegalStateException {
assertActive();
updateLastRequestTimestamp();
if (logger.isDebugEnabled()) {
logger.debug("Resume event signaled: " + sourceEvent);
}
String stateId = sourceEvent.getStateId();
if (!StringUtils.hasText(stateId)) {
if (logger.isDebugEnabled()) {
logger.debug("Current state id was not provided in request to signal event '"
+ sourceEvent.getId()
+ "' in flow "
+ getCaption()
+ "' -- pulling current state id from session -- "
+ "note: if the user has been using the browser back/forward buttons, the currentState could be incorrect.");
}
stateId = getCurrentState().getId();
}
TransitionableState state = getActiveFlow().getRequiredTransitionableState(stateId);
if (!state.equals(getCurrentState())) {
if (logger.isDebugEnabled()) {
logger.debug("Event '" + sourceEvent.getId() + "' in state '" + state.getId()
+ "' was signaled by client; however the current flow execution state is '"
+ getCurrentState().getId() + "'; updating current state to '" + state.getId() + "'");
}
setCurrentState(state);
}
// execute the event
StateContextImpl context = createStateContext(sourceEvent);
getListeners().fireRequestSubmitted(context);
getActiveSessionInternal().setStatus(FlowSessionStatus.ACTIVE);
getListeners().fireResumed(context);
try {
ViewDescriptor viewDescriptor = state.onEvent(sourceEvent, context);
if (isActive()) {
getActiveSessionInternal().setStatus(FlowSessionStatus.PAUSED);
getListeners().firePaused(context);
}
return viewDescriptor;
}
finally {
getListeners().fireRequestProcessed(context);
}
}
public FlowExecutionListenerList getListeners() {
return listenerList;
}
// flow session management helpers
/**
* Create a flow execution state context for given event.
* <p>
* The default implementation uses the <code>StateContextImpl</code>
* class. Subclasses can override this to use a custom class.
* @param sourceEvent the event at the origin of this request
*/
protected StateContextImpl createStateContext(Event sourceEvent) {
return new StateContextImpl(sourceEvent, this);
}
/**
* Returns the currently active flow session.
* @throws IllegalStateException this execution is not active
*/
protected FlowSessionImpl getActiveSessionInternal() throws IllegalStateException {
assertActive();
return (FlowSessionImpl)executingFlowSessions.peek();
}
/**
* Returns the parent flow session of the currently active flow session.
* @return the parent flow session
* @throws IllegalArgumentException when this execution is not active or
* when the current flow session has no parent (e.g. is the root
* flow session)
*/
protected FlowSession getParentSession() throws IllegalArgumentException {
assertActive();
Assert.state(!getActiveSession().isRoot(), "There is no parent flow session for the currently active flow session");
return (FlowSession)executingFlowSessions.get(executingFlowSessions.size() - 2);
}
/**
* Returns the flow session associated with the root flow.
* @throws IllegalStateException this execution is not active
*/
protected FlowSession getRootSession() throws IllegalStateException {
assertActive();
return (FlowSession)executingFlowSessions.get(0);
}
/**
* Set the state that is currently active in this flow execution.
* @param newState the new current state
*/
protected void setCurrentState(State newState) {
getActiveSessionInternal().setCurrentState(newState);
}
/**
* Create a new flow session and activate it in this flow execution. This
* will push the flow session onto the stack and mark it as the active flow
* session.
* @param context the flow execution request context
* @param subflow the flow that should be associated with the flow session
* @param input the input parameters used to populate the flow session
* @return the created and activated flow session
*/
protected FlowSession activateSession(RequestContext context, Flow subflow, Map input) {
FlowSessionImpl session;
if (!executingFlowSessions.isEmpty()) {
FlowSessionImpl parent = getActiveSessionInternal();
parent.setStatus(FlowSessionStatus.SUSPENDED);
session = createFlowSession(subflow, input, parent);
}
else {
session = createFlowSession(subflow, input, null);
}
executingFlowSessions.push(session);
session.setStatus(FlowSessionStatus.ACTIVE);
if (logger.isDebugEnabled()) {
logger.debug("Activated: " + session);
}
return session;
}
/**
* Create a new flow session object. Subclasses can override this to return
* a special implementation if required.
* @param flow the flow that should be associated with the flow session
* @param input the input parameters used to populate the flow session
* @param parent the flow session that should be the parent of the newly
* created flow session
* @return the newly created flow session
*/
protected FlowSessionImpl createFlowSession(Flow flow, Map input, FlowSessionImpl parent) {
return new FlowSessionImpl(flow, input, parent);
}
/**
* End the active flow session of this flow execution. This will pop the top
* element from the stack and activate the new top flow session.
* @return the flow session that ended
*/
protected FlowSession endActiveFlowSession() {
FlowSessionImpl endingSession = (FlowSessionImpl)executingFlowSessions.pop();
endingSession.setStatus(FlowSessionStatus.ENDED);
if (logger.isDebugEnabled()) {
logger.debug("Ended: " + endingSession);
}
if (!executingFlowSessions.isEmpty()) {
getActiveSessionInternal().setStatus(FlowSessionStatus.ACTIVE);
if (logger.isDebugEnabled()) {
logger.debug("Resumed: " + getActiveSessionInternal());
}
}
return endingSession;
}
// custom serialization
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(this.key);
out.writeLong(this.creationTimestamp);
if (this.getRootFlow() != null) {
// avoid bogus NullPointerExceptions
out.writeObject(this.getRootFlow().getId());
}
else {
out.writeObject(null);
}
out.writeObject(this.lastEventId);
out.writeLong(this.lastRequestTimestamp);
out.writeObject(this.executingFlowSessions);
}
private void readObject(ObjectInputStream in) throws OptionalDataException, ClassNotFoundException, IOException {
this.key = (String)in.readObject();
this.creationTimestamp = in.readLong();
this.rootFlowId = (String)in.readObject();
this.lastEventId = (String)in.readObject();
this.lastRequestTimestamp = in.readLong();
this.executingFlowSessions = (Stack)in.readObject();
}
public synchronized void rehydrate(FlowLocator flowLocator, FlowExecutionListenerLoader listenerLoader,
TransactionSynchronizer transactionSynchronizer) {
// implementation note: we cannot integrate this code into the
// readObject() method since we need the flow locator, listener list and tx synchronizer!
if (this.rootFlow != null) {
// nothing to do, we're already hydrated
return;
}
Assert.notNull(rootFlowId, "The root flow id was not set during deserialization: cannot restore"
+ " -- was this flow execution deserialized properly?");
this.rootFlow = flowLocator.getFlow(rootFlowId);
this.rootFlowId = null;
// rehydrate all flow sessions
Iterator it = this.executingFlowSessions.iterator();
while (it.hasNext()) {
FlowSessionImpl session = (FlowSessionImpl)it.next();
session.rehydrate(flowLocator);
}
if (isActive()) {
// sanity check
Assert.isTrue(getRootFlow() == getRootSession().getFlow(),
"The root flow of the execution should be the same as the flow in the root flow session");
}
this.listenerList = new FlowExecutionListenerList();
this.listenerList.add(listenerLoader.getListeners(this.rootFlow));
this.transactionSynchronizer = transactionSynchronizer;
}
public String toString() {
if (!isActive()) {
return "[Empty FlowExecutionStack with key '" + getKey() + "'; no flows are active]";
}
else {
return new ToStringCreator(this)
.append("key", getKey())
.append("activeFlow", getActiveSession().getFlow().getId())
.append("currentState", getCurrentState().getId())
.append("rootFlow", getRootFlow().getId())
.append("executingFlowSessions", executingFlowSessions).toString();
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?