diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/RequestControlContext.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/RequestControlContext.java index bea026ad..62a26df4 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/RequestControlContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/RequestControlContext.java @@ -117,14 +117,4 @@ public interface RequestControlContext extends RequestContext { */ public boolean getAlwaysRedirectOnPause(); - /** - * Initialize view scope. Called by view states when they enter. - */ - public void initViewScope(); - - /** - * Destroy view-scope. Called by view-states when they exit. - */ - public void destroyViewScope(); - } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java index 0f170de1..c78f7708 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/ViewState.java @@ -162,7 +162,6 @@ public class ViewState extends TransitionableState { } protected void doPreEntryActions(RequestControlContext context) throws FlowExecutionException { - context.initViewScope(); createVariables(context); } @@ -203,7 +202,6 @@ public class ViewState extends TransitionableState { public void exit(RequestControlContext context) { destroyVariables(context); - context.destroyViewScope(); super.exit(context); } 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 ef5b5eb4..0a87b8d4 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 @@ -331,6 +331,9 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable { void start(Flow flow, MutableAttributeMap input, RequestControlContext context) { listeners.fireSessionCreating(context, flow); FlowSession session = activateSession(flow); + if (input == null) { + input = new LocalAttributeMap(); + } listeners.fireSessionStarting(context, session, input); flow.start(context, input); listeners.fireSessionStarted(context, session); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowSessionImpl.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowSessionImpl.java index 85e04763..d69357ed 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowSessionImpl.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowSessionImpl.java @@ -40,6 +40,8 @@ import org.springframework.webflow.execution.FlowSession; */ class FlowSessionImpl implements FlowSession, Externalizable { + private static final String FLOW_VIEW_MAP_ATTRIBUTE = "flowViewMap"; + /** * The flow definition (a singleton). *
@@ -104,6 +106,18 @@ class FlowSessionImpl implements FlowSession, Externalizable {
return scope;
}
+ public MutableAttributeMap getViewScope() throws IllegalStateException {
+ if (state == null) {
+ throw new IllegalStateException("The current state of this flow '" + flow.getId()
+ + "' is [null] - cannot access view scope");
+ }
+ if (!state.isViewState()) {
+ throw new IllegalStateException("The current state '" + state.getId() + "' of this flow '" + flow.getId()
+ + "' is not a view state - view scope not accessible");
+ }
+ return (MutableAttributeMap) scope.get(FLOW_VIEW_MAP_ATTRIBUTE);
+ }
+
public FlowSession getParent() {
return parent;
}
@@ -158,8 +172,14 @@ class FlowSessionImpl implements FlowSession, Externalizable {
Assert.notNull(state, "The state is required");
Assert.isTrue(flow == state.getOwner(),
"The state does not belong to the flow associated with this flow session");
+ if (this.state != null && this.state.isViewState()) {
+ destroyViewScope();
+ }
this.state = state;
this.stateId = state.getId();
+ if (this.state.isViewState()) {
+ initViewScope();
+ }
}
/**
@@ -176,6 +196,16 @@ class FlowSessionImpl implements FlowSession, Externalizable {
return stateId;
}
+ // internal helpers
+
+ private void initViewScope() {
+ scope.put(FLOW_VIEW_MAP_ATTRIBUTE, new LocalAttributeMap());
+ }
+
+ private void destroyViewScope() {
+ scope.remove(FLOW_VIEW_MAP_ATTRIBUTE);
+ }
+
public String toString() {
return new ToStringCreator(this).append("flow", flowId).append("state", stateId).append("scope", scope)
.toString();
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 a5cd8275..a52fc9e3 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
@@ -48,8 +48,6 @@ import org.springframework.webflow.execution.FlowSession;
*/
class RequestControlContextImpl implements RequestControlContext {
- private static final String FLOW_VIEW_MAP_ATTRIBUTE = "flowViewMap";
-
/**
* The owning flow execution carrying out this request.
*/
@@ -123,14 +121,7 @@ class RequestControlContextImpl implements RequestControlContext {
}
public MutableAttributeMap getViewScope() throws IllegalStateException {
- if (!flowExecution.isActive()) {
- throw new IllegalStateException("This flow is not active");
- }
- if (!getCurrentState().isViewState()) {
- throw new IllegalStateException("The current state '" + getCurrentState().getId() + "' of this flow '"
- + getActiveFlow().getId() + "' is not a view state - view scope not accessible");
- }
- return (MutableAttributeMap) getFlowScope().get(FLOW_VIEW_MAP_ATTRIBUTE);
+ return flowExecution.getActiveSession().getViewScope();
}
public MutableAttributeMap getFlowScope() {
@@ -213,14 +204,6 @@ class RequestControlContextImpl implements RequestControlContext {
flowExecution.start(flow, input, this);
}
- public void initViewScope() {
- getFlowScope().put(FLOW_VIEW_MAP_ATTRIBUTE, new LocalAttributeMap());
- }
-
- public void destroyViewScope() {
- getFlowScope().remove(FLOW_VIEW_MAP_ATTRIBUTE);
- }
-
public boolean handleEvent(Event event) throws FlowExecutionException {
this.lastEvent = event;
return flowExecution.handleEvent(event, this);
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 7b1a4236..86af89e2 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
@@ -100,8 +100,8 @@ public interface FlowExecutionContext {
public FlowSession getActiveSession() throws IllegalStateException;
/**
- * Returns a mutable map for data held in "flash scope". Attributes in this map are cleared out on the next event
- * signaled against this flow execution. Flash attributes survive flow execution refresh operations.
+ * Returns a mutable map for data held in "flash scope". Attributes in this map are cleared out on the next view
+ * rendering. Flash attributes survive flow execution refresh operations.
* @return flash scope
*/
public MutableAttributeMap getFlashScope();
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowSession.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowSession.java
index f3e0ef23..d235bf40 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowSession.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowSession.java
@@ -54,6 +54,14 @@ public interface FlowSession {
*/
public MutableAttributeMap getScope();
+ /**
+ * Returns a mutable map for data held in "view scope". Attributes in this map are cleared out when the current view
+ * state exits.
+ * @return view scope
+ * @throws IllegalStateException if this flow session is not currently in a view state
+ */
+ public MutableAttributeMap getViewScope() throws IllegalStateException;
+
/**
* Returns the parent flow session in the current flow execution, or null if there is no parent flow
* session.
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockFlowSession.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockFlowSession.java
index cba37efd..1fbe3244 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockFlowSession.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockFlowSession.java
@@ -36,14 +36,14 @@ import org.springframework.webflow.execution.FlowSession;
*/
public class MockFlowSession implements FlowSession {
+ private static final String FLOW_VIEW_MAP_ATTRIBUTE = "flowViewMap";
+
private Flow definition;
private State state;
private MutableAttributeMap scope = new LocalAttributeMap();
- private MutableAttributeMap flashMap = new LocalAttributeMap();
-
private FlowSession parent;
/**
@@ -90,8 +90,16 @@ public class MockFlowSession implements FlowSession {
return scope;
}
- public MutableAttributeMap getFlashMap() {
- return flashMap;
+ public MutableAttributeMap getViewScope() throws IllegalStateException {
+ if (state == null) {
+ throw new IllegalStateException("The current state of this flow '" + definition.getId()
+ + "' is [null] - cannot access view scope");
+ }
+ if (!state.isViewState()) {
+ throw new IllegalStateException("The current state '" + state.getId() + "' of this flow '"
+ + definition.getId() + "' is not a view state - view scope not accessible");
+ }
+ return (MutableAttributeMap) scope.get(FLOW_VIEW_MAP_ATTRIBUTE);
}
public FlowSession getParent() {
@@ -115,7 +123,13 @@ public class MockFlowSession implements FlowSession {
* Set the currently active state.
*/
public void setState(State state) {
+ if (this.state != null && this.state.isViewState()) {
+ destroyViewScope();
+ }
this.state = state;
+ if (this.state != null && this.state.isViewState()) {
+ initViewScope();
+ }
}
/**
@@ -133,7 +147,7 @@ public class MockFlowSession implements FlowSession {
this.parent = parent;
}
- // conveniece accessors
+ // convenience accessors
/**
* Returns the flow definition of this session.
@@ -148,4 +162,14 @@ public class MockFlowSession implements FlowSession {
public State getStateInternal() {
return state;
}
+
+ // internal helpers
+
+ private void initViewScope() {
+ scope.put(FLOW_VIEW_MAP_ATTRIBUTE, new LocalAttributeMap());
+ }
+
+ private void destroyViewScope() {
+ scope.remove(FLOW_VIEW_MAP_ATTRIBUTE);
+ }
}
\ No newline at end of file
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractFlowExecutionTests.java b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractFlowExecutionTests.java
index 0d13e049..2169e960 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractFlowExecutionTests.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractFlowExecutionTests.java
@@ -19,6 +19,7 @@ import junit.framework.TestCase;
import org.springframework.util.Assert;
import org.springframework.webflow.context.ExternalContext;
+import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
import org.springframework.webflow.execution.FlowExecution;
@@ -33,9 +34,8 @@ import org.springframework.webflow.test.MockExternalContext;
*
* More specifically, a typical flow execution test case will test: *