flow execution status
This commit is contained in:
@@ -84,9 +84,9 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
private transient Flow flow;
|
||||
|
||||
/**
|
||||
* A flag indicating if this execution has started.
|
||||
* A enum tracking the status of this flow execution.
|
||||
*/
|
||||
private boolean started;
|
||||
private FlowExecutionStatus status;
|
||||
|
||||
/**
|
||||
* The stack of active, currently executing flow sessions. As subflows are spawned, they are pushed onto the stack.
|
||||
@@ -144,11 +144,12 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
public FlowExecutionImpl(Flow flow) {
|
||||
Assert.notNull(flow, "The flow definition is required");
|
||||
this.flow = flow;
|
||||
this.listeners = new FlowExecutionListeners();
|
||||
this.attributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP;
|
||||
this.flowSessions = new LinkedList();
|
||||
this.conversationScope = new LocalAttributeMap();
|
||||
this.conversationScope.put(FLASH_SCOPE_ATTRIBUTE, new LocalAttributeMap());
|
||||
status = FlowExecutionStatus.NOT_STARTED;
|
||||
listeners = new FlowExecutionListeners();
|
||||
attributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP;
|
||||
flowSessions = new LinkedList();
|
||||
conversationScope = new LocalAttributeMap();
|
||||
conversationScope.put(FLASH_SCOPE_ATTRIBUTE, new LocalAttributeMap());
|
||||
}
|
||||
|
||||
public String getCaption() {
|
||||
@@ -166,7 +167,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
}
|
||||
|
||||
public boolean hasStarted() {
|
||||
return started;
|
||||
return status != FlowExecutionStatus.NOT_STARTED;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
@@ -174,7 +175,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
}
|
||||
|
||||
public boolean hasEnded() {
|
||||
return hasStarted() && !isActive();
|
||||
return status == FlowExecutionStatus.ENDED;
|
||||
}
|
||||
|
||||
public FlowExecutionOutcome getOutcome() {
|
||||
@@ -182,12 +183,11 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
}
|
||||
|
||||
public FlowSession getActiveSession() {
|
||||
if (!isActive()) {
|
||||
if (started) {
|
||||
throw new IllegalStateException("No active session to access; this flow execution has ended");
|
||||
} else {
|
||||
throw new IllegalStateException("No active session to access; this flow execution has not been started");
|
||||
}
|
||||
if (status == FlowExecutionStatus.NOT_STARTED) {
|
||||
throw new IllegalStateException("No active session to access; this flow execution has not been started");
|
||||
}
|
||||
if (status == FlowExecutionStatus.ENDED) {
|
||||
throw new IllegalStateException("No active session to access; this flow execution has ended");
|
||||
}
|
||||
return getActiveSessionInternal();
|
||||
}
|
||||
@@ -208,11 +208,11 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
|
||||
public void start(MutableAttributeMap input, ExternalContext externalContext) throws FlowExecutionException,
|
||||
IllegalStateException {
|
||||
Assert.state(!started, "This flow has already been started; you cannot call 'start()' more than once");
|
||||
Assert.state(!hasStarted(), "This flow has already been started; you cannot call 'start()' more than once");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Starting in " + externalContext + " with input " + input);
|
||||
}
|
||||
started = true;
|
||||
status = FlowExecutionStatus.STARTING;
|
||||
MessageContext messageContext = createMessageContext(null);
|
||||
RequestControlContext requestContext = createRequestContext(externalContext, messageContext);
|
||||
RequestContextHolder.setRequestContext(requestContext);
|
||||
@@ -242,13 +242,7 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
}
|
||||
|
||||
public void resume(ExternalContext externalContext) throws FlowExecutionException, IllegalStateException {
|
||||
if (!isActive()) {
|
||||
if (started) {
|
||||
throw new IllegalStateException("This flow execution cannot be resumed; it has ended");
|
||||
} else {
|
||||
throw new IllegalStateException("This flow execution cannot be resumed; it has not been started");
|
||||
}
|
||||
}
|
||||
Assert.state(status == FlowExecutionStatus.STARTED, "This flow execution cannot be resumed; it is not active");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Resuming in " + externalContext);
|
||||
}
|
||||
@@ -291,11 +285,11 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
*/
|
||||
public void setCurrentState(String stateId) {
|
||||
FlowSessionImpl session;
|
||||
if (started) {
|
||||
session = getActiveSessionInternal();
|
||||
} else {
|
||||
if (status == FlowExecutionStatus.NOT_STARTED) {
|
||||
session = activateSession(flow);
|
||||
started = true;
|
||||
status = FlowExecutionStatus.STARTED;
|
||||
} else {
|
||||
session = getActiveSessionInternal();
|
||||
}
|
||||
State state = session.getFlow().getStateInstance(stateId);
|
||||
session.setCurrentState(state);
|
||||
@@ -341,6 +335,9 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
void start(Flow flow, MutableAttributeMap input, RequestControlContext context) {
|
||||
listeners.fireSessionCreating(context, flow);
|
||||
FlowSession session = activateSession(flow);
|
||||
if (session.isRoot()) {
|
||||
status = FlowExecutionStatus.STARTED;
|
||||
}
|
||||
if (input == null) {
|
||||
input = new LocalAttributeMap();
|
||||
}
|
||||
@@ -379,13 +376,17 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
|
||||
void endActiveFlowSession(String outcome, MutableAttributeMap output, RequestControlContext context) {
|
||||
FlowSessionImpl session = getActiveSessionInternal();
|
||||
if (session.isRoot()) {
|
||||
status = FlowExecutionStatus.ENDING;
|
||||
}
|
||||
listeners.fireSessionEnding(context, session, outcome, output);
|
||||
session.getFlow().end(context, outcome, output);
|
||||
flowSessions.removeLast();
|
||||
boolean executionEnded = hasEnded();
|
||||
boolean executionEnded = flowSessions.isEmpty();
|
||||
if (executionEnded) {
|
||||
// set the root flow execution outcome for external clients to use
|
||||
this.outcome = new FlowExecutionOutcome(outcome, output);
|
||||
status = FlowExecutionStatus.ENDED;
|
||||
}
|
||||
listeners.fireSessionEnded(context, session, outcome, output);
|
||||
if (!executionEnded) {
|
||||
@@ -418,6 +419,9 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
|
||||
TransitionDefinition getMatchingTransition(String eventId) {
|
||||
FlowSessionImpl session = getActiveSessionInternal();
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
TransitionableState currentState = (TransitionableState) session.getState();
|
||||
TransitionDefinition transition = currentState.getTransition(eventId);
|
||||
if (transition == null) {
|
||||
@@ -509,12 +513,12 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
// custom serialization (implementation of Externalizable for optimized storage)
|
||||
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
started = in.readBoolean();
|
||||
status = (FlowExecutionStatus) in.readObject();
|
||||
flowSessions = (LinkedList) in.readObject();
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeBoolean(started);
|
||||
out.writeObject(status);
|
||||
out.writeObject(flowSessions);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.springframework.webflow.engine.impl;
|
||||
|
||||
import org.springframework.core.enums.StaticLabeledEnum;
|
||||
|
||||
/**
|
||||
* A enum used internally by {@link FlowExecutionImpl} to track its status. Flow Executions initially start out in
|
||||
* NOT_STARTED. After start is called, they are STARTING. Once the root session is activated, they have STARTED. When
|
||||
* the execution begins to end, their status is ENDING. After ending, their status is updated to ENDED.
|
||||
*/
|
||||
public class FlowExecutionStatus extends StaticLabeledEnum {
|
||||
|
||||
/**
|
||||
* The flow execution has not yet started.
|
||||
*/
|
||||
public static final FlowExecutionStatus NOT_STARTED = new FlowExecutionStatus(0, "Not Started");
|
||||
|
||||
/**
|
||||
* The flow execution is in the process of starting; the root session has not yet been activated.
|
||||
*/
|
||||
public static final FlowExecutionStatus STARTING = new FlowExecutionStatus(1, "Starting");
|
||||
|
||||
/**
|
||||
* The flow execution has started and a session is active.
|
||||
*/
|
||||
public static final FlowExecutionStatus STARTED = new FlowExecutionStatus(2, "Started");
|
||||
|
||||
/**
|
||||
* The flow execution is ending.
|
||||
*/
|
||||
public static final FlowExecutionStatus ENDING = new FlowExecutionStatus(3, "Ending");
|
||||
|
||||
/**
|
||||
* The flow execution has ended.
|
||||
*/
|
||||
public static final FlowExecutionStatus ENDED = new FlowExecutionStatus(4, "Ended");
|
||||
|
||||
private FlowExecutionStatus(int code, String label) {
|
||||
super(code, label);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,11 +66,9 @@ public interface FlowExecutionContext {
|
||||
public boolean hasStarted();
|
||||
|
||||
/**
|
||||
* Is the flow execution active?
|
||||
* <p>
|
||||
* All methods on an active flow execution context can be called successfully. If the flow execution is not active,
|
||||
* a caller cannot access some methods such as {@link #getActiveSession()}.
|
||||
* @return true if active, false if the flow execution has terminated
|
||||
* Is the flow execution active? A flow execution is active once it has started and remains active until it has
|
||||
* ended.
|
||||
* @return true if active, false if the flow execution has terminated or has not yet started
|
||||
*/
|
||||
public boolean isActive();
|
||||
|
||||
@@ -91,11 +89,10 @@ public interface FlowExecutionContext {
|
||||
|
||||
/**
|
||||
* Returns the active flow session of this flow execution. The active flow session is the currently executing
|
||||
* session -- it may be the "root flow" session, or it may be a subflow session if this flow execution has spawned a
|
||||
* subflow.
|
||||
* session. It may be the "root flow" session, or it may be a subflow session if this flow execution has spawned a
|
||||
* subflow. Returns null of this flow execution is in the process of starting or has ended.
|
||||
* @return the active flow session
|
||||
* @throws IllegalStateException if this flow execution has not been started at all or if this execution has ended
|
||||
* and is no longer actively executing
|
||||
* @throws IllegalStateException if this flow execution has not been started at all
|
||||
*/
|
||||
public FlowSession getActiveSession() throws IllegalStateException;
|
||||
|
||||
|
||||
@@ -58,19 +58,18 @@ import org.springframework.webflow.definition.TransitionDefinition;
|
||||
public interface RequestContext {
|
||||
|
||||
/**
|
||||
* Returns the definition of the flow that is currently executing.
|
||||
* Returns the definition of the flow that is currently executing. Returns <code>null</code> when the flow execution
|
||||
* is in the process of starting and has not yet activated its root flow session.
|
||||
* @return the flow definition for the active session
|
||||
* @throws IllegalStateException if the flow execution has not been started at all, or if the execution has ended
|
||||
* and is no longer actively executing
|
||||
* @throws IllegalStateException if the flow execution has not been started at all or has ended
|
||||
*/
|
||||
public FlowDefinition getActiveFlow() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns the current state of the executing flow. May return <code>null</code> if this flow execution is in the
|
||||
* Returns the current state of the executiong flow. Returns <code>null</code> if this flow execution is in the
|
||||
* process of starting and has not yet entered its start state.
|
||||
* @return the current state, or <code>null</code> if in the process of starting
|
||||
* @throws IllegalStateException if this flow execution has not been started at all, or if this execution has ended
|
||||
* and is no longer actively executing
|
||||
* @throws IllegalStateException if this flow execution has not been started at all or has ended
|
||||
*/
|
||||
public StateDefinition getCurrentState() throws IllegalStateException;
|
||||
|
||||
@@ -78,8 +77,7 @@ public interface RequestContext {
|
||||
* Returns the transition that would execute on the occurrence of the given event.
|
||||
* @param eventId the id of the user event
|
||||
* @return the transition that would trigger, or <code>null</code> if no transition matches
|
||||
* @throws IllegalStateException if this flow execution has not been started at all, or if this execution has ended
|
||||
* and is no longer actively executing
|
||||
* @throws IllegalStateException if this flow execution has not been started at all or has ended
|
||||
*/
|
||||
public TransitionDefinition getMatchingTransition(String eventId) throws IllegalStateException;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.webflow.engine.impl;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.definition.FlowDefinition;
|
||||
import org.springframework.webflow.engine.EndState;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.RequestControlContext;
|
||||
@@ -58,6 +59,13 @@ public class FlowExecutionImplTests extends TestCase {
|
||||
execution.start(null, context);
|
||||
assertTrue(execution.hasStarted());
|
||||
assertFalse(execution.isActive());
|
||||
assertTrue(execution.hasEnded());
|
||||
try {
|
||||
execution.getActiveSession();
|
||||
fail("should have failed");
|
||||
} catch (IllegalStateException e) {
|
||||
|
||||
}
|
||||
assertEquals(1, mockListener.getRequestsSubmittedCount());
|
||||
assertEquals(1, mockListener.getRequestsProcessedCount());
|
||||
assertEquals(1, mockListener.getSessionCreatingCount());
|
||||
@@ -118,7 +126,14 @@ public class FlowExecutionImplTests extends TestCase {
|
||||
Flow flow = new Flow("flow");
|
||||
new EndState(flow, "end");
|
||||
FlowExecutionListener mockListener = new FlowExecutionListenerAdapter() {
|
||||
public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) {
|
||||
public void sessionCreating(RequestContext context, FlowDefinition definition) {
|
||||
assertNull(context.getCurrentState());
|
||||
assertNull(context.getActiveFlow());
|
||||
assertNull(context.getCurrentEvent());
|
||||
assertNull(context.getCurrentTransition());
|
||||
assertNull(context.getActiveFlow());
|
||||
assertNull(context.getFlowExecutionContext().getActiveSession());
|
||||
assertFalse(context.getFlowExecutionContext().isActive());
|
||||
throw new IllegalStateException("Oops");
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user