diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImpl.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImpl.java index bf08c425..499717fb 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImpl.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImpl.java @@ -242,7 +242,8 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { } public void resume(ExternalContext externalContext) throws FlowExecutionException, IllegalStateException { - Assert.state(status == FlowExecutionStatus.STARTED, "This flow execution cannot be resumed; it is not active"); + Assert.state(status == FlowExecutionStatus.STARTED, + "This flow execution cannot be resumed; it is not started or has ended"); if (logger.isDebugEnabled()) { logger.debug("Resuming in " + externalContext); } @@ -376,6 +377,9 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { void endActiveFlowSession(String outcome, MutableAttributeMap output, RequestControlContext context) { FlowSessionImpl session = getActiveSessionInternal(); + if (session == null) { + throw new IllegalArgumentException("Cannot end the active FlowSession when one has not been activated"); + } if (session.isRoot()) { status = FlowExecutionStatus.ENDING; } @@ -548,18 +552,16 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { * @return the new flow session */ private FlowSessionImpl activateSession(Flow flow) { - FlowSessionImpl session; - if (!flowSessions.isEmpty()) { - FlowSessionImpl parent = getActiveSessionInternal(); - session = createFlowSession(flow, parent); - } else { - session = createFlowSession(flow, null); - } + FlowSessionImpl parent = getActiveSessionInternal(); + FlowSessionImpl session = createFlowSession(flow, parent); flowSessions.add(session); return session; } private FlowSessionImpl getActiveSessionInternal() { + if (flowSessions.isEmpty()) { + return null; + } return (FlowSessionImpl) flowSessions.getLast(); } @@ -645,8 +647,9 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { * Returns the current flow which may or may not yet be active. */ private Flow getCurrentFlow() { - if (isActive()) { - return getActiveSessionInternal().getFlow(); + FlowSessionImpl session = getActiveSessionInternal(); + if (session != null) { + return session.getFlow(); } else { return flow; } @@ -654,8 +657,11 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { private State getCurrentState() { FlowSessionImpl session = getActiveSessionInternal(); - State currentState = (State) session.getState(); - return currentState; + if (session != null) { + return (State) session.getState(); + } else { + return null; + } } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/RequestControlContextImpl.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/RequestControlContextImpl.java index a29726cf..80be2f31 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/RequestControlContextImpl.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/RequestControlContextImpl.java @@ -32,6 +32,7 @@ import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.FlowExecutionContext; import org.springframework.webflow.execution.FlowExecutionException; import org.springframework.webflow.execution.FlowExecutionKey; +import org.springframework.webflow.execution.FlowSession; import org.springframework.webflow.execution.View; /** @@ -98,11 +99,13 @@ class RequestControlContextImpl implements RequestControlContext { // implementing RequestContext public FlowDefinition getActiveFlow() { - return flowExecution.getActiveSession().getDefinition(); + FlowSession session = flowExecution.getActiveSession(); + return session != null ? session.getDefinition() : null; } public StateDefinition getCurrentState() { - return flowExecution.getActiveSession().getState(); + FlowSession session = flowExecution.getActiveSession(); + return session != null ? session.getState() : null; } public TransitionDefinition getMatchingTransition(String eventId) throws IllegalStateException { @@ -122,11 +125,13 @@ class RequestControlContextImpl implements RequestControlContext { } public MutableAttributeMap getViewScope() throws IllegalStateException { - return flowExecution.getActiveSession().getViewScope(); + FlowSession session = flowExecution.getActiveSession(); + return session != null ? session.getViewScope() : null; } public MutableAttributeMap getFlowScope() { - return flowExecution.getActiveSession().getScope(); + FlowSession session = flowExecution.getActiveSession(); + return session != null ? session.getScope() : null; } public MutableAttributeMap getConversationScope() { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionContext.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionContext.java index 181f26e2..87915df4 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionContext.java @@ -90,9 +90,9 @@ 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. Returns null of this flow execution is in the process of starting or has ended. + * subflow. Returns null of this flow execution is in the process of starting. * @return the active flow session - * @throws IllegalStateException if this flow execution has not been started at all + * @throws IllegalStateException if this flow execution has not been started at all or has ended */ public FlowSession getActiveSession() throws IllegalStateException; diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/RequestContext.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/RequestContext.java index a492a7e6..09a0c627 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/RequestContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/RequestContext.java @@ -106,17 +106,21 @@ public interface RequestContext { /** * Returns a mutable map for accessing and/or setting attributes in view scope. View scoped attributes exist for * the life of the current view state. - * @return the view scope + * @return the view scope, or null if the flow execution is in the process of starting but has not yet completed + * startup * @see #inViewState() - * @throws IllegalStateException this flow is not in a view-state + * @throws IllegalStateException if this flow is not in a view-state, or the flow execution has not been started at + * all or has ended */ public MutableAttributeMap getViewScope() throws IllegalStateException; /** * Returns a mutable map for accessing and/or setting attributes in flow scope. Flow scoped attributes exist for * the life of the active flow session. - * @return the flow scope + * @return the flow scope, or null if the the flow execution is in the process of starting but has not yet completed + * startup * @see FlowSession + * @throws IllegalStateException if the flow execution has not been started at all or has ended */ public MutableAttributeMap getFlowScope(); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java index 74f712de..eceae582 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java @@ -148,6 +148,8 @@ public class FlowExecutionImplTests extends TestCase { } catch (FlowExecutionException e) { assertEquals(flow.getId(), e.getFlowId()); assertNull(e.getStateId()); + assertTrue(e.getCause() instanceof IllegalStateException); + assertTrue(e.getCause().getMessage().equals("Oops")); } }