diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfView.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfView.java index dd74096e..08a18db0 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfView.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfView.java @@ -97,24 +97,26 @@ public class JsfView implements View { return requestContext.getRequestParameters().size() > 1; } - /* - * Executes postback-processing portions of the standard JSF lifecycle including APPLY_REQUEST_VALUES through - * INVOKE_APPLICATION. - */ public void processUserEvent() { + /* + * Executes postback-processing portions of the standard JSF lifecycle including APPLY_REQUEST_VALUES through + * INVOKE_APPLICATION. + */ FacesContext facesContext = FlowFacesContext.newInstance(requestContext, facesLifecycle); facesContext.setViewRoot(viewRoot); try { + // TODO - render response / response complete check facesLifecycle.execute(facesContext); - if (!hasFlowEvent()) { - requestContext.getFlashScope().put(ViewRootHolder.VIEW_ROOT_HOLDER_KEY, - new ViewRootHolder(getViewRoot())); - } } finally { facesContext.release(); } } + public Object getUserEventState() { + // TODO - return view root holder + return null; + } + public boolean hasFlowEvent() { return requestContext.getExternalContext().getRequestMap().contains(EVENT_KEY); } 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 104d7fae..a3abab53 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 @@ -179,12 +179,8 @@ public class ViewState extends TransitionableState { context.getExternalContext().requestRedirectInPopup(); } } else { - if (externalContext.isResponseAllowed()) { - View view = viewFactory.getView(context); - render(context, view); - } else { - externalContext.recordResponseComplete(); - } + View view = viewFactory.getView(context); + render(context, view); } } } @@ -193,33 +189,48 @@ public class ViewState extends TransitionableState { restoreVariables(context); View view = viewFactory.getView(context); if (view.userEventQueued()) { - view.processUserEvent(); - boolean stateExited = false; - if (view.hasFlowEvent()) { - Event event = view.getFlowEvent(); - if (logger.isDebugEnabled()) { - logger.debug("Event '" + event.getId() + "' returned from view " + view); - } - stateExited = context.handleEvent(event); - } + boolean stateExited = handleEvent(view, context); if (!stateExited) { ExternalContext externalContext = context.getExternalContext(); if (externalContext.isResponseComplete()) { clearFlashIfNotRedirecting(context); } else { if (externalContext.isAjaxRequest()) { - renderIfAllowed(context, view); + render(context, view); } else { if (shouldRedirect(context)) { + context.getFlashScope().put(View.USER_EVENT_STATE_ATTRIBUTE, view.getUserEventState()); externalContext.requestFlowExecutionRedirect(); } else { - renderIfAllowed(context, view); + render(context, view); } } } } } else { - renderIfAllowed(context, view); + refresh(view, context); + } + } + + private boolean handleEvent(View view, RequestControlContext context) { + view.processUserEvent(); + if (view.hasFlowEvent()) { + Event event = view.getFlowEvent(); + if (logger.isDebugEnabled()) { + logger.debug("Event '" + event.getId() + "' returned from view " + view); + } + return context.handleEvent(event); + } else { + return false; + } + } + + private void refresh(View view, RequestControlContext context) { + ExternalContext externalContext = context.getExternalContext(); + if (externalContext.isResponseComplete()) { + clearFlash(context); + } else { + render(context, view); } } @@ -250,15 +261,6 @@ public class ViewState extends TransitionableState { } } - private void renderIfAllowed(RequestControlContext context, View view) throws ViewRenderingException { - ExternalContext externalContext = context.getExternalContext(); - if (externalContext.isResponseAllowed()) { - render(context, view); - } else { - externalContext.recordResponseComplete(); - } - } - private void render(RequestControlContext context, View view) throws ViewRenderingException { if (logger.isDebugEnabled()) { logger.debug("Rendering + " + view); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionExecutingViewFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionExecutingViewFactory.java index 0cf4ce00..5ced9fc5 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionExecutingViewFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionExecutingViewFactory.java @@ -58,6 +58,8 @@ public class ActionExecutingViewFactory implements ViewFactory { private String eventId; + private boolean userEventProcessed; + private ActionExecutingView(Action action, RequestContext requestContext) { this.action = action; this.requestContext = requestContext; @@ -70,15 +72,15 @@ public class ActionExecutingViewFactory implements ViewFactory { } public boolean userEventQueued() { - determineEventId(requestContext); - return eventId != null; + return getEventId() != null; } public void processUserEvent() { + userEventProcessed = true; } public boolean hasFlowEvent() { - return eventId != null; + return userEventProcessed && getEventId() != null; } public Event getFlowEvent() { @@ -88,8 +90,19 @@ public class ActionExecutingViewFactory implements ViewFactory { return new Event(this, eventId); } - private void determineEventId(RequestContext context) { - eventId = WebUtils.findParameterValue(context.getRequestParameters().asMap(), "_eventId"); + public Object getUserEventState() { + return null; + } + + private String getEventId() { + if (eventId == null) { + eventId = determineEventId(requestContext); + } + return this.eventId; + } + + protected String determineEventId(RequestContext context) { + return WebUtils.findParameterValue(context.getRequestParameters().asMap(), "_eventId"); } } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/View.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/View.java index 33b3c7eb..622dc44c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/View.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/View.java @@ -31,6 +31,11 @@ public interface View { */ public static final String RENDER_FRAGMENTS_ATTRIBUTE = "flowRenderFragments"; + /** + * Well-known attribute name for storing the results of processing a user event + */ + public static final String USER_EVENT_STATE_ATTRIBUTE = "viewUserEventState"; + /** * Render this view's content. * @throws IOException if an IO Exception occured rendering the view @@ -45,7 +50,7 @@ public interface View { /** * Process the queued user event. Should only be called when {@link #userEventQueued()} returns true. After calling - * this method, a flow event may be queued that should be raised in the Web Flow system. + * this method, a flow event may be raised that should be handled in the Web Flow system. * @see #hasFlowEvent() */ public void processUserEvent(); @@ -64,4 +69,12 @@ public interface View { */ public Event getFlowEvent(); + /** + * A memento holding the results of processing a user event. Used to allow transient view state such as binding and + * validation errors to survive a flow execution redirect. + * @return the user event state object, or null if no event state needs managing + * @see #processUserEvent() + */ + public Object getUserEventState(); + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java index 9f5eef96..f861db6b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java @@ -89,6 +89,8 @@ public abstract class AbstractMvcView implements View { private MessageCodesResolver messageCodesResolver; + private boolean userEventProcessed; + /** * Creates a new MVC view. * @param view the Spring MVC view to render @@ -185,52 +187,56 @@ public abstract class AbstractMvcView implements View { } public boolean userEventQueued() { - eventId = determineEventId(requestContext); - return eventId != null; + return getEventId() != null; } public void processUserEvent() { - if (logger.isDebugEnabled()) { - logger.debug("User event '" + eventId + "' raised"); - } - Object model = getModelObject(); - if (model == null) { - if (logger.isDebugEnabled()) { - logger.debug("No model to bind to; done processing user event"); - } + String eventId = getEventId(); + if (eventId == null) { return; } if (logger.isDebugEnabled()) { - logger.debug("Resolved model " + model); + logger.debug("Processing user event '" + eventId + "'"); } - TransitionDefinition transition = requestContext.getMatchingTransition(eventId); - if (shouldBind(model, transition)) { - mappingResults = bind(model); - if (hasErrors(mappingResults)) { - if (logger.isDebugEnabled()) { - logger.debug("Model binding resulted in errors; adding error messages to context"); + Object model = getModelObject(); + if (model != null) { + if (logger.isDebugEnabled()) { + logger.debug("Resolved model " + model); + } + TransitionDefinition transition = requestContext.getMatchingTransition(eventId); + if (shouldBind(model, transition)) { + mappingResults = bind(model); + if (hasErrors(mappingResults)) { + if (logger.isDebugEnabled()) { + logger.debug("Model binding resulted in errors; adding error messages to context"); + } + addErrorMessages(mappingResults); + } + if (shouldValidate(model, transition)) { + validate(model); } - addErrorMessages(mappingResults); } - if (shouldValidate(model, transition)) { - validate(model); + } else { + if (logger.isDebugEnabled()) { + logger.debug("No model to bind to; done processing user event"); } } - if (mappingResults != null && hasErrors(mappingResults)) { - requestContext.getFlashScope().put(ViewActionStateHolder.KEY, - new ViewActionStateHolder(eventId, mappingResults)); - } + userEventProcessed = true; } public boolean hasFlowEvent() { - return eventId != null && !requestContext.getMessageContext().hasErrorMessages(); + return userEventProcessed && !requestContext.getMessageContext().hasErrorMessages(); } public Event getFlowEvent() { if (!hasFlowEvent()) { return null; } - return new Event(this, eventId, requestContext.getRequestParameters().asAttributeMap()); + return new Event(this, getEventId(), requestContext.getRequestParameters().asAttributeMap()); + } + + public Object getUserEventState() { + return new ViewActionStateHolder(eventId, mappingResults); } public String toString() { @@ -262,22 +268,15 @@ public abstract class AbstractMvcView implements View { */ protected abstract void doRender(Map model) throws Exception; - /** - * Obtain the user event from the current flow request. The default implementation returns the value of the request - * parameter with name {@link #setEventIdParameterName(String) eventIdParameterName}. Subclasses may override. - * @param context the current flow request context - * @return the user event that occurred - */ - protected String determineEventId(RequestContext context) { - return WebUtils.findParameterValue(context.getRequestParameters().asMap(), eventIdParameterName); - } - /** * Returns the id of the user event being processed. * @return the user event */ protected String getEventId() { - return eventId; + if (eventId == null) { + eventId = determineEventId(requestContext); + } + return this.eventId; } /** @@ -303,6 +302,16 @@ public abstract class AbstractMvcView implements View { return mappingResults; } + /** + * Obtain the user event from the current flow request. The default implementation returns the value of the request + * parameter with name {@link #setEventIdParameterName(String) eventIdParameterName}. Subclasses may override. + * @param context the current flow request context + * @return the user event that occurred + */ + protected String determineEventId(RequestContext context) { + return WebUtils.findParameterValue(context.getRequestParameters().asMap(), eventIdParameterName); + } + // package private /** diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcViewFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcViewFactory.java index b930bd16..c3dfd139 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcViewFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcViewFactory.java @@ -90,7 +90,7 @@ public abstract class AbstractMvcViewFactory implements ViewFactory { mvcView.setFieldMarkerPrefix(fieldMarkerPrefix); } ViewActionStateHolder stateHolder = (ViewActionStateHolder) context.getFlashScope().get( - ViewActionStateHolder.KEY); + View.USER_EVENT_STATE_ATTRIBUTE); if (stateHolder != null) { mvcView.restoreState(stateHolder); } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java index 893e99fa..1e250195 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockExternalContext.java @@ -174,20 +174,17 @@ public class MockExternalContext implements ExternalContext { } public void requestFlowExecutionRedirect() throws IllegalStateException { - assertResponseAllowed(); flowExecutionRedirectRequested = true; recordResponseComplete(); } public void requestFlowDefinitionRedirect(String flowId, MutableAttributeMap input) throws IllegalStateException { - assertResponseAllowed(); flowDefinitionRedirectFlowId = flowId; flowDefinitionRedirectFlowInput = input; recordResponseComplete(); } public void requestExternalRedirect(String uri) throws IllegalStateException { - assertResponseAllowed(); externalRedirectUrl = uri; recordResponseComplete(); } @@ -435,8 +432,7 @@ public class MockExternalContext implements ExternalContext { throw new IllegalStateException( "A response is not allowed because an externalRedirect has already been requested on this ExternalContext"); } - throw new IllegalStateException( - "A response is not allowed because one has already been completed on this ExternalContext"); + throw new IllegalStateException("A response is not allowed"); } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestControlContext.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestControlContext.java index cb7c41a5..35c1c7ef 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestControlContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockRequestControlContext.java @@ -118,6 +118,9 @@ public class MockRequestControlContext extends MockRequestContext implements Req } public boolean getRedirectOnPause() { + if (!getExternalContext().isResponseAllowed()) { + return true; + } Boolean redirectOnPause = getMockFlowExecutionContext().getAttributes().getBoolean("alwaysRedirectOnPause"); return redirectOnPause != null ? redirectOnPause.booleanValue() : false; } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockViewFactoryCreator.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockViewFactoryCreator.java index a19fe07c..3ea1e4c1 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockViewFactoryCreator.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockViewFactoryCreator.java @@ -111,6 +111,10 @@ class MockViewFactoryCreator implements ViewFactoryCreator { return new Event(this, context.getRequestParameters().get("_eventId")); } + public Object getUserEventState() { + return null; + } + public void render() throws IOException { context.getExternalContext().getResponseWriter().write(viewId); } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/StubViewFactory.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/StubViewFactory.java index 81498b12..93772580 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/StubViewFactory.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/StubViewFactory.java @@ -45,6 +45,10 @@ public class StubViewFactory implements ViewFactory { } + public Object getUserEventState() { + return null; + } + public boolean hasFlowEvent() { return context.getExternalContext().getRequestParameterMap().contains("_eventId"); } @@ -52,5 +56,6 @@ public class StubViewFactory implements ViewFactory { public Event getFlowEvent() { return new Event(this, context.getExternalContext().getRequestParameterMap().get("_eventId")); } + } } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/ViewStateTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/ViewStateTests.java index 44d05ef2..ba44059f 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/ViewStateTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/ViewStateTests.java @@ -52,7 +52,7 @@ public class ViewStateTests extends TestCase { state.enter(context); assertFalse("Render called", context.getFlowScope().contains("renderCalled")); assertTrue(context.getExternalContext().isResponseComplete()); - assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested()); + assertTrue(context.getMockExternalContext().getFlowExecutionRedirectRequested()); } public void testEnterViewStateResponseAlreadyComplete() { @@ -160,22 +160,6 @@ public class ViewStateTests extends TestCase { assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested()); } - public void testResumeViewStateForRefreshResponseNotAllowed() { - Flow flow = new Flow("myFlow"); - StubViewFactory viewFactory = new StubViewFactory(); - ViewState state = new ViewState(flow, "viewState", viewFactory); - MockRequestControlContext context = new MockRequestControlContext(flow); - state.enter(context); - assertTrue("Render called", context.getFlowScope().contains("renderCalled")); - context = new MockRequestControlContext(context.getFlowExecutionContext()); - context.getMockExternalContext().setResponseAllowed(false); - context.getFlowScope().remove("renderCalled"); - state.resume(context); - assertFalse("Render called", context.getFlowScope().contains("renderCalled")); - assertTrue(context.getExternalContext().isResponseComplete()); - assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested()); - } - public void testResumeViewStateForRefreshResponseCompleteRecorded() { Flow flow = new Flow("myFlow"); StubViewFactory viewFactory = new StubViewFactory(); @@ -269,7 +253,7 @@ public class ViewStateTests extends TestCase { assertTrue(context.getFlowExecutionContext().isActive()); assertTrue(context.getExternalContext().isResponseComplete()); assertFalse("Render called", context.getFlowScope().contains("renderCalled")); - assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested()); + assertTrue(context.getMockExternalContext().getFlowExecutionRedirectRequested()); } public void testResumeViewStateForEventStateNotExitedNonAjaxRedirectEnabled() { @@ -315,30 +299,6 @@ public class ViewStateTests extends TestCase { assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested()); } - public void testResumeViewStateForEventStateNotExitedAjaxResponseNotAllowed() { - Flow flow = new Flow("myFlow"); - StubViewFactory viewFactory = new StubViewFactory(); - ViewState state = new ViewState(flow, "viewState", viewFactory); - Transition t = new Transition(on("submit"), null); - TestAction action = new TestAction(); - t.setExecutionCriteria(new ActionTransitionCriteria(action)); - state.getTransitionSet().add(t); - MockRequestControlContext context = new MockRequestControlContext(flow); - context.getMockExternalContext().setAjaxRequest(true); - state.enter(context); - context = new MockRequestControlContext(context.getFlowExecutionContext()); - context.putRequestParameter("_eventId", "submit"); - context.getMockExternalContext().setAjaxRequest(true); - context.getMockExternalContext().setResponseAllowed(false); - context.getFlowScope().remove("renderCalled"); - state.resume(context); - assertTrue(context.getFlowExecutionContext().isActive()); - assertEquals(1, action.getExecutionCount()); - assertTrue(context.getExternalContext().isResponseComplete()); - assertFalse("Render called", context.getFlowScope().contains("renderCalled")); - assertFalse(context.getMockExternalContext().getFlowExecutionRedirectRequested()); - } - public void testResumeViewStateForEventStateNoExitActionRecordedResponseComplete() { Flow flow = new Flow("myFlow"); StubViewFactory viewFactory = new StubViewFactory(); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/PortletMvcViewTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/PortletMvcViewTests.java index be1f8ec7..05b27e84 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/PortletMvcViewTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/PortletMvcViewTests.java @@ -16,7 +16,6 @@ import org.springframework.mock.web.portlet.MockRenderResponse; import org.springframework.web.servlet.ViewRendererServlet; import org.springframework.webflow.expression.DefaultExpressionParserFactory; import org.springframework.webflow.mvc.view.AbstractMvcView; -import org.springframework.webflow.mvc.view.ViewActionStateHolder; import org.springframework.webflow.mvc.view.MvcViewTests.BindBean; import org.springframework.webflow.test.MockFlowExecutionKey; import org.springframework.webflow.test.MockRequestContext; @@ -61,9 +60,6 @@ public class PortletMvcViewTests extends TestCase { view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); view.processUserEvent(); assertEquals(true, bindBean.getBooleanProperty()); - ViewActionStateHolder holder = (ViewActionStateHolder) context.getFlashScope().get(ViewActionStateHolder.KEY); - assertEquals("submit", holder.getEventId()); - assertNotNull(holder.getMappingResults()); } } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java index ba6bee23..1d7e0f9b 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/view/MvcViewTests.java @@ -228,71 +228,6 @@ public class MvcViewTests extends TestCase { context.setAlwaysRedirectOnPause(true); view.processUserEvent(); assertFalse(view.hasFlowEvent()); - assertTrue(context.getFlashScope().contains(ViewActionStateHolder.KEY)); - assertTrue(context.getExternalContext().isResponseCompleteFlowExecutionRedirect()); - view.render(); - assertEquals(context.getFlowScope().get("bindBean"), model.get("bindBean")); - BindingModel bm = (BindingModel) model.get(BindingResult.MODEL_KEY_PREFIX + "bindBean"); - assertNotNull(bm); - assertEquals("bogus 1", bm.getFieldValue("integerProperty")); - assertEquals("bogus 2", bm.getFieldValue("dateProperty")); - } - - public void testResumeEventBindingErrorsNoRedirectAllowed() throws Exception { - MockRequestControlContext context = new MockRequestControlContext(); - context.putRequestParameter("_eventId", "submit"); - context.putRequestParameter("integerProperty", "bogus 1"); - context.putRequestParameter("dateProperty", "bogus 2"); - BindBean bindBean = new BindBean(); - StaticExpression modelObject = new StaticExpression(bindBean); - modelObject.setExpressionString("bindBean"); - context.getCurrentState().getAttributes().put("model", modelObject); - context.getFlowScope().put("bindBean", bindBean); - context.getMockExternalContext().setNativeContext(new MockServletContext()); - context.getMockExternalContext().setNativeRequest(new MockHttpServletRequest()); - context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse()); - context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1")); - org.springframework.web.servlet.View mvcView = new MockView(); - AbstractMvcView view = new MockMvcView(mvcView, context); - view.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); - view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); - view.processUserEvent(); - assertTrue(context.getFlashScope().contains(ViewActionStateHolder.KEY)); - assertFalse(view.hasFlowEvent()); - assertFalse(context.getExternalContext().isResponseComplete()); - assertFalse(context.getExternalContext().isResponseCompleteFlowExecutionRedirect()); - view.render(); - assertEquals(context.getFlowScope().get("bindBean"), model.get("bindBean")); - BindingModel bm = (BindingModel) model.get(BindingResult.MODEL_KEY_PREFIX + "bindBean"); - assertNotNull(bm); - assertEquals("bogus 1", bm.getFieldValue("integerProperty")); - assertEquals("bogus 2", bm.getFieldValue("dateProperty")); - } - - public void testResumeEventBindingErrorsNoRedirectAjaxRequest() throws Exception { - MockRequestControlContext context = new MockRequestControlContext(); - context.putRequestParameter("_eventId", "submit"); - context.putRequestParameter("integerProperty", "bogus 1"); - context.putRequestParameter("dateProperty", "bogus 2"); - BindBean bindBean = new BindBean(); - StaticExpression modelObject = new StaticExpression(bindBean); - modelObject.setExpressionString("bindBean"); - context.getCurrentState().getAttributes().put("model", modelObject); - context.getFlowScope().put("bindBean", bindBean); - context.getMockExternalContext().setNativeContext(new MockServletContext()); - context.getMockExternalContext().setNativeRequest(new MockHttpServletRequest()); - context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse()); - context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1")); - org.springframework.web.servlet.View mvcView = new MockView(); - AbstractMvcView view = new MockMvcView(mvcView, context); - view.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); - view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); - context.getMockExternalContext().setAjaxRequest(true); - view.processUserEvent(); - assertFalse(view.hasFlowEvent()); - assertFalse(context.getExternalContext().isResponseComplete()); - assertFalse(context.getExternalContext().isResponseCompleteFlowExecutionRedirect()); - assertTrue(context.getFlashScope().contains(ViewActionStateHolder.KEY)); view.render(); assertEquals(context.getFlowScope().get("bindBean"), model.get("bindBean")); BindingModel bm = (BindingModel) model.get(BindingResult.MODEL_KEY_PREFIX + "bindBean");