swf-177
This commit is contained in:
@@ -20,14 +20,17 @@ import javax.faces.context.FacesContext;
|
|||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.binding.mapping.AttributeMapper;
|
||||||
import org.springframework.web.jsf.DecoratingNavigationHandler;
|
import org.springframework.web.jsf.DecoratingNavigationHandler;
|
||||||
import org.springframework.webflow.context.ExternalContext;
|
import org.springframework.webflow.context.ExternalContext;
|
||||||
|
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
||||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||||
import org.springframework.webflow.definition.FlowDefinition;
|
import org.springframework.webflow.definition.FlowDefinition;
|
||||||
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
|
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
|
||||||
import org.springframework.webflow.execution.FlowExecution;
|
import org.springframework.webflow.execution.FlowExecution;
|
||||||
import org.springframework.webflow.execution.FlowExecutionFactory;
|
import org.springframework.webflow.execution.FlowExecutionFactory;
|
||||||
import org.springframework.webflow.execution.ViewSelection;
|
import org.springframework.webflow.execution.ViewSelection;
|
||||||
|
import org.springframework.webflow.executor.RequestParameterInputMapper;
|
||||||
import org.springframework.webflow.executor.support.FlowExecutorArgumentExtractor;
|
import org.springframework.webflow.executor.support.FlowExecutorArgumentExtractor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,6 +83,21 @@ public class FlowNavigationHandler extends DecoratingNavigationHandler {
|
|||||||
*/
|
*/
|
||||||
private FlowExecutorArgumentExtractor argumentExtractor = new FlowNavigationHandlerArgumentExtractor();
|
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.
|
||||||
|
* <p>
|
||||||
|
* This allows developers to control what attributes are made available in
|
||||||
|
* the <code>inputMap</code> to new top-level flow executions. The
|
||||||
|
* starting execution may then choose to map that available input into its
|
||||||
|
* own local scope.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
* Create a new {@link FlowNavigationHandler} using the default constructor.
|
||||||
*/
|
*/
|
||||||
@@ -110,7 +128,26 @@ public class FlowNavigationHandler extends DecoratingNavigationHandler {
|
|||||||
public void setArgumentExtractor(FlowExecutorArgumentExtractor argumentExtractor) {
|
public void setArgumentExtractor(FlowExecutorArgumentExtractor argumentExtractor) {
|
||||||
this.argumentExtractor = 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.
|
||||||
|
* <p>
|
||||||
|
* 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,
|
public void handleNavigation(FacesContext facesContext, String fromAction, String outcome,
|
||||||
NavigationHandler originalNavigationHandler) {
|
NavigationHandler originalNavigationHandler) {
|
||||||
JsfExternalContext context = new JsfExternalContext(facesContext, fromAction, outcome);
|
JsfExternalContext context = new JsfExternalContext(facesContext, fromAction, outcome);
|
||||||
@@ -135,7 +172,7 @@ public class FlowNavigationHandler extends DecoratingNavigationHandler {
|
|||||||
FlowExecution flowExecution = getFactory(context).createFlowExecution(flowDefinition);
|
FlowExecution flowExecution = getFactory(context).createFlowExecution(flowDefinition);
|
||||||
FlowExecutionHolder holder = new FlowExecutionHolder(flowExecution);
|
FlowExecutionHolder holder = new FlowExecutionHolder(flowExecution);
|
||||||
FlowExecutionHolderUtils.setFlowExecutionHolder(holder, facesContext);
|
FlowExecutionHolderUtils.setFlowExecutionHolder(holder, facesContext);
|
||||||
ViewSelection selectedView = flowExecution.start(createInput(flowExecution, context), context);
|
ViewSelection selectedView = flowExecution.start(createInput(context), context);
|
||||||
holder.setViewSelection(selectedView);
|
holder.setViewSelection(selectedView);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -155,12 +192,19 @@ public class FlowNavigationHandler extends DecoratingNavigationHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method that creates the input attribute map for a newly created
|
* Factory method that creates the input attribute map for a newly created
|
||||||
* {@link FlowExecution}. TODO - add support for input mappings here
|
* {@link FlowExecution}. This implementation uses the registered input mapper,
|
||||||
* @param flowExecution the new flow execution (yet to be started)
|
* if any.
|
||||||
* @param context the external context
|
* @param context the external context
|
||||||
* @return the input map
|
* @return the input map, or null if no input
|
||||||
*/
|
*/
|
||||||
protected MutableAttributeMap createInput(FlowExecution flowExecution, ExternalContext context) {
|
protected MutableAttributeMap createInput(ExternalContext context) {
|
||||||
return null;
|
if (inputMapper != null) {
|
||||||
|
MutableAttributeMap inputMap = new LocalAttributeMap();
|
||||||
|
inputMapper.map(context, inputMap, null);
|
||||||
|
return inputMap;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,9 +28,11 @@ import javax.faces.event.PhaseListener;
|
|||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.binding.mapping.AttributeMapper;
|
||||||
import org.springframework.webflow.context.ExternalContext;
|
import org.springframework.webflow.context.ExternalContext;
|
||||||
import org.springframework.webflow.context.ExternalContextHolder;
|
import org.springframework.webflow.context.ExternalContextHolder;
|
||||||
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
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.FlowDefinition;
|
||||||
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
|
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
|
||||||
import org.springframework.webflow.execution.FlowExecution;
|
import org.springframework.webflow.execution.FlowExecution;
|
||||||
@@ -43,6 +45,7 @@ import org.springframework.webflow.execution.support.ApplicationView;
|
|||||||
import org.springframework.webflow.execution.support.ExternalRedirect;
|
import org.springframework.webflow.execution.support.ExternalRedirect;
|
||||||
import org.springframework.webflow.execution.support.FlowDefinitionRedirect;
|
import org.springframework.webflow.execution.support.FlowDefinitionRedirect;
|
||||||
import org.springframework.webflow.execution.support.FlowExecutionRedirect;
|
import org.springframework.webflow.execution.support.FlowExecutionRedirect;
|
||||||
|
import org.springframework.webflow.executor.RequestParameterInputMapper;
|
||||||
import org.springframework.webflow.executor.ResponseInstruction;
|
import org.springframework.webflow.executor.ResponseInstruction;
|
||||||
import org.springframework.webflow.executor.support.FlowExecutorArgumentHandler;
|
import org.springframework.webflow.executor.support.FlowExecutorArgumentHandler;
|
||||||
import org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler;
|
import org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler;
|
||||||
@@ -76,12 +79,27 @@ public class FlowPhaseListener implements PhaseListener {
|
|||||||
* Logger, usable by subclasses.
|
* Logger, usable by subclasses.
|
||||||
*/
|
*/
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper for handling arguments needed by this phase listener.
|
* A helper for handling arguments needed by this phase listener to resume and launch flow executions.
|
||||||
*/
|
*/
|
||||||
private FlowExecutorArgumentHandler argumentHandler = new RequestParameterFlowExecutorArgumentHandler();
|
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.
|
||||||
|
* <p>
|
||||||
|
* This allows developers to control what attributes are made available in
|
||||||
|
* the <code>inputMap</code> to new top-level flow executions. The
|
||||||
|
* starting execution may then choose to map that available input into its
|
||||||
|
* own local scope.
|
||||||
|
* <p>
|
||||||
|
* The default implementation simply exposes all request parameters as flow
|
||||||
|
* execution input attributes. May be null.
|
||||||
|
*/
|
||||||
|
private AttributeMapper inputMapper = new RequestParameterInputMapper();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves selected Web Flow view names to JSF view ids.
|
* Resolves selected Web Flow view names to JSF view ids.
|
||||||
*/
|
*/
|
||||||
@@ -101,6 +119,25 @@ public class FlowPhaseListener implements PhaseListener {
|
|||||||
this.argumentHandler = argumentHandler;
|
this.argumentHandler = argumentHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the JSF view id resolver used by this phase listener.
|
* Returns the JSF view id resolver used by this phase listener.
|
||||||
*/
|
*/
|
||||||
@@ -142,7 +179,9 @@ public class FlowPhaseListener implements PhaseListener {
|
|||||||
saveFlowExecution(getCurrentContext(), holder);
|
saveFlowExecution(getCurrentContext(), holder);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
holder.getFlowExecutionLock().unlock();
|
if (holder.getFlowExecutionLock() != null) {
|
||||||
|
holder.getFlowExecutionLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,6 +206,7 @@ public class FlowPhaseListener implements PhaseListener {
|
|||||||
FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(argumentHandler
|
FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(argumentHandler
|
||||||
.extractFlowExecutionKey(context));
|
.extractFlowExecutionKey(context));
|
||||||
FlowExecutionLock lock = repository.getLock(flowExecutionKey);
|
FlowExecutionLock lock = repository.getLock(flowExecutionKey);
|
||||||
|
lock.lock();
|
||||||
FlowExecution flowExecution = repository.getFlowExecution(flowExecutionKey);
|
FlowExecution flowExecution = repository.getFlowExecution(flowExecutionKey);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Loaded existing flow execution from repository with id '" + flowExecutionKey + "'");
|
logger.debug("Loaded existing flow execution from repository with id '" + flowExecutionKey + "'");
|
||||||
@@ -182,7 +222,7 @@ public class FlowPhaseListener implements PhaseListener {
|
|||||||
FlowExecution flowExecution = getFactory(context).createFlowExecution(flowDefinition);
|
FlowExecution flowExecution = getFactory(context).createFlowExecution(flowDefinition);
|
||||||
FlowExecutionHolder holder = new FlowExecutionHolder(flowExecution);
|
FlowExecutionHolder holder = new FlowExecutionHolder(flowExecution);
|
||||||
FlowExecutionHolderUtils.setFlowExecutionHolder(holder, facesContext);
|
FlowExecutionHolderUtils.setFlowExecutionHolder(holder, facesContext);
|
||||||
ViewSelection selectedView = flowExecution.start(createInput(flowExecution, context), context);
|
ViewSelection selectedView = flowExecution.start(createInput(context), context);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Started new flow execution");
|
logger.debug("Started new flow execution");
|
||||||
}
|
}
|
||||||
@@ -192,13 +232,20 @@ public class FlowPhaseListener implements PhaseListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method that creates the input attribute map for a newly created
|
* Factory method that creates the input attribute map for a newly created
|
||||||
* {@link FlowExecution}. TODO - add support for input mappings here
|
* {@link FlowExecution}. This implementation uses the registered input mapper,
|
||||||
* @param flowExecution the new flow execution (yet to be started)
|
* if any.
|
||||||
* @param context the external context
|
* @param context the external context
|
||||||
* @return the input map
|
* @return the input map, or null if no input
|
||||||
*/
|
*/
|
||||||
protected LocalAttributeMap createInput(FlowExecution flowExecution, ExternalContext context) {
|
protected MutableAttributeMap createInput(ExternalContext context) {
|
||||||
return null;
|
if (inputMapper != null) {
|
||||||
|
MutableAttributeMap inputMap = new LocalAttributeMap();
|
||||||
|
inputMapper.map(context, inputMap, null);
|
||||||
|
return inputMap;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void prepareResponse(final JsfExternalContext context, final FlowExecutionHolder holder) {
|
protected void prepareResponse(final JsfExternalContext context, final FlowExecutionHolder holder) {
|
||||||
|
|||||||
@@ -29,10 +29,6 @@ import org.springframework.webflow.execution.FlowExecution;
|
|||||||
/**
|
/**
|
||||||
* Custom property resolve that resolves active flow session scope properties
|
* Custom property resolve that resolves active flow session scope properties
|
||||||
* from a thread bound flow execution.
|
* from a thread bound flow execution.
|
||||||
* <p>
|
|
||||||
* TODO: this class probably needs to delegate to a strategy object pulled out
|
|
||||||
* of the appcontext, to provide ability to override and configure, as JSF
|
|
||||||
* provides no other way to customize and configure this instance.
|
|
||||||
*
|
*
|
||||||
* @author Colin Sampaleanu
|
* @author Colin Sampaleanu
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user