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 6b114119..2ad14d17 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 @@ -18,26 +18,13 @@ package org.springframework.webflow.executor.jsf; import javax.faces.application.NavigationHandler; import javax.faces.context.FacesContext; -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.webflow.context.ExternalContext; -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.registry.FlowDefinitionLocator; -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.FlowExecutionFactory; import org.springframework.webflow.execution.ViewSelection; -import org.springframework.webflow.executor.RequestParameterInputMapper; -import org.springframework.webflow.executor.support.FlowExecutorArgumentExtractor; /** * An implementation of a JSF NavigationHandler that provides integration with Spring Web Flow. - * Responsible for delegating to Spring Web Flow to launch and resume flow executions, treating JSF action outcomes + * Responsible for delegating to Spring Web Flow to resume flow executions by treating JSF action outcomes * (like a command button click) as web flow events. - * + *

* This class delegates to the standard NavigationHandler implementation when a navigation request does not pertain to a * flow execution. *

@@ -46,159 +33,43 @@ import org.springframework.webflow.executor.support.FlowExecutorArgumentExtracto *

* If a flow execution has been restored in the current request: *

- *

*

- * If a flow execution has not been restored in the current request: - *

- *

- * 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 org.springframework.web.jsf.DelegatingNavigationHandlerProxy} when you need - * to customize a FlowNavigationHandler instance. + * If a flow execution has not been restored in the current request simply delegate to the next NavigationHandler in + * the chain and return. * * @author Craig McClanahan * @author Colin Sampaleanu * @author Keith Donald */ -public class FlowNavigationHandler extends DecoratingNavigationHandler { +public class FlowNavigationHandler extends NavigationHandler { /** - * Logger, usable by subclasses. + * The standard navigation handler to delegate to when this one does not apply. */ - protected final Log logger = LogFactory.getLog(getClass()); - + private NavigationHandler delegateHandler; + /** - * A helper for extracting parameters needed by this flow navigation handler. + * Create a new {@link FlowNavigationHandler} wrapping the specified standard navigation handler implementation. + * @param delegateHandler the standard NavigationHandler this class decorates */ - private FlowExecutorArgumentExtractor argumentExtractor = new FlowNavigationHandlerArgumentExtractor(); - - /** - * 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. - *

- * The default implementation simply exposes all request parameters as flow execution input attributes. May be null. - */ - private AttributeMapper inputMapper = new RequestParameterInputMapper(); - - /** - * Create a new {@link FlowNavigationHandler} using the default constructor. - */ - public FlowNavigationHandler() { - super(); + public FlowNavigationHandler(NavigationHandler delegateHandler) { + this.delegateHandler = delegateHandler; } - /** - * Create a new {@link FlowNavigationHandler}, wrapping the specified standard navigation handler implementation. - * @param originalNavigationHandler Standard NavigationHandler we are wrapping - */ - public FlowNavigationHandler(NavigationHandler originalNavigationHandler) { - super(originalNavigationHandler); - } - - /** - * Returns the argument extractor used by this navigation handler. - */ - public FlowExecutorArgumentExtractor getArgumentExtractor() { - return argumentExtractor; - } - - /** - * Sets the argument extractor to use by this navigation handler. Call to customize how flow id and event id - * arguments are extracted. - */ - public void setArgumentExtractor(FlowExecutorArgumentExtractor argumentExtractor) { - this.argumentExtractor = argumentExtractor; - } - - /** - * Returns the configured flow execution input mapper. - */ - public AttributeMapper getInputMapper() { - return inputMapper; - } - - /** - * 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. - * @see RequestParameterInputMapper - */ - public void setInputMapper(AttributeMapper inputMapper) { - this.inputMapper = inputMapper; - } - - public void handleNavigation(FacesContext facesContext, String fromAction, String outcome, - NavigationHandler originalNavigationHandler) { - JsfExternalContext context = new JsfExternalContext(facesContext, fromAction, outcome); + public void handleNavigation(FacesContext facesContext, String fromAction, String outcome) { if (FlowExecutionHolderUtils.isFlowExecutionRestored(facesContext)) { - // the flow execution has been restored, now see if we need to signal an event against it - if (argumentExtractor.isEventIdPresent(context)) { - // a flow execution has been restored, signal an event in it - String eventId = argumentExtractor.extractEventId(context); - FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(facesContext); - ViewSelection selectedView = holder.getFlowExecution().signalEvent(eventId, context); - holder.setViewSelection(selectedView); - } + // a flow execution has been restored - signal an event against it + FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(facesContext); + JsfExternalContext context = new JsfExternalContext(facesContext, fromAction, outcome); + ViewSelection selectedView = holder.getFlowExecution().signalEvent(outcome, context); + holder.setViewSelection(selectedView); } else { - // no flow execution exists, see if we need to launch one if the flow id is present - if (argumentExtractor.isFlowIdPresent(context)) { - // a flow execution launch has been requested, start it - String flowId = argumentExtractor.extractFlowId(context); - 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); - holder.setViewSelection(selectedView); - } - else { - // no flow id submitted, proceed with std navigation - originalNavigationHandler.handleNavigation(facesContext, fromAction, outcome); - } + // no flow execution is restored, proceed with std navigation + delegateHandler.handleNavigation(facesContext, fromAction, outcome); } } - - /** - * 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 - * @return the input map, or null if no input - */ - protected MutableAttributeMap createInput(ExternalContext context) { - if (inputMapper != null) { - MutableAttributeMap inputMap = new LocalAttributeMap(); - inputMapper.map(context, inputMap, null); - return inputMap; - } - else { - return null; - } - } - - // helpers - - private FlowDefinitionLocator getLocator(JsfExternalContext context) { - return FlowFacesUtils.getDefinitionLocator(context.getFacesContext()); - } - - private FlowExecutionFactory getFactory(JsfExternalContext context) { - return FlowFacesUtils.getExecutionFactory(context.getFacesContext()); - } } \ No newline at end of file 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 deleted file mode 100644 index faa3b707..00000000 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowNavigationHandlerArgumentExtractor.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2004-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.webflow.executor.jsf; - -import org.springframework.util.StringUtils; -import org.springframework.webflow.context.ExternalContext; -import org.springframework.webflow.executor.support.FlowExecutorArgumentExtractionException; -import org.springframework.webflow.executor.support.FlowExecutorArgumentExtractor; - -/** - * An {@link FlowExecutorArgumentExtractor} that is aware of JSF outcomes that communicate requests to launch flow - * executions and signal event in existing flow executions. Designed to be used wih a {@link FlowNavigationHandler}. - * - * Note: this class only implements flow id and event id extraction methods. A FlowNavigationHandler is not expected to - * extract a flow execution key, as flow execution restoration is fully handled by the {@link FlowPhaseListener} and the - * JSF restore view phase. - * - * @author Keith Donald - */ -public class FlowNavigationHandlerArgumentExtractor implements FlowExecutorArgumentExtractor { - - /** - * The default prefix of a JSF outcome string that indicates a new flow should be launched. - */ - private static final String FLOW_ID_PREFIX = "flowId:"; - - /** - * The prefix for JSF outcome strings indicating a new flow should be launched. - */ - private String flowIdPrefix = FLOW_ID_PREFIX; - - /** - * Returns the configured prefix for outcome strings that indicate a new flow should be launched. - */ - public String getFlowIdPrefix() { - return flowIdPrefix; - } - - /** - * Sets the prefix of an outcome string that indicates a new flow should be launched. - */ - public void setFlowIdPrefix(String flowIdPrefix) { - this.flowIdPrefix = flowIdPrefix; - } - - public boolean isFlowIdPresent(ExternalContext context) throws FlowExecutorArgumentExtractionException { - String outcome = getOutcome(context); - if (outcome != null && outcome.startsWith(getFlowIdPrefix())) { - return true; - } - else { - return false; - } - } - - public String extractFlowId(ExternalContext context) throws FlowExecutorArgumentExtractionException { - // extract the flowId from a JSF outcome in format ${flowIdPrefix}${flowId} - String outcome = getOutcome(context); - int index = outcome.indexOf(getFlowIdPrefix()); - if (index == -1) { - throw new FlowExecutorArgumentExtractionException( - "Unable to extract flow id; make sure the JSF outcome is prefixed with '" + getFlowIdPrefix() - + "' to launch a new flow execution"); - } - String flowId = outcome.substring(getFlowIdPrefix().length()); - if (!StringUtils.hasText(flowId)) { - throw new FlowExecutorArgumentExtractionException( - "Unable to extract flow id; make sure the flow id is provided in the outcome string"); - } - return flowId; - } - - public boolean isEventIdPresent(ExternalContext context) { - return StringUtils.hasText(getOutcome(context)); - } - - public String extractEventId(ExternalContext context) throws FlowExecutorArgumentExtractionException { - // treat the action outcome string as the event id - return getOutcome(context); - } - - public boolean isFlowExecutionKeyPresent(ExternalContext context) { - throw new UnsupportedOperationException("Should not be called by a FlowNavigationHandler"); - } - - public String extractFlowExecutionKey(ExternalContext context) throws FlowExecutorArgumentExtractionException { - throw new UnsupportedOperationException("Should not be called by a FlowNavigationHandler"); - } - - // helpers - private String getOutcome(ExternalContext context) { - return ((JsfExternalContext) context).getOutcome(); - } -} \ No newline at end of file