diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandler.java
index 1feca90b..17fee0d1 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandler.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandler.java
@@ -22,6 +22,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.binding.mapping.AttributeMapper;
import org.springframework.web.jsf.DecoratingNavigationHandler;
+import org.springframework.web.jsf.DelegatingNavigationHandlerProxy;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
@@ -63,6 +64,9 @@ import org.springframework.webflow.executor.support.FlowExecutorArgumentExtracto
* How the flowId and eventId arguments are extracted can be customized by setting a custom
* {@link #setArgumentExtractor(FlowExecutorArgumentExtractor) argument extractor}.
*
+ * Note about customization: since NavigationHandlers managed directly by the JSF provider cannot be benefit from DependencyInjection,
+ * See Spring's {@link DelegatingNavigationHandlerProxy} when you need to customize a FlowNavigationHandler instance.
+ *
* @author Craig McClanahan
* @author Colin Sampaleanu
* @author Keith Donald
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandlerArgumentExtractor.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandlerArgumentExtractor.java
index 3025a705..faa3b707 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandlerArgumentExtractor.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandlerArgumentExtractor.java
@@ -33,7 +33,7 @@ import org.springframework.webflow.executor.support.FlowExecutorArgumentExtracto
public class FlowNavigationHandlerArgumentExtractor implements FlowExecutorArgumentExtractor {
/**
- * The default prefix of a outcome string that indicates a new flow should be launched.
+ * The default prefix of a JSF outcome string that indicates a new flow should be launched.
*/
private static final String FLOW_ID_PREFIX = "flowId:";
@@ -50,7 +50,7 @@ public class FlowNavigationHandlerArgumentExtractor implements FlowExecutorArgum
}
/**
- * Sets the prefix of a outcome string that indicates a new flow should be launched.
+ * Sets the prefix of an outcome string that indicates a new flow should be launched.
*/
public void setFlowIdPrefix(String flowIdPrefix) {
this.flowIdPrefix = flowIdPrefix;
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 eee12e50..0b5733a1 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
@@ -29,6 +29,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.web.jsf.DelegatingPhaseListenerMulticaster;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.context.ExternalContextHolder;
import org.springframework.webflow.core.collection.LocalAttributeMap;
@@ -52,23 +53,37 @@ import org.springframework.webflow.executor.support.RequestParameterFlowExecutor
import org.springframework.webflow.executor.support.ResponseInstructionHandler;
/**
- * JSF phase listener that is responsible for managing a {@link FlowExecution} object representing an active user
- * conversation so that other JSF artifacts that execute in different phases of the JSF lifecycle may have access to it.
+ * JSF phase listener responsible for managing the {@link FlowExecution} object lifecycle in a JSF environment. This
+ * class handles restoring and saving a FlowExecution so other JSF artifacts that execute in different phases of the JSF
+ * lifecycle may access conversational state and utilize Web Flow navigation behavior.
+ *
+ * A restored flow execution is placed in a holder that other JSF artifacts such as VariableResolvers, PropertyResolvers
+ * and NavigationHandlers may access during the request lifecycle. Once in the holder the execution is considered
+ * "restored" and referred to as the "current" flow execution for this request.
+ *
*
* This phase listener implements the following algorithm:
*
- * - On BEFORE_RESTORE_VIEW, restore the {@link FlowExecution} the user is participating in if a call to
- * {@link FlowExecutorArgumentHandler#extractFlowExecutionKey(ExternalContext)} returns a submitted flow execution key.
- * Place the restored flow execution in a holder that other JSF artifacts such as VariableResolvers, PropertyResolvers,
- * and NavigationHandlers may access during the request lifecycle.
- *
- On BEFORE_RENDER_RESPONSE, if a flow execution was restored in the RESTORE_VIEW phase generate a new key for
- * identifying the updated execution within a the selected {@link FlowExecutionRepository}. Expose the new flow
- * execution key as a component in the view root for restoration on the next request. Expose managed flow execution
- * attributes to the views before rendering.
+ *
- On BEFORE_RESTORE_VIEW, restore a {@link FlowExecution} if a call to
+ * {@link FlowExecutorArgumentHandler#extractFlowExecutionKey(ExternalContext)} returns a valid flow execution key. This
+ * occurs when a flow execution redirect or browser refresh is issued and ultimately results in a flow execution
+ * refresh.
+ *
- On BEFORE_RESTORE_VIEW, launch a {@link FlowExecution} if a call to
+ * {@link FlowExecutorArgumentHandler#extractFlowId(ExternalContext)} returns a valid flow id. This occurs when a
+ * browser accesses a flow definition URL directly and is used to launch a new flow execution.
+ *
- During RESTORE_VIEW, the {@link FlowExecutionKeyStateHolder state holder component} will restore the current
+ * FlowExecution if it is present in the JSF ViewRoot. This occurs when a postback from a JSF view that is participating
+ * in a flow.
+ *
- On BEFORE_RENDER_RESPONSE, if a flow execution was restored in the RESTORE_VIEW phase generate a new key that
+ * will identify the updated execution within the configured {@link FlowExecutionRepository}. Expose the new flow
+ * execution key as a component in the view root for restoration on the next request.
*
- On AFTER_RENDER_RESPONSE, if a flow execution was restored in the RESTORE_VIEW phase save the updated
* execution to the repository using the new key generated in the BEFORE_RENDER_RESPONSE phase.
*
*
+ * Note about customization: since PhaseListeners managed directly by the JSF provider cannot be benefit from DependencyInjection,
+ * See Spring's {@link DelegatingPhaseListenerMulticaster} when you need to customize a FlowPhaseListener instance.
+ *
* @author Colin Sampaleanu
* @author Keith Donald
* @author Jeremy Grelle
@@ -81,7 +96,27 @@ public class FlowPhaseListener implements PhaseListener {
protected final Log logger = LogFactory.getLog(getClass());
/**
- * A helper for handling arguments needed by this phase listener to resume and launch flow executions.
+ * A helper for handling arguments needed by this phase listener to restore and launch flow executions.
+ *
+ * This helper is responsible for two main things:
+ *
+ * - Helping in the restoration of the "current" FlowExecution by extracting arguments from the request.
+ * Specifically:
+ *
+ * - The flowExecutionKey argument is extracted to perform a flow execution refresh on redirects and browser
+ * refreshes.
+ *
- The flowId argument is extracted to perform a flow execution launch on direct browser access of a flow
+ * definition URL.
+ *
+ * - Generating URLs exposing the proper flow execution arguments. Specifically:
+ *
+ * - Generating the flow execution URL to redirect to on a FlowExecutionRedirect response.
+ *
- Generating the flow definition URL to redirect to on a FlowDefinitionRedirect response.
+ *
- Generating external URLs to redirect to on a ExternalRedirect repsonse.
+ *
+ *
+ * How arguments are extracted and how URLs are generated can be customized by setting a custom
+ * {{@link #setArgumentHandler(FlowExecutorArgumentHandler) argument handler}.
*/
private FlowExecutorArgumentHandler argumentHandler = new RequestParameterFlowExecutorArgumentHandler();
@@ -110,7 +145,24 @@ public class FlowPhaseListener implements PhaseListener {
}
/**
- * Sets the argument handler to use.
+ * Sets the handler for arguments needed by this phase listener to restore and launch flow executions.
+ * This handler is responsible for two things:
+ *
+ * - Helping in the restoration of the "current" FlowExecution by extracting arguments from the request.
+ * Specifically:
+ *
+ * - The flowExecutionKey argument is extracted to perform a flow execution refresh on redirects and browser
+ * refreshes.
+ *
- The flowId argument is extracted to perform a flow execution launch on direct browser access of a flow
+ * definition URL.
+ *
+ * - Generating URLs exposing the proper flow execution arguments. Specifically:
+ *
+ * - Generating the flow execution URL to redirect to on a FlowExecutionRedirect response.
+ *
- Generating the flow definition URL to redirect to on a FlowDefinitionRedirect response.
+ *
- Generating external URLs to redirect to on a ExternalRedirect repsonse.
+ *
+ *
*/
public void setArgumentHandler(FlowExecutorArgumentHandler argumentHandler) {
this.argumentHandler = argumentHandler;