view scope
This commit is contained in:
@@ -97,4 +97,8 @@ public class SerializableListDataModel extends DataModel implements Serializable
|
||||
setRowIndex(newRowIndex);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class FlowViewStateManager extends StateManager {
|
||||
}
|
||||
|
||||
RequestContext requestContext = RequestContextHolder.getRequestContext();
|
||||
SerializedView view = (SerializedView) requestContext.getFlowScope().get(SERIALIZED_VIEW_STATE);
|
||||
SerializedView view = (SerializedView) requestContext.getViewScope().get(SERIALIZED_VIEW_STATE);
|
||||
viewRoot.processRestoreState(context, view.componentState);
|
||||
logger.debug("UIViewRoot component state restored");
|
||||
}
|
||||
@@ -85,7 +85,7 @@ public class FlowViewStateManager extends StateManager {
|
||||
}
|
||||
|
||||
RequestContext requestContext = RequestContextHolder.getRequestContext();
|
||||
SerializedView view = (SerializedView) requestContext.getFlowScope().get(SERIALIZED_VIEW_STATE);
|
||||
SerializedView view = (SerializedView) requestContext.getViewScope().get(SERIALIZED_VIEW_STATE);
|
||||
if (view == null || !view.viewId.equals(viewId)) {
|
||||
logger.debug("No matching view in flow scope;");
|
||||
return null;
|
||||
@@ -145,7 +145,7 @@ public class FlowViewStateManager extends StateManager {
|
||||
}
|
||||
SerializedView view = new SerializedView(context.getViewRoot().getViewId(), getTreeStructureToSave(context),
|
||||
getComponentStateToSave(context));
|
||||
requestContext.getFlowScope().put(SERIALIZED_VIEW_STATE, view);
|
||||
requestContext.getViewScope().put(SERIALIZED_VIEW_STATE, view);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@@ -228,6 +228,10 @@ public class JsfViewFactoryTests extends TestCase {
|
||||
|
||||
private class NormalViewState implements StateDefinition {
|
||||
|
||||
public boolean isViewState() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
throw new UnsupportedOperationException("Auto-generated method stub");
|
||||
}
|
||||
|
||||
@@ -265,6 +265,10 @@ public class JsfViewTests extends TestCase {
|
||||
|
||||
MutableAttributeMap attrs = new LocalAttributeMap();
|
||||
|
||||
public boolean isViewState() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public ModalViewState() {
|
||||
attrs.asMap().put("modal", Boolean.TRUE);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<persistence-context/>
|
||||
|
||||
<input name="hotelId" value="flowScope.hotelId"/>
|
||||
<input name="hotelId" value="flowScope.hotelId" required="true"/>
|
||||
|
||||
<on-start>
|
||||
<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)" result="flowScope.booking" />
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<view-state id="enterSearchCriteria">
|
||||
<on-render>
|
||||
<evaluate expression="bookingService.findBookings(currentUser.name)" result="flowScope.bookings" result-type="dataModel" />
|
||||
<evaluate expression="bookingService.findBookings(currentUser.name)" result="viewScope.bookings" result-type="dataModel" />
|
||||
</on-render>
|
||||
<transition on="search" to="reviewHotels" />
|
||||
<transition on="cancelBooking">
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<view-state id="reviewHotels">
|
||||
<on-render>
|
||||
<evaluate expression="bookingService.findHotels(searchCriteria)" result="flowScope.hotels" result-type="dataModel" />
|
||||
<evaluate expression="bookingService.findHotels(searchCriteria)" result="viewScope.hotels" result-type="dataModel" />
|
||||
</on-render>
|
||||
<transition on="previous">
|
||||
<evaluate expression="searchCriteria.previousPage()" />
|
||||
@@ -28,20 +28,19 @@
|
||||
<evaluate expression="searchCriteria.nextPage()" />
|
||||
<render fragments="hotels:searchResultsFragment" />
|
||||
</transition>
|
||||
<transition on="select" to="reviewHotel" />
|
||||
<transition on="select" to="reviewHotel">
|
||||
<set name="flowScope.hotel" value="hotels.selectedRow" />
|
||||
</transition>
|
||||
<transition on="changeSearch" to="changeSearchCriteria" />
|
||||
</view-state>
|
||||
|
||||
<view-state id="reviewHotel">
|
||||
<on-render>
|
||||
<set name="requestScope.hotel" value="hotels.selectedRow" />
|
||||
</on-render>
|
||||
<transition on="book" to="bookHotel" />
|
||||
<transition on="cancel" to="enterSearchCriteria" />
|
||||
</view-state>
|
||||
|
||||
<subflow-state id="bookHotel" subflow="booking">
|
||||
<input name="hotelId" value="hotels.selectedRow.id" />
|
||||
<input name="hotelId" value="hotel.id" />
|
||||
<transition on="bookingConfirmed" to="finish" />
|
||||
<transition on="bookingCancelled" to="enterSearchCriteria" />
|
||||
</subflow-state>
|
||||
@@ -56,5 +55,5 @@
|
||||
</view-state>
|
||||
|
||||
<end-state id="finish" />
|
||||
|
||||
|
||||
</flow>
|
||||
@@ -17,22 +17,22 @@
|
||||
<ui:fragment id="searchResultsFragment">
|
||||
<div id="searchResults">
|
||||
<h:outputText id="noHotelsText" value="No Hotels Found" rendered="#{hotels.rowCount == 0}"/>
|
||||
<h:dataTable id="hotels" styleClass="summary" value="#{hotels}" var="hotel" rendered="#{hotels.rowCount > 0}">
|
||||
<h:dataTable id="hotels" styleClass="summary" value="#{hotels}" var="h" rendered="#{hotels.rowCount > 0}">
|
||||
<h:column>
|
||||
<f:facet name="header">Name</f:facet>
|
||||
#{hotel.name}
|
||||
#{h.name}
|
||||
</h:column>
|
||||
<h:column>
|
||||
<f:facet name="header">Address</f:facet>
|
||||
#{hotel.address}
|
||||
#{h.address}
|
||||
</h:column>
|
||||
<h:column>
|
||||
<f:facet name="header">City, State</f:facet>
|
||||
#{hotel.city}, #{hotel.state}, #{hotel.country}
|
||||
#{h.city}, #{h.state}, #{h.country}
|
||||
</h:column>
|
||||
<h:column>
|
||||
<f:facet name="header">Zip</f:facet>
|
||||
#{hotel.zip}
|
||||
#{h.zip}
|
||||
</h:column>
|
||||
<h:column>
|
||||
<f:facet name="header">Action</f:facet>
|
||||
|
||||
@@ -37,4 +37,10 @@ public interface StateDefinition extends Annotated {
|
||||
* @return the state identifier
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Returns true if this state is a view state.
|
||||
* @return true if a view state, false otherwise
|
||||
*/
|
||||
public boolean isViewState();
|
||||
}
|
||||
@@ -117,4 +117,14 @@ 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();
|
||||
|
||||
}
|
||||
@@ -98,6 +98,10 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isViewState() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// implementation specific
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,6 +77,12 @@ public class ViewState extends TransitionableState {
|
||||
this.viewFactory = viewFactory;
|
||||
}
|
||||
|
||||
// implementing StateDefinition
|
||||
|
||||
public boolean isViewState() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a view variable.
|
||||
* @param variable the variable
|
||||
@@ -156,6 +162,7 @@ public class ViewState extends TransitionableState {
|
||||
}
|
||||
|
||||
protected void doPreEntryActions(RequestControlContext context) throws FlowExecutionException {
|
||||
context.initViewScope();
|
||||
createVariables(context);
|
||||
}
|
||||
|
||||
@@ -196,6 +203,7 @@ public class ViewState extends TransitionableState {
|
||||
|
||||
public void exit(RequestControlContext context) {
|
||||
destroyVariables(context);
|
||||
context.destroyViewScope();
|
||||
super.exit(context);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public class ViewVariable extends AnnotatedObject {
|
||||
*/
|
||||
public void create(RequestContext context) {
|
||||
Object value = valueFactory.createInitialValue(context);
|
||||
context.getFlowScope().put(name, value);
|
||||
context.getViewScope().put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +67,7 @@ public class ViewVariable extends AnnotatedObject {
|
||||
* @param context the executing flow
|
||||
*/
|
||||
public void restore(RequestContext context) {
|
||||
Object value = context.getFlowScope().get(name);
|
||||
Object value = context.getViewScope().get(name);
|
||||
valueFactory.restoreReferences(value, context);
|
||||
}
|
||||
|
||||
@@ -76,6 +76,6 @@ public class ViewVariable extends AnnotatedObject {
|
||||
* @param context the executing flow
|
||||
*/
|
||||
public Object destroy(RequestContext context) {
|
||||
return context.getFlowScope().remove(name);
|
||||
return context.getViewScope().remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ 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.
|
||||
*/
|
||||
@@ -116,6 +118,21 @@ class RequestControlContextImpl implements RequestControlContext {
|
||||
return flowExecution.getFlashScope();
|
||||
}
|
||||
|
||||
public boolean inViewState() {
|
||||
return flowExecution.isActive() && getCurrentState() != null && getCurrentState().isViewState();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public MutableAttributeMap getFlowScope() {
|
||||
return flowExecution.getActiveSession().getScope();
|
||||
}
|
||||
@@ -196,6 +213,14 @@ 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);
|
||||
|
||||
@@ -89,6 +89,22 @@ public interface RequestContext {
|
||||
*/
|
||||
public MutableAttributeMap getFlashScope();
|
||||
|
||||
/**
|
||||
* Returns true if the flow is currently active and in a view state. When in a view state {@link #getViewScope()},
|
||||
* can be safely called.
|
||||
* @see #getViewScope()
|
||||
* @return true if in a view state, false if not
|
||||
*/
|
||||
public boolean inViewState();
|
||||
|
||||
/**
|
||||
* Returns a mutable map for accessing and/or setting attributes in view scope. <b>View scoped attributes exist for
|
||||
* the life of the current view state.</b>
|
||||
* @return the view scope
|
||||
* @throws IllegalStateException this flow is not in a view-state
|
||||
*/
|
||||
public MutableAttributeMap getViewScope() throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Returns a mutable map for accessing and/or setting attributes in flow scope. <b>Flow scoped attributes exist for
|
||||
* the life of the active flow session.</b>
|
||||
@@ -177,4 +193,5 @@ public interface RequestContext {
|
||||
* @return the flow execution URL
|
||||
*/
|
||||
public String getFlowExecutionUrl() throws IllegalStateException;
|
||||
|
||||
}
|
||||
@@ -151,6 +151,7 @@ public class ImplicitFlowVariableELResolver extends ELResolver {
|
||||
vars.put("requestParameters", requestContextResolver);
|
||||
vars.put("requestScope", requestContextResolver);
|
||||
vars.put("flashScope", requestContextResolver);
|
||||
vars.put("viewScope", requestContextResolver);
|
||||
vars.put("flowScope", requestContextResolver);
|
||||
vars.put("conversationScope", requestContextResolver);
|
||||
vars.put("messageContext", requestContextResolver);
|
||||
|
||||
@@ -67,6 +67,9 @@ public class ScopeSearchingELResolver extends ELResolver {
|
||||
} else if (requestContext.getFlashScope().contains(attributeName)) {
|
||||
elContext.setPropertyResolved(true);
|
||||
return requestContext.getFlashScope().get(attributeName).getClass();
|
||||
} else if (requestContext.inViewState() && requestContext.getViewScope().contains(attributeName)) {
|
||||
elContext.setPropertyResolved(true);
|
||||
return requestContext.getViewScope().get(attributeName).getClass();
|
||||
} else if (requestContext.getFlowScope().contains(attributeName)) {
|
||||
elContext.setPropertyResolved(true);
|
||||
return requestContext.getFlowScope().get(attributeName).getClass();
|
||||
@@ -96,6 +99,12 @@ public class ScopeSearchingELResolver extends ELResolver {
|
||||
}
|
||||
elContext.setPropertyResolved(true);
|
||||
return requestContext.getFlashScope().get(attributeName);
|
||||
} else if (requestContext.inViewState() && requestContext.getViewScope().contains(attributeName)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Successfully resolved view scoped variable '" + property + "'");
|
||||
}
|
||||
elContext.setPropertyResolved(true);
|
||||
return requestContext.getViewScope().get(attributeName);
|
||||
} else if (requestContext.getFlowScope().contains(attributeName)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Successfully resolved flow scoped variable '" + property + "'");
|
||||
@@ -125,6 +134,9 @@ public class ScopeSearchingELResolver extends ELResolver {
|
||||
} else if (requestContext.getFlashScope().contains(attributeName)) {
|
||||
elContext.setPropertyResolved(true);
|
||||
return false;
|
||||
} else if (requestContext.inViewState() && requestContext.getViewScope().contains(attributeName)) {
|
||||
elContext.setPropertyResolved(true);
|
||||
return false;
|
||||
} else if (requestContext.getFlowScope().contains(attributeName)) {
|
||||
elContext.setPropertyResolved(true);
|
||||
return false;
|
||||
@@ -154,6 +166,12 @@ public class ScopeSearchingELResolver extends ELResolver {
|
||||
}
|
||||
elContext.setPropertyResolved(true);
|
||||
requestContext.getFlashScope().put(attributeName, value);
|
||||
} else if (requestContext.inViewState() && requestContext.getViewScope().contains(attributeName)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Successfully resolved view scoped variable '" + property + "'");
|
||||
}
|
||||
elContext.setPropertyResolved(true);
|
||||
requestContext.getViewScope().put(attributeName, value);
|
||||
} else if (requestContext.getFlowScope().contains(attributeName)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Successfully resolved flow scoped variable '" + property + "'");
|
||||
|
||||
@@ -45,6 +45,8 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
*/
|
||||
public class MockRequestContext implements RequestContext {
|
||||
|
||||
protected static final String FLOW_VIEW_MAP_ATTRIBUTE = "flowViewMap";
|
||||
|
||||
private FlowExecutionContext flowExecutionContext;
|
||||
|
||||
private ExternalContext externalContext;
|
||||
@@ -126,6 +128,21 @@ public class MockRequestContext implements RequestContext {
|
||||
return getMockFlowExecutionContext().getFlashScope();
|
||||
}
|
||||
|
||||
public boolean inViewState() {
|
||||
return getFlowExecutionContext().isActive() && getCurrentState() != null && getCurrentState().isViewState();
|
||||
}
|
||||
|
||||
public MutableAttributeMap getViewScope() throws IllegalStateException {
|
||||
if (!getFlowExecutionContext().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);
|
||||
}
|
||||
|
||||
public MutableAttributeMap getFlowScope() {
|
||||
return getFlowExecutionContext().getActiveSession().getScope();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.webflow.test;
|
||||
|
||||
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.RequestControlContext;
|
||||
@@ -73,6 +74,14 @@ public class MockRequestControlContext extends MockRequestContext implements Req
|
||||
flow.start(this, input);
|
||||
}
|
||||
|
||||
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) {
|
||||
setLastEvent(event);
|
||||
return ((Flow) getActiveFlow()).handleEvent(this);
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ViewStateTests extends TestCase {
|
||||
}));
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
state.enter(context);
|
||||
assertEquals("bar", context.getFlowScope().getString("foo"));
|
||||
assertEquals("bar", context.getViewScope().getString("foo"));
|
||||
assertTrue("Render not called", context.getFlowScope().contains("renderCalled"));
|
||||
assertFalse(context.getFlowExecutionRedirectSent());
|
||||
}
|
||||
@@ -151,7 +151,7 @@ public class ViewStateTests extends TestCase {
|
||||
state.resume(context);
|
||||
assertTrue("Render not called", context.getFlowScope().contains("renderCalled"));
|
||||
assertFalse(context.getFlowExecutionRedirectSent());
|
||||
assertEquals("Restored", ((TestBean) context.getFlowScope().get("foo")).datum1);
|
||||
assertEquals("Restored", ((TestBean) context.getViewScope().get("foo")).datum1);
|
||||
}
|
||||
|
||||
public void testResumeViewStateForEvent() {
|
||||
@@ -202,7 +202,7 @@ public class ViewStateTests extends TestCase {
|
||||
new ViewState(flow, "next", viewFactory);
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
state.enter(context);
|
||||
assertTrue(context.getFlowScope().contains("foo"));
|
||||
assertTrue(context.getViewScope().contains("foo"));
|
||||
context = new MockRequestControlContext(context.getFlowExecutionContext());
|
||||
context.putRequestParameter("_eventId", "submit");
|
||||
state.resume(context);
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.springframework.webflow.engine;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.test.MockRequestContext;
|
||||
import org.springframework.webflow.test.MockRequestControlContext;
|
||||
|
||||
public class ViewVariableTests extends TestCase {
|
||||
|
||||
@@ -18,9 +18,12 @@ public class ViewVariableTests extends TestCase {
|
||||
public void restoreReferences(Object value, RequestContext context) {
|
||||
}
|
||||
});
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
Flow flow = new Flow("flow");
|
||||
ViewState view = new ViewState(flow, "view", new StubViewFactory());
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
view.enter(context);
|
||||
var.create(context);
|
||||
assertEquals("bar", context.getFlowScope().get("foo"));
|
||||
assertEquals("bar", context.getViewScope().get("foo"));
|
||||
}
|
||||
|
||||
public void testDestroyVariable() {
|
||||
@@ -32,11 +35,14 @@ public class ViewVariableTests extends TestCase {
|
||||
public void restoreReferences(Object value, RequestContext context) {
|
||||
}
|
||||
});
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
Flow flow = new Flow("flow");
|
||||
ViewState view = new ViewState(flow, "view", new StubViewFactory());
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
view.enter(context);
|
||||
var.create(context);
|
||||
assertEquals("bar", context.getFlowScope().get("foo"));
|
||||
assertEquals("bar", context.getViewScope().get("foo"));
|
||||
var.destroy(context);
|
||||
assertFalse(context.getFlowScope().contains("foo"));
|
||||
assertFalse(context.getViewScope().contains("foo"));
|
||||
}
|
||||
|
||||
public void testRestoreVariable() {
|
||||
@@ -50,10 +56,13 @@ public class ViewVariableTests extends TestCase {
|
||||
assertEquals("bar", value);
|
||||
}
|
||||
});
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
Flow flow = new Flow("flow");
|
||||
ViewState view = new ViewState(flow, "view", new StubViewFactory());
|
||||
MockRequestControlContext context = new MockRequestControlContext(flow);
|
||||
view.enter(context);
|
||||
var.create(context);
|
||||
var.restore(context);
|
||||
assertEquals("bar", context.getFlowScope().get("foo"));
|
||||
assertEquals("bar", context.getViewScope().get("foo"));
|
||||
assertTrue(restoreCalled);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user