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 17fee0d1..6b114119 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,7 +22,6 @@ 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; @@ -64,8 +63,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. + * Note about customization: since NavigationHandlers managed directly by the JSF provider cannot be benefit from + * DependencyInjection, See Spring's {@link org.springframework.web.jsf.DelegatingNavigationHandlerProxy} when you need + * to customize a FlowNavigationHandler instance. * * @author Craig McClanahan * @author Colin Sampaleanu 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 7df804cc..6db87a83 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,7 +29,6 @@ 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; @@ -53,47 +52,37 @@ import org.springframework.webflow.executor.support.RequestParameterFlowExecutor import org.springframework.webflow.executor.support.ResponseInstructionHandler; /** - * 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. + * 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 + * 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: *

* - * 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. + * Note about customization: since PhaseListeners managed directly by the JSF provider cannot be benefit from + * DependencyInjection, See Spring's {@link org.springframework.web.jsf.DelegatingPhaseListenerMulticaster} when you + * need to customize a FlowPhaseListener instance. * * @author Colin Sampaleanu * @author Keith Donald @@ -107,47 +96,38 @@ public class FlowPhaseListener implements PhaseListener { protected final Log logger = LogFactory.getLog(getClass()); /** - * A helper for handling arguments needed by this phase listener to restore - * 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: *
    - *
  1. Helping in the restoration of the "current" FlowExecution by - * extracting arguments from the request. Specifically: - * - *
  2. Generating URLs exposing the proper flow execution arguments. + *
  3. Helping in the restoration of the "current" FlowExecution by extracting arguments from the request. * Specifically: * + *
  4. Generating URLs exposing the proper flow execution arguments. Specifically: + * *
- * How arguments are extracted and how URLs are generated can be customized - * by setting a custom {{@link #setArgumentHandler(FlowExecutorArgumentHandler) argument handler}. + * 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(); /** - * The service responsible for mapping attributes of an - * {@link ExternalContext} to a new {@link FlowExecution} during the - * {@link #launch(String, ExternalContext) launch flow} operation. + * The service responsible for mapping attributes of an {@link ExternalContext} to a new {@link FlowExecution} + * during the {@link #launch(String, ExternalContext) launch flow} operation. *

- * This allows developers to control what attributes are made available in - * the inputMap to new top-level flow executions. The - * starting execution may then choose to map that available input into its - * own local scope. + * This allows developers to control what attributes are made available in the inputMap to new + * top-level flow executions. The starting execution may then choose to map that available input into its own local + * scope. *

- * The default implementation simply exposes all request parameters as flow - * execution input attributes. May be null. + * The default implementation simply exposes all request parameters as flow execution input attributes. May be null. */ private AttributeMapper inputMapper = new RequestParameterInputMapper(); @@ -164,28 +144,25 @@ public class FlowPhaseListener implements PhaseListener { } /** - * Sets the handler for arguments needed by this phase listener to restore - * and launch flow executions. This handler is responsible for two things: + * Sets the handler for arguments needed by this phase listener to restore and launch flow executions. This handler + * is responsible for two things: *

    - *
  1. Helping in the restoration of the "current" FlowExecution by - * extracting arguments from the request. Specifically: - * - *
  2. Generating URLs exposing the proper flow execution arguments. + *
  3. Helping in the restoration of the "current" FlowExecution by extracting arguments from the request. * Specifically: * + *
  4. Generating URLs exposing the proper flow execution arguments. Specifically: + * *
+ * @param argumentHandler the argument handler */ public void setArgumentHandler(FlowExecutorArgumentHandler argumentHandler) { this.argumentHandler = argumentHandler; @@ -199,13 +176,11 @@ public class FlowPhaseListener implements PhaseListener { } /** - * Sets the service responsible for mapping attributes of an - * {@link ExternalContext} to a new {@link FlowExecution} during a launch - * flow operation. + * Sets the service responsible for mapping attributes of an {@link ExternalContext} to a new {@link FlowExecution} + * during a launch flow operation. *

- * The default implementation simply exposes all request parameters as flow - * execution input attributes. May be null. - * + * The default implementation simply exposes all request parameters as flow execution input attributes. May be null. + * @param inputMapper the input mapper * @see RequestParameterInputMapper */ public void setInputMapper(AttributeMapper inputMapper) { @@ -220,27 +195,22 @@ public class FlowPhaseListener implements PhaseListener { } /** - * Sets the JSF view id mapper used by this phase listener. The - * {@link ViewIdMapper} provides a mechanism to convert a logical SWF view - * id into JSF view id.
+ * Sets the JSF view id mapper used by this phase listener. The {@link ViewIdMapper} provides a mechanism to convert + * a logical Spring Web Flow application view name into a JSF view id.
* - * View ids are important to JSF: it uses them to check whether a view has - * changed, and also to locate the physical template for the layout. The JSF - * view id is not the exact physical location of a view template, nor is it - * a purely logical value: it normally specifies the physical location of a - * view template minus a suffix.
+ * JSF view ids are important to this phase listener: it uses them to check whether the current view has changed, + * and if a new view needs to be created and activated by delegating to the application's {@link ViewHandler}. * - * JSF replaces the suffix of any view id it gets with its own default - * suffix (e.g. ".jsp" or ".xhtml"), and then tries to locate a physical - * template view. Thus the {@link ViewIdMapper} gives us a chance to convert - * a SWF view id into a physical path that will be used by JSF to locate the - * template. (It doesn't matter what suffix we use on the JSF view id, it - * will always be replaced to locate the phyical template.)
+ * A view handler typically treats a JSF view id as the physical location of a view template encapsulating a page + * layout. The JSF view id normally specifies the physical location of the view template minus a suffix. View + * handlers typically replace the suffix of any view id with their own default suffix (e.g. ".jsp" or ".xhtml") and + * then try to locate a physical template view. * - * The default value for the view id mapper is a {@link DefaultViewIdMapper} - * which just passes through the SWF viewId.
- * - * @see ViewIdMapper + * The {@link ViewIdMapper} provides the ability to customize how SWF view name is mapped to a JSF view id that will + * be passed to the ViewHandler. The default value for the view id mapper is a {@link DefaultViewIdMapper} which + * just returns the SWF viewId as-is. + * @param viewIdMapper the view id mapper + * @see #prepareApplicationView(FacesContext, FlowExecutionHolder) */ public void setViewIdMapper(ViewIdMapper viewIdMapper) { this.viewIdMapper = viewIdMapper; @@ -252,14 +222,13 @@ public class FlowPhaseListener implements PhaseListener { public void beforePhase(PhaseEvent event) { if (event.getPhaseId() == PhaseId.RESTORE_VIEW) { - ExternalContextHolder.setExternalContext(new JsfExternalContext( - event.getFacesContext())); + ExternalContextHolder.setExternalContext(new JsfExternalContext(event.getFacesContext())); restoreFlowExecution(event.getFacesContext()); - } else if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) { - if (FlowExecutionHolderUtils.isFlowExecutionRestored(event - .getFacesContext())) { - prepareResponse(getCurrentContext(), FlowExecutionHolderUtils - .getFlowExecutionHolder(event.getFacesContext())); + } + else if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) { + if (FlowExecutionHolderUtils.isFlowExecutionRestored(event.getFacesContext())) { + prepareResponse(getCurrentContext(), FlowExecutionHolderUtils.getFlowExecutionHolder(event + .getFacesContext())); } } } @@ -267,19 +236,20 @@ public class FlowPhaseListener implements PhaseListener { public void afterPhase(PhaseEvent event) { if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) { try { - if (FlowExecutionHolderUtils.isFlowExecutionRestored(event - .getFacesContext())) { - FlowExecutionHolder holder = FlowExecutionHolderUtils - .getFlowExecutionHolder(event.getFacesContext()); + if (FlowExecutionHolderUtils.isFlowExecutionRestored(event.getFacesContext())) { + FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(event + .getFacesContext()); try { saveFlowExecution(getCurrentContext(), holder); - } finally { + } + finally { if (holder.getFlowExecutionLock() != null) { holder.getFlowExecutionLock().unlock(); } } } - } finally { + } + finally { ExternalContextHolder.setExternalContext(null); } } @@ -293,53 +263,41 @@ public class FlowPhaseListener implements PhaseListener { // (this could happen as part of a flow execution redirect or // browser refresh) FlowExecutionRepository repository = getRepository(context); - FlowExecutionKey flowExecutionKey = repository - .parseFlowExecutionKey(argumentHandler - .extractFlowExecutionKey(context)); + FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(argumentHandler + .extractFlowExecutionKey(context)); FlowExecutionLock lock = repository.getLock(flowExecutionKey); lock.lock(); - FlowExecution flowExecution = repository - .getFlowExecution(flowExecutionKey); + FlowExecution flowExecution = repository.getFlowExecution(flowExecutionKey); if (logger.isDebugEnabled()) { - logger - .debug("Loaded existing flow execution key '" - + flowExecutionKey - + "' due to browser access " - + "[either via a flow execution redirect or direct browser refresh]"); + logger.debug("Loaded existing flow execution key '" + flowExecutionKey + "' due to browser access " + + "[either via a flow execution redirect or direct browser refresh]"); } - FlowExecutionHolderUtils.setFlowExecutionHolder( - new FlowExecutionHolder(flowExecutionKey, flowExecution, - lock), facesContext); - } else if (argumentHandler.isFlowIdPresent(context)) { + FlowExecutionHolderUtils.setFlowExecutionHolder(new FlowExecutionHolder(flowExecutionKey, flowExecution, + lock), facesContext); + } + else if (argumentHandler.isFlowIdPresent(context)) { // launch a new flow execution // (this could happen as part of direct browser access or a flow // definition redirect) String flowId = argumentHandler.extractFlowId(context); - FlowDefinition flowDefinition = getLocator(context) - .getFlowDefinition(flowId); - FlowExecution flowExecution = getFactory(context) - .createFlowExecution(flowDefinition); + FlowDefinition flowDefinition = getLocator(context).getFlowDefinition(flowId); + FlowExecution flowExecution = getFactory(context).createFlowExecution(flowDefinition); FlowExecutionHolder holder = new FlowExecutionHolder(flowExecution); - FlowExecutionHolderUtils.setFlowExecutionHolder(holder, - facesContext); - ViewSelection selectedView = flowExecution.start( - createInput(context), context); + FlowExecutionHolderUtils.setFlowExecutionHolder(holder, facesContext); + ViewSelection selectedView = flowExecution.start(createInput(context), context); holder.setViewSelection(selectedView); if (logger.isDebugEnabled()) { - logger - .debug("Launched a new flow execution due to browser access " - + "[either via a flow redirect or direct browser URL access]"); + logger.debug("Launched a new flow execution due to browser access " + + "[either via a flow redirect or direct browser URL access]"); } } } /** - * Factory method that creates the input attribute map for a newly created - * {@link FlowExecution}. This implementation uses the registered input - * mapper, if any. + * Factory method that creates the input attribute map for a newly created {@link FlowExecution}. This + * implementation uses the registered input mapper, if any. * - * @param context - * the external context + * @param context the external context * @return the input map, or null if no input */ protected MutableAttributeMap createInput(ExternalContext context) { @@ -347,22 +305,19 @@ public class FlowPhaseListener implements PhaseListener { MutableAttributeMap inputMap = new LocalAttributeMap(); inputMapper.map(context, inputMap, null); return inputMap; - } else { + } + else { return null; } } /** - * Prepare the appropriate JSF response (e.g. rendering a view, sending a - * redirect, etc). + * Prepare the appropriate JSF response (e.g. rendering a view, sending a redirect, etc). * - * @param context - * the context - * @param holder - * the holder + * @param context the context + * @param holder the holder */ - protected void prepareResponse(final JsfExternalContext context, - final FlowExecutionHolder holder) { + protected void prepareResponse(final JsfExternalContext context, final FlowExecutionHolder holder) { generateKey(context, holder); ViewSelection selectedView = holder.getViewSelection(); if (selectedView == null) { @@ -370,33 +325,25 @@ public class FlowPhaseListener implements PhaseListener { holder.setViewSelection(selectedView); } new ResponseInstructionHandler() { - protected void handleApplicationView(ApplicationView view) - throws Exception { + protected void handleApplicationView(ApplicationView view) throws Exception { prepareApplicationView(context.getFacesContext(), holder); } - protected void handleFlowDefinitionRedirect( - FlowDefinitionRedirect redirect) throws Exception { - String url = argumentHandler.createFlowDefinitionUrl(redirect, - context); + protected void handleFlowDefinitionRedirect(FlowDefinitionRedirect redirect) throws Exception { + String url = argumentHandler.createFlowDefinitionUrl(redirect, context); sendRedirect(url, context); } - protected void handleFlowExecutionRedirect( - FlowExecutionRedirect redirect) throws Exception { - String url = argumentHandler.createFlowExecutionUrl(holder - .getFlowExecutionKey().toString(), holder + protected void handleFlowExecutionRedirect(FlowExecutionRedirect redirect) throws Exception { + String url = argumentHandler.createFlowExecutionUrl(holder.getFlowExecutionKey().toString(), holder .getFlowExecution(), context); sendRedirect(url, context); } - protected void handleExternalRedirect(ExternalRedirect redirect) - throws Exception { - String flowExecutionKey = holder.getFlowExecution().isActive() ? holder - .getFlowExecutionKey().toString() - : null; - String url = argumentHandler.createExternalUrl(redirect, - flowExecutionKey, context); + protected void handleExternalRedirect(ExternalRedirect redirect) throws Exception { + String flowExecutionKey = holder.getFlowExecution().isActive() ? holder.getFlowExecutionKey() + .toString() : null; + String url = argumentHandler.createExternalUrl(redirect, flowExecutionKey, context); sendRedirect(url, context); } @@ -404,65 +351,52 @@ public class FlowPhaseListener implements PhaseListener { // nothing to do } - }.handleQuietly(new ResponseInstruction(holder.getFlowExecution(), - selectedView)); + }.handleQuietly(new ResponseInstruction(holder.getFlowExecution(), selectedView)); } /** * Prepare the JSF view for rendering. * - * @param facesContext - * the faces context - * @param holder - * the holder of the current flow execution + * @param facesContext the faces context + * @param holder the holder of the current flow execution */ - protected void prepareApplicationView(FacesContext facesContext, - FlowExecutionHolder holder) { + protected void prepareApplicationView(FacesContext facesContext, FlowExecutionHolder holder) { ApplicationView view = (ApplicationView) holder.getViewSelection(); if (view != null) { // expose the view's "model map" in the request map - putInto(facesContext.getExternalContext().getRequestMap(), view - .getModel()); + putInto(facesContext.getExternalContext().getRequestMap(), view.getModel()); // update the root component if necessary - updateViewRoot(facesContext, viewIdMapper.mapViewId(view - .getViewName())); + updateViewRoot(facesContext, viewIdMapper.mapViewId(view.getViewName())); } - String flowExecutionKey = holder.getFlowExecution().isActive() ? holder - .getFlowExecutionKey().toString() : null; + String flowExecutionKey = holder.getFlowExecution().isActive() ? holder.getFlowExecutionKey().toString() : null; if (flowExecutionKey != null) { saveInViewRoot(facesContext, flowExecutionKey); } Map requestMap = facesContext.getExternalContext().getRequestMap(); - argumentHandler.exposeFlowExecutionContext(flowExecutionKey, holder - .getFlowExecution(), requestMap); + argumentHandler.exposeFlowExecutionContext(flowExecutionKey, holder.getFlowExecution(), requestMap); } /** * Updates the current flow execution in the repository. * - * @param context - * the external context - * @param holder - * the current flow execution holder + * @param context the external context + * @param holder the current flow execution holder */ - protected void saveFlowExecution(JsfExternalContext context, - FlowExecutionHolder holder) { + protected void saveFlowExecution(JsfExternalContext context, FlowExecutionHolder holder) { FlowExecution flowExecution = holder.getFlowExecution(); FlowExecutionRepository repository = getRepository(context); if (flowExecution.isActive()) { // save the flow execution out to the repository if (logger.isDebugEnabled()) { - logger.debug("Saving continuation to repository with key " - + holder.getFlowExecutionKey()); + logger.debug("Saving continuation to repository with key " + holder.getFlowExecutionKey()); } - repository.putFlowExecution(holder.getFlowExecutionKey(), - flowExecution); - } else { + repository.putFlowExecution(holder.getFlowExecutionKey(), flowExecution); + } + else { if (holder.getFlowExecutionKey() != null) { // remove the flow execution from the repository if (logger.isDebugEnabled()) { - logger.debug("Removing execution in repository with key '" - + holder.getFlowExecutionKey() + "'"); + logger.debug("Removing execution in repository with key '" + holder.getFlowExecutionKey() + "'"); } repository.removeFlowExecution(holder.getFlowExecutionKey()); } @@ -479,8 +413,7 @@ public class FlowPhaseListener implements PhaseListener { UIViewRoot viewRoot = facesContext.getViewRoot(); if (viewRoot == null || hasViewChanged(viewRoot, viewId)) { // create the specified view so that it can be rendered - ViewHandler handler = facesContext.getApplication() - .getViewHandler(); + ViewHandler handler = facesContext.getApplication().getViewHandler(); UIViewRoot view = handler.createView(facesContext, viewId); facesContext.setViewRoot(view); } @@ -491,20 +424,16 @@ public class FlowPhaseListener implements PhaseListener { } /** - * Saves the flow execution key in a component in the view root for - * restoration on subsequent RESTORE_VIEW operations. + * Saves the flow execution key in a component in the view root for restoration on subsequent RESTORE_VIEW + * operations. * - * @param facesContext - * the faces context exposing the view root - * @param flowExecutionKey - * the flow execution key + * @param facesContext the faces context exposing the view root + * @param flowExecutionKey the flow execution key */ - private void saveInViewRoot(FacesContext facesContext, - String flowExecutionKey) { + private void saveInViewRoot(FacesContext facesContext, String flowExecutionKey) { // search for key holder in the component tree - FlowExecutionKeyStateHolder keyHolder = (FlowExecutionKeyStateHolder) facesContext - .getViewRoot().findComponent( - FlowExecutionKeyStateHolder.COMPONENT_ID); + FlowExecutionKeyStateHolder keyHolder = (FlowExecutionKeyStateHolder) facesContext.getViewRoot().findComponent( + FlowExecutionKeyStateHolder.COMPONENT_ID); if (keyHolder == null) { keyHolder = new FlowExecutionKeyStateHolder(); // expose as the first component in the view root for preservation @@ -514,8 +443,7 @@ public class FlowPhaseListener implements PhaseListener { keyHolder.setFlowExecutionKey(flowExecutionKey); } - private void generateKey(JsfExternalContext context, - FlowExecutionHolder holder) { + private void generateKey(JsfExternalContext context, FlowExecutionHolder holder) { FlowExecution flowExecution = holder.getFlowExecution(); if (flowExecution.isActive()) { // generate new continuation key for the flow execution before @@ -525,30 +453,28 @@ public class FlowPhaseListener implements PhaseListener { if (flowExecutionKey == null) { // it is an new conversation, generate a brand new key flowExecutionKey = repository.generateKey(flowExecution); - } else { + } + else { // it is an existing conversaiton, use same conversation id, // generate a new continuation id - flowExecutionKey = repository.getNextKey(flowExecution, - flowExecutionKey); + flowExecutionKey = repository.getNextKey(flowExecution, flowExecutionKey); } holder.setFlowExecutionKey(flowExecutionKey); } } /** - * Utility method needed needed only because we can not rely on JSF - * RequestMap supporting Map's putAll method. Tries putAll, falls back to - * individual adds + * Utility method needed needed only because we can not rely on JSF RequestMap supporting Map's putAll method. Tries + * putAll, falls back to individual adds * - * @param targetMap - * the target map to add the model data to - * @param map - * the model data to add to the target map + * @param targetMap the target map to add the model data to + * @param map the model data to add to the target map */ private void putInto(Map targetMap, Map map) { try { targetMap.putAll(map); - } catch (UnsupportedOperationException e) { + } + catch (UnsupportedOperationException e) { // work around nasty MyFaces bug where it's RequestMap doesn't // support putAll remove after it's fixed in MyFaces Iterator it = map.entrySet().iterator(); @@ -561,13 +487,12 @@ public class FlowPhaseListener implements PhaseListener { private void sendRedirect(String url, JsfExternalContext context) { try { - url = context.getFacesContext().getExternalContext() - .encodeResourceURL(url); + url = context.getFacesContext().getExternalContext().encodeResourceURL(url); context.getFacesContext().getExternalContext().redirect(url); context.getFacesContext().responseComplete(); - } catch (IOException e) { - throw new IllegalArgumentException("Could not send redirect to " - + url); + } + catch (IOException e) { + throw new IllegalArgumentException("Could not send redirect to " + url); } } @@ -584,8 +509,7 @@ public class FlowPhaseListener implements PhaseListener { } /** - * Standard default view id resolver which uses the web flow view name as - * the jsf view id + * Standard default view id resolver which uses the web flow view name as the jsf view id */ public static class DefaultViewIdMapper implements ViewIdMapper { public String mapViewId(String viewName) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/ViewIdMapper.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/ViewIdMapper.java index f3fbf245..22061858 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/ViewIdMapper.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/ViewIdMapper.java @@ -15,16 +15,24 @@ */ package org.springframework.webflow.executor.jsf; +import javax.faces.application.ViewHandler; + /** - * Interface to be implemented by objects that can map Web Flow view names to - * JSF view identifiers. + * Interface to be implemented by objects that can map Web Flow view names to JSF view identifiers. JSF view identifiers + * are used to determine if the current view has changed and to create views by delegating to the application's + * {@link ViewHandler}. + * + * A view handler typically treats a JSF view id as the physical location of a view template encapsulating a page + * layout. The JSF view id normally specifies the physical location of the view template minus a suffix. View handlers + * typically replace the suffix of any view id with their own default suffix (e.g. ".jsp" or ".xhtml") and then try to + * locate a physical template view. * * @author Colin Sampaleanu */ public interface ViewIdMapper { /** - * Map the given Web Flow view name to a JSF view id. + * Map the given Spring Web Flow view name to a JSF view identifier. * @param viewName name of the view to map * @return the corresponding JSF view id */