diff --git a/spring-webflow-reference/src/portlet.xml b/spring-webflow-reference/src/portlet.xml index a6e19b62..190a5d9d 100644 --- a/spring-webflow-reference/src/portlet.xml +++ b/spring-webflow-reference/src/portlet.xml @@ -190,6 +190,12 @@ externalContext.requestMap.portletMode The Portlet API only allows redirects to be requested from an action request. Because views are rendered on the render request, views and view-states cannot trigger a redirect. + The externalRedirect: view prefix is a convenience for Servlet based flows. + An IllegalStateException is thrown if a redirect is requested from a render request. + + + This limitation can be worked around for an end-state by implementing the FlowHandler.handleExecutionOutcome method. + This callback provides the ActionResponse object which supports redirects. diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java index f9018b39..de64c99a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java @@ -235,19 +235,31 @@ public class PortletExternalContext implements ExternalContext { } public void requestFlowExecutionRedirect() { + if (isRenderPhase()) { + throw new IllegalStateException("Redirects are not allowed durring the portlet render phase"); + } flowExecutionRedirectRequested = true; } public void requestExternalRedirect(String uri) { + if (isRenderPhase()) { + throw new IllegalStateException("Redirects are not allowed durring the portlet render phase"); + } externalRedirectUrl = uri; } public void requestFlowDefinitionRedirect(String flowId, MutableAttributeMap input) { + if (isRenderPhase()) { + throw new IllegalStateException("Redirects are not allowed durring the portlet render phase"); + } flowDefinitionRedirectFlowId = flowId; flowDefinitionRedirectFlowInput = input; } public void requestRedirectInPopup() { + if (isRenderPhase()) { + throw new IllegalStateException("Redirects are not allowed durring the portlet render phase"); + } redirectInPopup = true; } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/context/portlet/PortletExternalContextTests.java b/spring-webflow/src/test/java/org/springframework/webflow/context/portlet/PortletExternalContextTests.java index 37cf7da7..f31cb01a 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/context/portlet/PortletExternalContextTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/context/portlet/PortletExternalContextTests.java @@ -22,6 +22,8 @@ import org.springframework.mock.web.portlet.MockActionResponse; import org.springframework.mock.web.portlet.MockPortletContext; import org.springframework.mock.web.portlet.MockPortletRequest; import org.springframework.mock.web.portlet.MockPortletResponse; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; import org.springframework.webflow.context.servlet.ServletExternalContext; /** @@ -37,11 +39,20 @@ public class PortletExternalContextTests extends TestCase { private PortletExternalContext context; + private MockPortletRequest renderRequest; + + private MockPortletResponse renderResponse; + + private PortletExternalContext renderContext; + protected void setUp() { portletContext = new MockPortletContext(); request = new MockActionRequest(); response = new MockActionResponse(); context = new PortletExternalContext(portletContext, request, response); + renderRequest = new MockRenderRequest(); + renderResponse = new MockRenderResponse(); + renderContext = new PortletExternalContext(portletContext, renderRequest, renderResponse); } public void testGetContextPath() { @@ -76,18 +87,45 @@ public class PortletExternalContextTests extends TestCase { assertTrue(context.getFlowExecutionRedirectRequested()); } + public void testCommitExecutionRedirectRenderRequest() { + try { + renderContext.requestFlowExecutionRedirect(); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + // we want this + } + } + public void testCommitFlowRedirect() { context.requestFlowDefinitionRedirect("foo", null); assertTrue(context.getFlowDefinitionRedirectRequested()); assertEquals("foo", context.getFlowRedirectFlowId()); } + public void testCommitFlowRedirectRenderRequest() { + try { + renderContext.requestFlowDefinitionRedirect("foo", null); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + // we want this + } + } + public void testCommitExternalRedirect() { context.requestExternalRedirect("foo"); assertTrue(context.getExternalRedirectRequested()); assertEquals("foo", context.getExternalRedirectUrl()); } + public void testCommitExternalRedirectRenderRequest() { + try { + renderContext.requestExternalRedirect("foo"); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + // we want this + } + } + public void testCommitExecutionRedirectPopup() { context.requestFlowExecutionRedirect(); context.requestRedirectInPopup(); @@ -111,6 +149,15 @@ public class PortletExternalContextTests extends TestCase { assertTrue(context.getRedirectInPopup()); } + public void testExecutionRedirectPopupRenderRequest() { + try { + renderContext.requestRedirectInPopup(); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + // we want this + } + } + public void testResponseAllowed() { assertFalse(context.isResponseAllowed()); }