From bcf469722ff85ae2a9ced7aacab7d9a90208ef75 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Mon, 6 Apr 2009 16:13:32 +0000 Subject: [PATCH] flash scope fix initial commit --- .../webflow/context/ExternalContext.java | 19 +++++- .../portlet/PortletExternalContext.java | 28 +++++--- .../servlet/ServletExternalContext.java | 14 +++- .../webflow/engine/ViewState.java | 67 +++++++++++++------ .../webflow/test/MockExternalContext.java | 14 +++- 5 files changed, 103 insertions(+), 39 deletions(-) diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContext.java index 5a8a4f69..3b74ee01 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContext.java @@ -146,19 +146,25 @@ public interface ExternalContext { /** * Request that a flow execution redirect be performed by the calling environment. Typically called from within a * flow execution to request a refresh operation, usually to support "refresh after event processing" behavior. + * Calling this method also sets responseComplete status to true. + * @see #isResponseComplete() */ public void requestFlowExecutionRedirect(); /** * Request that a flow definition redirect be performed by the calling environment. Typically called from within a * flow execution end state to request starting a new, independent execution of a flow in a chain-like manner. + * Calling this method also sets responseComplete status to true. + * @see #isResponseComplete() * @param flowId the id of the flow definition to redirect to * @param input input to pass the flow; this input is generally encoded the url to launch the flow */ public void requestFlowDefinitionRedirect(String flowId, MutableAttributeMap input); /** - * Request a redirect to an arbitrary resource location. May not be supported in some environments. + * Request a redirect to an arbitrary resource location. May not be supported in some environments. Calling this + * method also sets responseComplete status to true. + * @see #isResponseComplete() * @param location the location of the resource to redirect to */ public void requestExternalRedirect(String location); @@ -185,4 +191,15 @@ public interface ExternalContext { */ public boolean isResponseComplete(); + /** + * Returns true if the response has been completed with a request to redirect the caller to another resource. + * Supported redirects are flow execution redirects, flow definition redirects, and external redirects. + * @return true if a redirect response has been completed + * @see #isResponseComplete() + * @see #requestFlowExecutionRedirect() + * @see #requestFlowDefinitionRedirect(String, MutableAttributeMap) + * @see #requestExternalRedirect(String) + */ + public boolean isRedirectRequested(); + } \ No newline at end of file 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 de64c99a..3e66a321 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 @@ -94,7 +94,7 @@ public class PortletExternalContext implements ExternalContext { * A flag indicating if the flow committed the response. Set to true by requesting an execution redirect, definition * redirect, external redirect, or by calling {@link ExternalContext#recordResponseComplete()} */ - private boolean responseCommitted; + private boolean responseComplete; /** * A flag indicating if a flow execution redirect has been requested. @@ -227,11 +227,11 @@ public class PortletExternalContext implements ExternalContext { } public boolean isResponseComplete() { - return responseCommitted; + return responseComplete; } public void recordResponseComplete() { - responseCommitted = true; + responseComplete = true; } public void requestFlowExecutionRedirect() { @@ -239,13 +239,7 @@ public class PortletExternalContext implements ExternalContext { 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; + recordResponseComplete(); } public void requestFlowDefinitionRedirect(String flowId, MutableAttributeMap input) { @@ -254,6 +248,15 @@ public class PortletExternalContext implements ExternalContext { } flowDefinitionRedirectFlowId = flowId; flowDefinitionRedirectFlowInput = input; + recordResponseComplete(); + } + + public void requestExternalRedirect(String uri) { + if (isRenderPhase()) { + throw new IllegalStateException("Redirects are not allowed durring the portlet render phase"); + } + externalRedirectUrl = uri; + recordResponseComplete(); } public void requestRedirectInPopup() { @@ -263,6 +266,11 @@ public class PortletExternalContext implements ExternalContext { redirectInPopup = true; } + public boolean isRedirectRequested() { + return getFlowExecutionRedirectRequested() || getFlowDefinitionRedirectRequested() + || getExternalRedirectRequested(); + } + // implementation specific methods /** diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/ServletExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/ServletExternalContext.java index 2e38a6db..0505b11f 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/ServletExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/servlet/ServletExternalContext.java @@ -80,7 +80,7 @@ public class ServletExternalContext implements ExternalContext { * A flag indicating if the flow committed the response. Set to true by requesting an execution redirect, definition * redirect, external redirect, or by calling {@link ExternalContext#recordResponseComplete()} */ - private boolean responseCommitted; + private boolean responseComplete; /** * A flag indicating if a flow execution redirect has been requested. @@ -220,30 +220,38 @@ public class ServletExternalContext implements ExternalContext { } public boolean isResponseComplete() { - return responseCommitted; + return responseComplete; } public void recordResponseComplete() { - responseCommitted = true; + responseComplete = true; } public void requestFlowExecutionRedirect() { flowExecutionRedirectRequested = true; + recordResponseComplete(); } public void requestExternalRedirect(String location) { externalRedirectUrl = location; + recordResponseComplete(); } public void requestFlowDefinitionRedirect(String flowId, MutableAttributeMap input) { flowDefinitionRedirectFlowId = flowId; flowDefinitionRedirectFlowInput = input; + recordResponseComplete(); } public void requestRedirectInPopup() { redirectInPopup = true; } + public boolean isRedirectRequested() { + return getFlowExecutionRedirectRequested() || getFlowDefinitionRedirectRequested() + || getExternalRedirectRequested(); + } + // implementation specific methods /** 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 f741e219..e33a1ea4 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 @@ -169,15 +169,22 @@ public class ViewState extends TransitionableState { protected void doEnter(RequestControlContext context) throws FlowExecutionException { context.assignFlowExecutionKey(); - if (canSendResponse(context.getExternalContext())) { - if (shouldRedirect(context)) { - context.getExternalContext().requestFlowExecutionRedirect(); - if (popup) { - context.getExternalContext().requestRedirectInPopup(); + ExternalContext externalContext = context.getExternalContext(); + if (externalContext.isResponseAllowed()) { + if (externalContext.isResponseComplete()) { + if (!externalContext.isRedirectRequested()) { + clearFlash(context); } } else { - View view = viewFactory.getView(context); - render(context, view); + if (shouldRedirect(context)) { + context.getExternalContext().requestFlowExecutionRedirect(); + if (popup) { + context.getExternalContext().requestRedirectInPopup(); + } + } else { + View view = viewFactory.getView(context); + render(context, view); + } } } } @@ -192,20 +199,36 @@ public class ViewState extends TransitionableState { logger.debug("Event '" + event.getId() + "' returned from view " + view); } boolean stateExited = context.handleEvent(event); - if (!stateExited && canSendResponse(context.getExternalContext())) { - if (context.getExternalContext().isAjaxRequest()) { - render(context, view); - } else { - if (shouldRedirect(context)) { - context.getExternalContext().requestFlowExecutionRedirect(); + if (!stateExited) { + ExternalContext externalContext = context.getExternalContext(); + if (externalContext.isResponseAllowed()) { + if (externalContext.isResponseComplete()) { + if (!externalContext.isRedirectRequested()) { + clearFlash(context); + } } else { - render(context, view); + if (externalContext.isAjaxRequest()) { + render(context, view); + } else { + if (shouldRedirect(context)) { + externalContext.requestFlowExecutionRedirect(); + } else { + render(context, view); + } + } } } } } else { - if (canSendResponse(context.getExternalContext())) { - render(context, view); + ExternalContext externalContext = context.getExternalContext(); + if (externalContext.isResponseAllowed()) { + if (externalContext.isResponseComplete()) { + if (!externalContext.isRedirectRequested()) { + clearFlash(context); + } + } else { + render(context, view); + } } } } @@ -229,10 +252,6 @@ public class ViewState extends TransitionableState { } } - private boolean canSendResponse(ExternalContext context) { - return context.isResponseAllowed() && !context.isResponseComplete(); - } - private boolean shouldRedirect(RequestControlContext context) { if (redirect != null) { return redirect.booleanValue(); @@ -254,12 +273,16 @@ public class ViewState extends TransitionableState { } catch (IOException e) { throw new ViewRenderingException(getOwner().getId(), getId(), view, e); } - context.getFlashScope().clear(); - context.getMessageContext().clearMessages(); + clearFlash(context); context.getExternalContext().recordResponseComplete(); context.viewRendered(view); } + private void clearFlash(RequestControlContext context) { + context.getFlashScope().clear(); + context.getMessageContext().clearMessages(); + } + private void restoreVariables(RequestContext context) { Iterator it = variables.values().iterator(); while (it.hasNext()) { 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 1fd85e84..1634ac64 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 @@ -63,7 +63,7 @@ public class MockExternalContext implements ExternalContext { private boolean ajaxRequest; - private boolean responseCommitted; + private boolean responseCompleted; private boolean flowExecutionRedirectRequested; @@ -155,30 +155,38 @@ public class MockExternalContext implements ExternalContext { } public boolean isResponseComplete() { - return responseCommitted; + return responseCompleted; } public void recordResponseComplete() throws IllegalStateException { - responseCommitted = true; + responseCompleted = true; } public void requestFlowExecutionRedirect() { flowExecutionRedirectRequested = true; + recordResponseComplete(); } public void requestFlowDefinitionRedirect(String flowId, MutableAttributeMap input) { flowDefinitionRedirectFlowId = flowId; flowDefinitionRedirectFlowInput = input; + recordResponseComplete(); } public void requestExternalRedirect(String uri) { externalRedirectUrl = uri; + recordResponseComplete(); } public void requestRedirectInPopup() { redirectInPopup = true; } + public boolean isRedirectRequested() { + return getFlowExecutionRedirectRequested() || getFlowDefinitionRedirectRequested() + || getExternalRedirectRequested(); + } + /** * Set the context path of the application. * @param contextPath the context path