diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java index d79d8691..8e011efa 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java @@ -37,6 +37,7 @@ import javax.faces.event.PhaseListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.binding.mapping.AttributeMapper; +import org.springframework.util.Assert; import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.context.ExternalContextHolder; import org.springframework.webflow.core.collection.LocalAttributeMap; @@ -416,8 +417,13 @@ public class FlowPhaseListener implements PhaseListener { ViewSelection selectedView = holder.getViewSelection(); if (selectedView == null) { - // no navigation event has been processed - simply refresh the execution with the same key - selectedView = holder.getFlowExecution().refresh(context); + if (holder.getFlowExecution().isActive()) { + // no navigation event has been processed - simply refresh the execution with the same key + selectedView = holder.getFlowExecution().refresh(context); + } else { + // fall back to a null-view + selectedView = ViewSelection.NULL_VIEW; + } holder.setViewSelection(selectedView); } else { // a navigation event has been processed - generate a new flow execution key if necessary @@ -536,6 +542,12 @@ public class FlowPhaseListener implements PhaseListener { */ protected void restoreFacesMessages(FacesContext context) { if (FlowExecutionHolderUtils.isFlowExecutionRestored(context)) { + if (!FlowExecutionHolderUtils.getRequiredCurrentFlowExecution(context).isActive()) { + // the flow execution has ended -- no need to restore faces messages since we can't have a + // redirect in this case anyway + return; + } + MutableAttributeMap scope = getFacesMessagesScope(context); Map facesMessagesMap = (Map) scope.get(getFacesMessagesKey()); if (facesMessagesMap != null) { @@ -559,6 +571,9 @@ public class FlowPhaseListener implements PhaseListener { * @since 1.0.6 */ protected void saveFacesMessages(FacesContext context) { + Assert.state(FlowExecutionHolderUtils.getCurrentFlowExecution(context).isActive(), + "The flow execution should be active when trying to save faces messages"); + // gather all message to put away in the flow execution Map facesMessagesMap = new HashMap(); for (Iterator clientIds = context.getClientIdsWithMessages(); clientIds.hasNext();) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfArgumentHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfArgumentHandler.java index e65cd567..b8be3322 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfArgumentHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfArgumentHandler.java @@ -22,8 +22,8 @@ import org.springframework.webflow.executor.support.RequestParameterFlowExecutor * {@link #createExternalUrl(org.springframework.webflow.execution.support.ExternalRedirect, String, ExternalContext) external URLs}, * since we're clearly not in a postback situation in those cases. *

- * Also note that the resulting URL could potentially be too long when using JSF client-side state saving mode. In general - * there are issues in trying to use alwaysRedirectOnPause with client-side state saving. + * Also note that the resulting URL could potentially be too long when using JSF client-side state saving mode. In + * general there are issues in trying to use alwaysRedirectOnPause with client-side state saving. * * @since 1.0.6 * @@ -45,5 +45,4 @@ public class JsfArgumentHandler extends RequestParameterFlowExecutorArgumentHand } return url.toString(); } - } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/support/AutowiringSupport.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/support/AutowiringSupport.java index 6f21ac21..ec50b675 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/support/AutowiringSupport.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/support/AutowiringSupport.java @@ -66,23 +66,26 @@ public abstract class AutowiringSupport { } /** - * Autowire all objects in flash, flow and conversation scope for given flow execution. + * Autowire all objects in flash, flow and conversation scope for given flow execution. Autowiring will only happen + * if the provided flow execution is still active. * @see #autowire(ScopeType, MutableAttributeMap) */ public void autowire(FlowExecutionContext flowExecutionContext) { - // no need to autowire request scope since that will be setup from scratch in this request + if (flowExecutionContext.isActive()) { + // no need to autowire request scope since that will be setup from scratch in this request - // autowire flash and flow scope for all flow sessions in the flow execution - FlowSession flowSession = flowExecutionContext.getActiveSession(); - while (flowSession != null) { - autowire(ScopeType.FLASH, flowSession.getFlashMap()); - autowire(ScopeType.FLOW, flowSession.getScope()); + // autowire flash and flow scope for all flow sessions in the flow execution + FlowSession flowSession = flowExecutionContext.getActiveSession(); + while (flowSession != null) { + autowire(ScopeType.FLASH, flowSession.getFlashMap()); + autowire(ScopeType.FLOW, flowSession.getScope()); - flowSession = flowSession.getParent(); + flowSession = flowSession.getParent(); + } + + // autowire conversation scope, which is not tied to the flow session + autowire(ScopeType.CONVERSATION, flowExecutionContext.getConversationScope()); } - - // autowire conversation scope, which is not tied to the flow session - autowire(ScopeType.CONVERSATION, flowExecutionContext.getConversationScope()); } /**