From 0570108b8c591fc5ee3b95676427f3b7b8217c26 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Tue, 7 Apr 2009 20:24:14 +0000 Subject: [PATCH] now redirecting after post that generated bind/validation errors if redirectOnPause=true; consistent with redirect behavior if a transition executes but does not change state --- .../faces/webflow/JsfView.java | 2 +- .../webflow/mvc/view/AbstractMvcView.java | 12 +++- .../test/MockRequestControlContext.java | 8 +-- .../webflow/mvc/view/MvcViewTests.java | 67 +++++++++++++++++++ 4 files changed, 83 insertions(+), 6 deletions(-) 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 03fef9aa..b8086bf9 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 @@ -104,7 +104,7 @@ public class JsfView implements View { } /* - * Executes postback-processing portions of the standard JSF lifecyle including APPLY_REQUEST_VALUES through + * Executes postback-processing portions of the standard JSF lifecycle including APPLY_REQUEST_VALUES through * INVOKE_APPLICATION. */ public void processUserEvent() { 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 1448fa7d..9cbff6eb 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 @@ -45,6 +45,7 @@ import org.springframework.util.Assert; import org.springframework.validation.BindingResult; import org.springframework.validation.MessageCodesResolver; import org.springframework.web.util.WebUtils; +import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.ParameterMap; import org.springframework.webflow.definition.TransitionDefinition; @@ -215,9 +216,18 @@ public abstract class AbstractMvcView implements View { validate(model); } } - if (mappingResults != null && mappingResults.hasErrorResults()) { + if (mappingResults != null && hasErrors(mappingResults)) { requestContext.getFlashScope().put(ViewActionStateHolder.KEY, new ViewActionStateHolder(eventId, mappingResults)); + ExternalContext context = requestContext.getExternalContext(); + if (!context.isAjaxRequest()) { + Boolean redirectOnPause = requestContext.getFlowExecutionContext().getAttributes().getBoolean( + "alwaysRedirectOnPause"); + boolean redirectAllowed = redirectOnPause != null ? redirectOnPause.booleanValue() : false; + if (redirectAllowed) { + requestContext.getExternalContext().requestFlowExecutionRedirect(); + } + } } } 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 a548caf3..cb7c41a5 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 @@ -38,8 +38,6 @@ import org.springframework.webflow.execution.View; */ public class MockRequestControlContext extends MockRequestContext implements RequestControlContext { - private boolean alwaysRedirectOnPause; - /** * Creates a new mock request control context. */ @@ -120,13 +118,15 @@ public class MockRequestControlContext extends MockRequestContext implements Req } public boolean getRedirectOnPause() { - return alwaysRedirectOnPause; + Boolean redirectOnPause = getMockFlowExecutionContext().getAttributes().getBoolean("alwaysRedirectOnPause"); + return redirectOnPause != null ? redirectOnPause.booleanValue() : false; } // implementation specific accessors for testing public void setAlwaysRedirectOnPause(boolean alwaysRedirectOnPause) { - this.alwaysRedirectOnPause = alwaysRedirectOnPause; + getMockFlowExecutionContext().getAttributeMap().put("alwaysRedirectOnPause", + Boolean.valueOf(alwaysRedirectOnPause)); } } \ No newline at end of file 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 e3c51f4d..ba6bee23 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 @@ -178,6 +178,7 @@ public class MvcViewTests extends TestCase { view.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); view.processUserEvent(); assertTrue(view.hasFlowEvent()); + assertFalse(context.getFlashScope().contains(ViewActionStateHolder.KEY)); assertEquals("submit", view.getFlowEvent().getId()); assertEquals("foo", bindBean.getStringProperty()); assertEquals(new Integer(5), bindBean.getIntegerProperty()); @@ -224,8 +225,74 @@ public class MvcViewTests extends TestCase { AbstractMvcView view = new MockMvcView(mvcView, context); view.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); view.setMessageCodesResolver(new WebFlowMessageCodesResolver()); + 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");