Brought spring-webflow code to formatting conventions
This commit is contained in:
@@ -27,13 +27,11 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.support.EventFactorySupport;
|
||||
|
||||
/**
|
||||
* Base action that provides assistance commonly needed by action
|
||||
* implementations. This includes:
|
||||
* Base action that provides assistance commonly needed by action implementations. This includes:
|
||||
* <ul>
|
||||
* <li>Implementing {@link InitializingBean} to receive an init callback
|
||||
* when deployed within a Spring bean factory.
|
||||
* <li>Exposing convenient event factory methods to create common result
|
||||
* {@link Event} objects such as "success" and "error".
|
||||
* <li>Implementing {@link InitializingBean} to receive an init callback when deployed within a Spring bean factory.
|
||||
* <li>Exposing convenient event factory methods to create common result {@link Event} objects such as "success" and
|
||||
* "error".
|
||||
* <li>A hook for inserting action pre and post execution logic.
|
||||
* </ul>
|
||||
*
|
||||
@@ -58,19 +56,16 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
try {
|
||||
initAction();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
throw new BeanInitializationException("Initialization of this Action failed: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action initializing callback, may be overriden by subclasses to perform
|
||||
* custom initialization logic.
|
||||
* Action initializing callback, may be overriden by subclasses to perform custom initialization logic.
|
||||
* <p>
|
||||
* Keep in mind that this hook will only be invoked when this action is
|
||||
* deployed in a Spring application context since it uses the Spring
|
||||
* {@link InitializingBean} mechanism to trigger action initialisation.
|
||||
* Keep in mind that this hook will only be invoked when this action is deployed in a Spring application context
|
||||
* since it uses the Spring {@link InitializingBean} mechanism to trigger action initialisation.
|
||||
*/
|
||||
protected void initAction() throws Exception {
|
||||
}
|
||||
@@ -83,8 +78,7 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "success" result event with the provided result object as a
|
||||
* parameter.
|
||||
* Returns a "success" result event with the provided result object as a parameter.
|
||||
* @param result the action success result
|
||||
*/
|
||||
protected Event success(Object result) {
|
||||
@@ -100,8 +94,7 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
|
||||
/**
|
||||
* Returns an "error" result event caused by the provided exception.
|
||||
* @param e the exception that caused the error event, to be configured as
|
||||
* an event attribute
|
||||
* @param e the exception that caused the error event, to be configured as an event attribute
|
||||
*/
|
||||
protected Event error(Exception e) {
|
||||
return getEventFactorySupport().error(this, e);
|
||||
@@ -131,8 +124,8 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a result event for this action with the specified identifier.
|
||||
* Typically called as part of return, for example:
|
||||
* Returns a result event for this action with the specified identifier. Typically called as part of return, for
|
||||
* example:
|
||||
*
|
||||
* <pre>
|
||||
* protected Event doExecute(RequestContext context) {
|
||||
@@ -145,8 +138,7 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Consider calling the error() or success() factory methods for returning
|
||||
* common results.
|
||||
* Consider calling the error() or success() factory methods for returning common results.
|
||||
* @param eventId the result event identifier
|
||||
* @return the action result event
|
||||
*/
|
||||
@@ -155,9 +147,8 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a result event for this action with the specified identifier and
|
||||
* the specified set of attributes. Typically called as part of return, for
|
||||
* example:
|
||||
* Returns a result event for this action with the specified identifier and the specified set of attributes.
|
||||
* Typically called as part of return, for example:
|
||||
*
|
||||
* <pre>
|
||||
* protected Event doExecute(RequestContext context) {
|
||||
@@ -172,8 +163,7 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Consider calling the error() or success() factory methods for returning
|
||||
* common results.
|
||||
* Consider calling the error() or success() factory methods for returning common results.
|
||||
* @param eventId the result event identifier
|
||||
* @param resultAttributes the event attributes
|
||||
* @return the action result event
|
||||
@@ -183,8 +173,7 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a result event for this action with the specified identifier and
|
||||
* a single attribute.
|
||||
* Returns a result event for this action with the specified identifier and a single attribute.
|
||||
* @param eventId the result id
|
||||
* @param resultAttributeName the attribute name
|
||||
* @param resultAttributeValue the attribute value
|
||||
@@ -203,27 +192,25 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
result = doExecute(context);
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (result != null) {
|
||||
logger.debug("Action '" + getActionNameForLogging() + "' completed execution; result is '" + result.getId() + "'");
|
||||
}
|
||||
else {
|
||||
logger.debug("Action '" + getActionNameForLogging() + "' completed execution; result is '"
|
||||
+ result.getId() + "'");
|
||||
} else {
|
||||
logger.debug("Action '" + getActionNameForLogging() + "' completed execution; result is [null]");
|
||||
}
|
||||
}
|
||||
doPostExecute(context);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Action execution disallowed; pre-execution result is '" + result.getId() + "'");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Internal helper to return the name of this action for logging
|
||||
* purposes. Defaults to the short class name.
|
||||
* Internal helper to return the name of this action for logging purposes. Defaults to the short class name.
|
||||
* @see ClassUtils#getShortName(java.lang.Class)
|
||||
*/
|
||||
protected String getActionNameForLogging() {
|
||||
@@ -231,48 +218,37 @@ public abstract class AbstractAction implements Action, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-action-execution hook, subclasses may override. If this method
|
||||
* returns a non-<code>null</code> event, the <code>doExecute()</code>
|
||||
* method will <b>not</b> be called and the returned event will be used to
|
||||
* select a transition to trigger in the calling action state. If this
|
||||
* method returns <code>null</code>, <code>doExecute()</code> will be
|
||||
* called to obtain an action result event.
|
||||
* Pre-action-execution hook, subclasses may override. If this method returns a non-<code>null</code> event, the
|
||||
* <code>doExecute()</code> method will <b>not</b> be called and the returned event will be used to select a
|
||||
* transition to trigger in the calling action state. If this method returns <code>null</code>,
|
||||
* <code>doExecute()</code> will be called to obtain an action result event.
|
||||
* <p>
|
||||
* This implementation just returns <code>null</code>.
|
||||
* @param context the action execution context, for accessing and setting
|
||||
* data in "flow scope" or "request scope"
|
||||
* @return the non-<code>null</code> action result, in which case the
|
||||
* <code>doExecute()</code> will not be called, or <code>null</code> if
|
||||
* the <code>doExecute()</code> method should be called to obtain the
|
||||
* action result
|
||||
* @throws Exception an <b>unrecoverable</b> exception occured, either
|
||||
* checked or unchecked
|
||||
* @param context the action execution context, for accessing and setting data in "flow scope" or "request scope"
|
||||
* @return the non-<code>null</code> action result, in which case the <code>doExecute()</code> will not be
|
||||
* called, or <code>null</code> if the <code>doExecute()</code> method should be called to obtain the action
|
||||
* result
|
||||
* @throws Exception an <b>unrecoverable</b> exception occured, either checked or unchecked
|
||||
*/
|
||||
protected Event doPreExecute(RequestContext context) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template hook method subclasses should override to encapsulate their
|
||||
* specific action execution logic.
|
||||
* @param context the action execution context, for accessing and setting
|
||||
* data in "flow scope" or "request scope"
|
||||
* Template hook method subclasses should override to encapsulate their specific action execution logic.
|
||||
* @param context the action execution context, for accessing and setting data in "flow scope" or "request scope"
|
||||
* @return the action result event
|
||||
* @throws Exception an <b>unrecoverable</b> exception occured, either
|
||||
* checked or unchecked
|
||||
* @throws Exception an <b>unrecoverable</b> exception occured, either checked or unchecked
|
||||
*/
|
||||
protected abstract Event doExecute(RequestContext context) throws Exception;
|
||||
|
||||
/**
|
||||
* Post-action execution hook, subclasses may override. Will only be called
|
||||
* if <code>doExecute()</code> was called, e.g. when <code>doPreExecute()</code>
|
||||
* returned <code>null</code>.
|
||||
* Post-action execution hook, subclasses may override. Will only be called if <code>doExecute()</code> was
|
||||
* called, e.g. when <code>doPreExecute()</code> returned <code>null</code>.
|
||||
* <p>
|
||||
* This implementation does nothing.
|
||||
* @param context the action execution context, for accessing and setting
|
||||
* data in "flow scope" or "request scope"
|
||||
* @throws Exception an <b>unrecoverable</b> exception occured, either
|
||||
* checked or unchecked
|
||||
* @param context the action execution context, for accessing and setting data in "flow scope" or "request scope"
|
||||
* @throws Exception an <b>unrecoverable</b> exception occured, either checked or unchecked
|
||||
*/
|
||||
protected void doPostExecute(RequestContext context) throws Exception {
|
||||
}
|
||||
|
||||
@@ -25,12 +25,11 @@ import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Base class for actions that delegate to methods on beans (POJOs - Plain Old
|
||||
* Java Objects). Acts as an adapter that adapts an {@link Object} method to the
|
||||
* Spring Web Flow {@link Action} contract.
|
||||
* Base class for actions that delegate to methods on beans (POJOs - Plain Old Java Objects). Acts as an adapter that
|
||||
* adapts an {@link Object} method to the Spring Web Flow {@link Action} contract.
|
||||
* <p>
|
||||
* Subclasses are required to implement the {@link #getBean(RequestContext)}
|
||||
* method, returning the bean on which a method should be invoked.
|
||||
* Subclasses are required to implement the {@link #getBean(RequestContext)} method, returning the bean on which a
|
||||
* method should be invoked.
|
||||
*
|
||||
* @see BeanInvokingActionFactory
|
||||
*
|
||||
@@ -39,21 +38,20 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
public abstract class AbstractBeanInvokingAction extends AbstractAction {
|
||||
|
||||
/**
|
||||
* The signature of the method to invoke on the target bean, capable of
|
||||
* resolving the method when used with a {@link MethodInvoker}. Required.
|
||||
* The signature of the method to invoke on the target bean, capable of resolving the method when used with a
|
||||
* {@link MethodInvoker}. Required.
|
||||
*/
|
||||
private MethodSignature methodSignature;
|
||||
|
||||
/**
|
||||
* The method invoker that performs the action->bean method binding,
|
||||
* accepting a {@link MethodSignature} and
|
||||
* The method invoker that performs the action->bean method binding, accepting a {@link MethodSignature} and
|
||||
* {@link #getBean(RequestContext) target bean} instance.
|
||||
*/
|
||||
private MethodInvoker methodInvoker = new MethodInvoker();
|
||||
|
||||
/**
|
||||
* The specification (configuration) for how bean method return values
|
||||
* should be exposed to an executing flow that invokes this action.
|
||||
* The specification (configuration) for how bean method return values should be exposed to an executing flow that
|
||||
* invokes this action.
|
||||
*/
|
||||
private ActionResultExposer methodResultExposer;
|
||||
|
||||
@@ -79,17 +77,16 @@ public abstract class AbstractBeanInvokingAction extends AbstractAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration for how bean method return values should be
|
||||
* exposed to an executing flow that invokes this action.
|
||||
* Returns the configuration for how bean method return values should be exposed to an executing flow that invokes
|
||||
* this action.
|
||||
*/
|
||||
public ActionResultExposer getMethodResultExposer() {
|
||||
return methodResultExposer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures how bean method return values should be exposed to an
|
||||
* executing flow that invokes this action. This is optional. By default the
|
||||
* bean method return values do not get exposed to the executing flow.
|
||||
* Configures how bean method return values should be exposed to an executing flow that invokes this action. This is
|
||||
* optional. By default the bean method return values do not get exposed to the executing flow.
|
||||
*/
|
||||
public void setMethodResultExposer(ActionResultExposer methodResultExposer) {
|
||||
this.methodResultExposer = methodResultExposer;
|
||||
@@ -103,17 +100,15 @@ public abstract class AbstractBeanInvokingAction extends AbstractAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean return value->event adaption strategy. Defaults to
|
||||
* {@link SuccessEventFactory}, so all bean method return values will be
|
||||
* interpreted as "success".
|
||||
* Set the bean return value->event adaption strategy. Defaults to {@link SuccessEventFactory}, so all bean
|
||||
* method return values will be interpreted as "success".
|
||||
*/
|
||||
public void setResultEventFactory(ResultEventFactory resultEventFactory) {
|
||||
this.resultEventFactory = resultEventFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the conversion service to perform type conversion of event parameters
|
||||
* to method arguments as neccessary.
|
||||
* Set the conversion service to perform type conversion of event parameters to method arguments as neccessary.
|
||||
* Defaults to {@link DefaultConversionService}.
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
@@ -139,8 +134,7 @@ public abstract class AbstractBeanInvokingAction extends AbstractAction {
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Retrieves the bean to invoke a method on. Subclasses need to implement
|
||||
* this method.
|
||||
* Retrieves the bean to invoke a method on. Subclasses need to implement this method.
|
||||
* @param context the flow execution request context
|
||||
* @return the bean on which to invoke methods
|
||||
* @throws Exception when the bean cannot be retreived
|
||||
|
||||
@@ -23,8 +23,8 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ScopeType;
|
||||
|
||||
/**
|
||||
* Specifies how an action result value should be exposed to an executing flow.
|
||||
* The return value is exposed as an attribute in a configured scope.
|
||||
* Specifies how an action result value should be exposed to an executing flow. The return value is exposed as an
|
||||
* attribute in a configured scope.
|
||||
*
|
||||
* @see EvaluateAction
|
||||
* @see AbstractBeanInvokingAction
|
||||
@@ -70,8 +70,7 @@ public class ActionResultExposer implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose given bean method return value in given flow execution request
|
||||
* context.
|
||||
* Expose given bean method return value in given flow execution request context.
|
||||
* @param result the return value
|
||||
* @param context the request context
|
||||
*/
|
||||
|
||||
@@ -22,15 +22,12 @@ import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Action that executes an attribute mapper to map information in the request
|
||||
* context. Both the source and the target of the mapping will be the request
|
||||
* context. This allows for maximum flexibility when defining attribute mapping
|
||||
* Action that executes an attribute mapper to map information in the request context. Both the source and the target of
|
||||
* the mapping will be the request context. This allows for maximum flexibility when defining attribute mapping
|
||||
* expressions (e.g. "${flowScope.someAttribute}").
|
||||
* <p>
|
||||
* This action always returns the
|
||||
* {@link org.springframework.webflow.action.AbstractAction#success() success}
|
||||
* event. If something goes wrong while executing the mapping, an exception
|
||||
* is thrown.
|
||||
* This action always returns the {@link org.springframework.webflow.action.AbstractAction#success() success} event. If
|
||||
* something goes wrong while executing the mapping, an exception is thrown.
|
||||
*
|
||||
* @see org.springframework.binding.mapping.AttributeMapper
|
||||
* @see org.springframework.webflow.execution.RequestContext
|
||||
@@ -46,8 +43,8 @@ public class AttributeMapperAction extends AbstractAction {
|
||||
private AttributeMapper attributeMapper;
|
||||
|
||||
/**
|
||||
* Creates a new attribute mapper action that delegates to the configured
|
||||
* attribute mapper to complete the mapping process.
|
||||
* Creates a new attribute mapper action that delegates to the configured attribute mapper to complete the mapping
|
||||
* process.
|
||||
* @param attributeMapper the mapper
|
||||
*/
|
||||
public AttributeMapperAction(AttributeMapper attributeMapper) {
|
||||
@@ -62,9 +59,8 @@ public class AttributeMapperAction extends AbstractAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a context containing extra data available during attribute mapping.
|
||||
* The default implementation just returns null. Subclasses can
|
||||
* override this if necessary.
|
||||
* Returns a context containing extra data available during attribute mapping. The default implementation just
|
||||
* returns null. Subclasses can override this if necessary.
|
||||
*/
|
||||
protected MappingContext getMappingContext(RequestContext context) {
|
||||
return null;
|
||||
|
||||
@@ -23,14 +23,11 @@ import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.execution.Action;
|
||||
|
||||
/**
|
||||
* A helper factory for {@link Action} instances that invoke methods on beans
|
||||
* managed in a Spring bean factory.
|
||||
* A helper factory for {@link Action} instances that invoke methods on beans managed in a Spring bean factory.
|
||||
* <p>
|
||||
* This factory encapsulates the logic required to take an arbitrary
|
||||
* <code>java.lang.Object</code> from a Spring bean factory and adapt a method
|
||||
* on it to the {@link Action} interface. If the bean you want to use is not
|
||||
* managed in a Spring bean factory, consider subclassing
|
||||
* {@link AbstractBeanInvokingAction} and using it directly.
|
||||
* This factory encapsulates the logic required to take an arbitrary <code>java.lang.Object</code> from a Spring bean
|
||||
* factory and adapt a method on it to the {@link Action} interface. If the bean you want to use is not managed in a
|
||||
* Spring bean factory, consider subclassing {@link AbstractBeanInvokingAction} and using it directly.
|
||||
*
|
||||
* @see AbstractBeanInvokingAction
|
||||
*
|
||||
@@ -39,43 +36,36 @@ import org.springframework.webflow.execution.Action;
|
||||
public class BeanInvokingActionFactory {
|
||||
|
||||
/**
|
||||
* Determines which result event factory should be used for each bean
|
||||
* invoking action created by this factory.
|
||||
* Determines which result event factory should be used for each bean invoking action created by this factory.
|
||||
*/
|
||||
private ResultEventFactorySelector resultEventFactorySelector = new ResultEventFactorySelector();
|
||||
|
||||
/**
|
||||
* Returns the strategy for calculating the result event factory to
|
||||
* configure for each bean invoking action created by this factory.
|
||||
* Returns the strategy for calculating the result event factory to configure for each bean invoking action created
|
||||
* by this factory.
|
||||
*/
|
||||
public ResultEventFactorySelector getResultEventFactorySelector() {
|
||||
return resultEventFactorySelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy to calculate the result event factory to configure for
|
||||
* each bean invoking action created by this factory.
|
||||
* Sets the strategy to calculate the result event factory to configure for each bean invoking action created by
|
||||
* this factory.
|
||||
*/
|
||||
public void setResultEventFactorySelector(ResultEventFactorySelector resultEventFactorySelector) {
|
||||
this.resultEventFactorySelector = resultEventFactorySelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that creates a bean invoking action, an adapter that
|
||||
* adapts a method on an abitrary {@link Object} to the {@link Action}
|
||||
* interface. This method is an atomic operation that returns a fully
|
||||
* initialized Action. It encapsulates the selection of the action
|
||||
* implementation as well as the action assembly.
|
||||
* Factory method that creates a bean invoking action, an adapter that adapts a method on an abitrary {@link Object}
|
||||
* to the {@link Action} interface. This method is an atomic operation that returns a fully initialized Action. It
|
||||
* encapsulates the selection of the action implementation as well as the action assembly.
|
||||
* @param beanId the id of the bean to be adapted to an Action instance
|
||||
* @param beanFactory the bean factory where the bean is managed
|
||||
* @param methodSignature the method to invoke on the bean when the action
|
||||
* is executed (required)
|
||||
* @param resultExposer the specification for what to do with the method
|
||||
* return value (optional)
|
||||
* @param conversionService the conversion service to be used to convert
|
||||
* method parameters (optional)
|
||||
* @param attributes attributes that may be used to affect the bean invoking
|
||||
* action's construction
|
||||
* @param methodSignature the method to invoke on the bean when the action is executed (required)
|
||||
* @param resultExposer the specification for what to do with the method return value (optional)
|
||||
* @param conversionService the conversion service to be used to convert method parameters (optional)
|
||||
* @param attributes attributes that may be used to affect the bean invoking action's construction
|
||||
* @return the fully configured bean invoking action instance
|
||||
*/
|
||||
public Action createBeanInvokingAction(String beanId, BeanFactory beanFactory, MethodSignature methodSignature,
|
||||
|
||||
@@ -29,14 +29,12 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
/**
|
||||
* An action that will execute an ordered chain of other actions when executed.
|
||||
* <p>
|
||||
* The event id of the last not-null result returned by the executed actions
|
||||
* will be used as the result event id of the composite action. Lacking that,
|
||||
* the action will return the "success" event.
|
||||
* The event id of the last not-null result returned by the executed actions will be used as the result event id of the
|
||||
* composite action. Lacking that, the action will return the "success" event.
|
||||
* <p>
|
||||
* The resulting event will have an "actionResults" event attribute
|
||||
* with a list of all events returned by the executed actions, including the null
|
||||
* events. This allows you to relate an executed action and its result event by
|
||||
* their index in the list.
|
||||
* The resulting event will have an "actionResults" event attribute with a list of all events returned by the executed
|
||||
* actions, including the null events. This allows you to relate an executed action and its result event by their index
|
||||
* in the list.
|
||||
* <p>
|
||||
* This is the classic GoF composite design pattern.
|
||||
*
|
||||
@@ -45,8 +43,8 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
public class CompositeAction extends AbstractAction {
|
||||
|
||||
/**
|
||||
* The resulting event whill have an attribute of this name which holds a
|
||||
* list of all events returned by the executed actions. ("actionResults")
|
||||
* The resulting event whill have an attribute of this name which holds a list of all events returned by the
|
||||
* executed actions. ("actionResults")
|
||||
*/
|
||||
public static final String ACTION_RESULTS_ATTRIBUTE_NAME = "actionResults";
|
||||
|
||||
@@ -85,9 +83,8 @@ public class CompositeAction extends AbstractAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stop on error flag. This determines whether or not execution
|
||||
* should stop with the first action that returns an error event. In the
|
||||
* error case, the composite action will also return the "error" event.
|
||||
* Sets the stop on error flag. This determines whether or not execution should stop with the first action that
|
||||
* returns an error event. In the error case, the composite action will also return the "error" event.
|
||||
*/
|
||||
public void setStopOnError(boolean stopOnError) {
|
||||
this.stopOnError = stopOnError;
|
||||
|
||||
@@ -19,13 +19,10 @@ import org.springframework.webflow.action.MultiAction.MethodResolver;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Default method resolver used by the MultiAction class. It uses the following
|
||||
* algorithm to calculate a method name:
|
||||
* Default method resolver used by the MultiAction class. It uses the following algorithm to calculate a method name:
|
||||
* <ol>
|
||||
* <li>If the currently executing action has a "method" property defined, use
|
||||
* the value as method name.</li>
|
||||
* <li>Else use the name of the current state of the flow execution as a method
|
||||
* name.</li>
|
||||
* <li>If the currently executing action has a "method" property defined, use the value as method name.</li>
|
||||
* <li>Else use the name of the current state of the flow execution as a method name.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @see org.springframework.webflow.action.MultiAction
|
||||
@@ -42,8 +39,7 @@ public class DefaultMultiActionMethodResolver implements MethodResolver {
|
||||
if (context.getCurrentState() != null) {
|
||||
// default to the state id
|
||||
method = context.getCurrentState().getId();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new IllegalStateException("Unable to resolve action method; no 'method' context attribute set");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
/**
|
||||
* An action that evaluates an expression and optionally exposes its result.
|
||||
* <p>
|
||||
* Delegates to a helper {@link ResultEventFactorySelector} strategy to determine how
|
||||
* to map the evaluation result to an action outcome {@link Event}.
|
||||
* Delegates to a helper {@link ResultEventFactorySelector} strategy to determine how to map the evaluation result to an
|
||||
* action outcome {@link Event}.
|
||||
*
|
||||
* @see Expression
|
||||
* @see ActionResultExposer
|
||||
@@ -46,8 +46,7 @@ public class EvaluateAction extends AbstractAction {
|
||||
private ActionResultExposer evaluationResultExposer;
|
||||
|
||||
/**
|
||||
* The selector for the factory that will create the action result event
|
||||
* callers can respond to.
|
||||
* The selector for the factory that will create the action result event callers can respond to.
|
||||
*/
|
||||
private ResultEventFactorySelector resultEventFactorySelector = new ResultEventFactorySelector();
|
||||
|
||||
@@ -62,8 +61,7 @@ public class EvaluateAction extends AbstractAction {
|
||||
/**
|
||||
* Create a new evaluate action.
|
||||
* @param expression the expression to evaluate
|
||||
* @param evaluationResultExposer the strategy for how the expression result
|
||||
* will be exposed to the flow
|
||||
* @param evaluationResultExposer the strategy for how the expression result will be exposed to the flow
|
||||
*/
|
||||
public EvaluateAction(Expression expression, ActionResultExposer evaluationResultExposer) {
|
||||
Assert.notNull(expression, "The expression this action should evaluate is required");
|
||||
@@ -80,8 +78,8 @@ public class EvaluateAction extends AbstractAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method subclasses may override to customize the expressin
|
||||
* evaluation context. This implementation returns null.
|
||||
* Template method subclasses may override to customize the expressin evaluation context. This implementation
|
||||
* returns null.
|
||||
* @param context the request context
|
||||
* @return the evaluation context
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,15 +21,13 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ScopeType;
|
||||
|
||||
/**
|
||||
* Convenience helper that encapsulates logic on how to retrieve and expose form
|
||||
* objects and associated errors to and from a flow execution request context.
|
||||
* Convenience helper that encapsulates logic on how to retrieve and expose form objects and associated errors to and
|
||||
* from a flow execution request context.
|
||||
* <p>
|
||||
* <b>Note</b>: The form object available under the well known attribute name
|
||||
* {@link #CURRENT_FORM_OBJECT_ATTRIBUTE} will be the last ("current") form
|
||||
* object set in the request context. The same is true for the associated errors
|
||||
* object. This implies that special care should be taken when accessing the
|
||||
* form object using this alias if there are multiple form objects available in
|
||||
* the flow execution request context!
|
||||
* <b>Note</b>: The form object available under the well known attribute name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}
|
||||
* will be the last ("current") form object set in the request context. The same is true for the associated errors
|
||||
* object. This implies that special care should be taken when accessing the form object using this alias if there are
|
||||
* multiple form objects available in the flow execution request context!
|
||||
*
|
||||
* @see org.springframework.webflow.execution.RequestContext
|
||||
* @see org.springframework.validation.Errors
|
||||
@@ -40,15 +38,14 @@ import org.springframework.webflow.execution.ScopeType;
|
||||
public class FormObjectAccessor {
|
||||
|
||||
/**
|
||||
* The form object instance is aliased under this attribute name in the flow
|
||||
* context by the default form setup and bind and validate actions.
|
||||
* The form object instance is aliased under this attribute name in the flow context by the default form setup and
|
||||
* bind and validate actions.
|
||||
* <p>
|
||||
* Note that if you would have multiple form objects in the request context,
|
||||
* the last one that was used would be available using this alias!
|
||||
* Note that if you would have multiple form objects in the request context, the last one that was used would be
|
||||
* available using this alias!
|
||||
* <p>
|
||||
* We need to keep track of the 'current form object' using this attribute
|
||||
* to be able to deal with the limitations of some clients that can only
|
||||
* deal with a single form backing object, e.g. Struts when using the Struts
|
||||
* We need to keep track of the 'current form object' using this attribute to be able to deal with the limitations
|
||||
* of some clients that can only deal with a single form backing object, e.g. Struts when using the Struts
|
||||
* FlowAction.
|
||||
*/
|
||||
private static final String CURRENT_FORM_OBJECT_ATTRIBUTE = "currentFormObject";
|
||||
@@ -56,9 +53,9 @@ public class FormObjectAccessor {
|
||||
/**
|
||||
* The errors prefix.
|
||||
*/
|
||||
//use deprecated API to remain compatible with Spring 1.2.x
|
||||
// use deprecated API to remain compatible with Spring 1.2.x
|
||||
private static final String ERRORS_PREFIX = BindException.ERROR_KEY_PREFIX;
|
||||
|
||||
|
||||
/**
|
||||
* The wrapped request context.
|
||||
*/
|
||||
@@ -79,7 +76,7 @@ public class FormObjectAccessor {
|
||||
public static String getCurrentFormObjectName() {
|
||||
return CURRENT_FORM_OBJECT_ATTRIBUTE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current form object errors attribute name.
|
||||
* @return the current form object errors attribute name
|
||||
@@ -89,8 +86,8 @@ public class FormObjectAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form object from the context, using the well-known attribute
|
||||
* name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}. Will try all scopes.
|
||||
* Gets the form object from the context, using the well-known attribute name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}.
|
||||
* Will try all scopes.
|
||||
* @return the form object, or null if not found
|
||||
*/
|
||||
public Object getCurrentFormObject() {
|
||||
@@ -110,8 +107,7 @@ public class FormObjectAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form object from the context, using the well-known attribute
|
||||
* name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}.
|
||||
* Gets the form object from the context, using the well-known attribute name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}.
|
||||
* @param scopeType the scope to obtain the form object from
|
||||
* @return the form object, or null if not found
|
||||
*/
|
||||
@@ -120,13 +116,13 @@ public class FormObjectAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose given form object using the well known alias
|
||||
* {@link #CURRENT_FORM_OBJECT_ATTRIBUTE} in the specified scope.
|
||||
* Expose given form object using the well known alias {@link #CURRENT_FORM_OBJECT_ATTRIBUTE} in the specified
|
||||
* scope.
|
||||
* @param formObject the form object
|
||||
* @param scopeType the scope in which to expose the form object
|
||||
*/
|
||||
public void setCurrentFormObject(Object formObject, ScopeType scopeType) {
|
||||
//don't call setFormObject since that would cause infinite recursion!
|
||||
// don't call setFormObject since that would cause infinite recursion!
|
||||
scopeType.getScope(context).put(getCurrentFormObjectName(), formObject);
|
||||
}
|
||||
|
||||
@@ -143,8 +139,7 @@ public class FormObjectAccessor {
|
||||
/**
|
||||
* Gets the form object from the context, using the specified name.
|
||||
* @param formObjectName the name of the form in the context
|
||||
* @param formObjectClass the class of the form object, which will be
|
||||
* verified
|
||||
* @param formObjectClass the class of the form object, which will be verified
|
||||
* @param scopeType the scope to obtain the form object from
|
||||
* @return the form object, or null if not found
|
||||
*/
|
||||
@@ -153,8 +148,8 @@ public class FormObjectAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose given form object using given name in specified scope. Given
|
||||
* object will become the <i>current</i> form object.
|
||||
* Expose given form object using given name in specified scope. Given object will become the <i>current</i> form
|
||||
* object.
|
||||
* @param formObject the form object
|
||||
* @param formObjectName the name of the form object
|
||||
* @param scopeType the scope in which to expose the form object
|
||||
@@ -165,9 +160,8 @@ public class FormObjectAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form object <code>Errors</code> tracker from the context,
|
||||
* using the form object name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}. This
|
||||
* method will search all scopes.
|
||||
* Gets the form object <code>Errors</code> tracker from the context, using the form object name
|
||||
* {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}. This method will search all scopes.
|
||||
* @return the form object Errors tracker, or null if not found
|
||||
*/
|
||||
public Errors getCurrentFormErrors() {
|
||||
@@ -187,8 +181,8 @@ public class FormObjectAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form object <code>Errors</code> tracker from the context,
|
||||
* using the form object name {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}.
|
||||
* Gets the form object <code>Errors</code> tracker from the context, using the form object name
|
||||
* {@link #CURRENT_FORM_OBJECT_ATTRIBUTE}.
|
||||
* @param scopeType the scope to obtain the errors from
|
||||
* @return the form object Errors tracker, or null if not found
|
||||
*/
|
||||
@@ -197,8 +191,8 @@ public class FormObjectAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose given errors instance using the well known alias
|
||||
* {@link #CURRENT_FORM_OBJECT_ATTRIBUTE} in the specified scope.
|
||||
* Expose given errors instance using the well known alias {@link #CURRENT_FORM_OBJECT_ATTRIBUTE} in the specified
|
||||
* scope.
|
||||
* @param errors the errors instance
|
||||
* @param scopeType the scope in which to expose the errors instance
|
||||
*/
|
||||
@@ -207,20 +201,19 @@ public class FormObjectAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form object <code>Errors</code> tracker from the context,
|
||||
* using the specified form object name.
|
||||
* @param formObjectName the name of the Errors object, which will be
|
||||
* prefixed with {@link BindException#ERROR_KEY_PREFIX}
|
||||
* Gets the form object <code>Errors</code> tracker from the context, using the specified form object name.
|
||||
* @param formObjectName the name of the Errors object, which will be prefixed with
|
||||
* {@link BindException#ERROR_KEY_PREFIX}
|
||||
* @param scopeType the scope to obtain the errors from
|
||||
* @return the form object errors instance, or null if not found
|
||||
*/
|
||||
public Errors getFormErrors(String formObjectName, ScopeType scopeType) {
|
||||
return (Errors)scopeType.getScope(context).get(ERRORS_PREFIX + formObjectName, Errors.class);
|
||||
return (Errors) scopeType.getScope(context).get(ERRORS_PREFIX + formObjectName, Errors.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose given errors instance in the specified scope. Given errors
|
||||
* instance will become the <i>current</i> form errors instance.
|
||||
* Expose given errors instance in the specified scope. Given errors instance will become the <i>current</i> form
|
||||
* errors instance.
|
||||
* @param errors the errors object
|
||||
* @param scopeType the scope to expose the errors in
|
||||
*/
|
||||
|
||||
@@ -22,8 +22,8 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Thin action proxy that delegates to a method on an arbitrary bean. The bean
|
||||
* instance is managed locally by this Action in an instance variable.
|
||||
* Thin action proxy that delegates to a method on an arbitrary bean. The bean instance is managed locally by this
|
||||
* Action in an instance variable.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -35,8 +35,8 @@ class LocalBeanInvokingAction extends AbstractBeanInvokingAction implements Seri
|
||||
private Object bean;
|
||||
|
||||
/**
|
||||
* Creates a bean invoking action that invokes a method on the specified bean.
|
||||
* The bean may be a proxy providing a layer of indirection if necessary.
|
||||
* Creates a bean invoking action that invokes a method on the specified bean. The bean may be a proxy providing a
|
||||
* layer of indirection if necessary.
|
||||
* @param bean the bean to invoke
|
||||
*/
|
||||
public LocalBeanInvokingAction(MethodSignature methodSignature, Object bean) {
|
||||
|
||||
@@ -21,18 +21,16 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.util.DispatchMethodInvoker;
|
||||
|
||||
/**
|
||||
* Action implementation that bundles two or more action execution methods into
|
||||
* a single class. Action execution methods defined by subclasses must adhere to
|
||||
* the following signature:
|
||||
* Action implementation that bundles two or more action execution methods into a single class. Action execution methods
|
||||
* defined by subclasses must adhere to the following signature:
|
||||
*
|
||||
* <pre>
|
||||
* public Event ${method}(RequestContext context) throws Exception;
|
||||
* </pre>
|
||||
*
|
||||
* When this action is invoked, by default the <code>id</code> of the calling
|
||||
* action state state is treated as the action execution method name.
|
||||
* Alternatively, the execution method name may be explicitly specified as a
|
||||
* attribute of the calling action state.
|
||||
* When this action is invoked, by default the <code>id</code> of the calling action state state is treated as the
|
||||
* action execution method name. Alternatively, the execution method name may be explicitly specified as a attribute of
|
||||
* the calling action state.
|
||||
* <p>
|
||||
* For example, the following action state definition:
|
||||
*
|
||||
@@ -46,7 +44,7 @@ import org.springframework.webflow.util.DispatchMethodInvoker;
|
||||
* ... when entered, executes the method:
|
||||
*
|
||||
* <pre>
|
||||
* public Event search(RequestContext context) throws Exception;
|
||||
* public Event search(RequestContext context) throws Exception;
|
||||
* </pre>
|
||||
*
|
||||
* Alternatively (and typically recommended), you may explictly specify the method name:
|
||||
@@ -59,10 +57,9 @@ import org.springframework.webflow.util.DispatchMethodInvoker;
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* A typical use of the MultiAction is to centralize all command logic for a
|
||||
* flow in one place. Another common use is to centralize form setup and submit
|
||||
* logic in one place, or CRUD (create/read/update/delete) operations for a
|
||||
* single domain object in one place.
|
||||
* A typical use of the MultiAction is to centralize all command logic for a flow in one place. Another common use is to
|
||||
* centralize form setup and submit logic in one place, or CRUD (create/read/update/delete) operations for a single
|
||||
* domain object in one place.
|
||||
*
|
||||
* @see MultiAction.MethodResolver
|
||||
* @see org.springframework.webflow.action.DefaultMultiActionMethodResolver
|
||||
@@ -84,8 +81,8 @@ public class MultiAction extends AbstractAction {
|
||||
private MethodResolver methodResolver = new DefaultMultiActionMethodResolver();
|
||||
|
||||
/**
|
||||
* Protected default constructor; not invokable for direct MultiAction instantiation.
|
||||
* Intended for use by subclasses.
|
||||
* Protected default constructor; not invokable for direct MultiAction instantiation. Intended for use by
|
||||
* subclasses.
|
||||
* <p>
|
||||
* Sets the target to this multi action instance.
|
||||
* @see #setTarget(Object)
|
||||
@@ -95,12 +92,13 @@ public class MultiAction extends AbstractAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a multi action that invokes methods on the specified target
|
||||
* object. Note: invokable methods on the target must conform to the multi action
|
||||
* method signature:
|
||||
* Constructs a multi action that invokes methods on the specified target object. Note: invokable methods on the
|
||||
* target must conform to the multi action method signature:
|
||||
*
|
||||
* <pre>
|
||||
* public Event ${method}(RequestContext context) throws Exception;
|
||||
* </pre>
|
||||
*
|
||||
* @param target the target of this multi action's invocations
|
||||
*/
|
||||
public MultiAction(Object target) {
|
||||
@@ -112,7 +110,7 @@ public class MultiAction extends AbstractAction {
|
||||
* @param target the target
|
||||
*/
|
||||
protected final void setTarget(Object target) {
|
||||
methodInvoker = new DispatchMethodInvoker(target, new Class[] { RequestContext.class } );
|
||||
methodInvoker = new DispatchMethodInvoker(target, new Class[] { RequestContext.class });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,9 +121,8 @@ public class MultiAction extends AbstractAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the strategy used to resolve action execution method names.
|
||||
* Allows full control over the method resolution algorithm.
|
||||
* Defaults to {@link DefaultMultiActionMethodResolver}.
|
||||
* Set the strategy used to resolve action execution method names. Allows full control over the method resolution
|
||||
* algorithm. Defaults to {@link DefaultMultiActionMethodResolver}.
|
||||
*/
|
||||
public void setMethodResolver(MethodResolver methodResolver) {
|
||||
this.methodResolver = methodResolver;
|
||||
@@ -135,19 +132,17 @@ public class MultiAction extends AbstractAction {
|
||||
String method = getMethodResolver().resolveMethod(context);
|
||||
Object obj = methodInvoker.invoke(method, new Object[] { context });
|
||||
if (obj != null) {
|
||||
Assert.isInstanceOf(Event.class, obj,
|
||||
"The '" + method + "' action execution method on target object '" +
|
||||
methodInvoker.getTarget() + "' did not return an Event object but '" +
|
||||
obj + "' of type " + obj.getClass().getName() + " -- " +
|
||||
"Programmer error; make sure the method signature conforms to " +
|
||||
"'public Event ${method}(RequestContext context) throws Exception;'.");
|
||||
Assert.isInstanceOf(Event.class, obj, "The '" + method + "' action execution method on target object '"
|
||||
+ methodInvoker.getTarget() + "' did not return an Event object but '" + obj + "' of type "
|
||||
+ obj.getClass().getName() + " -- "
|
||||
+ "Programmer error; make sure the method signature conforms to "
|
||||
+ "'public Event ${method}(RequestContext context) throws Exception;'.");
|
||||
}
|
||||
return (Event)obj;
|
||||
return (Event) obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy interface used by the MultiAction to map a request context to
|
||||
* the name of an action execution method.
|
||||
* Strategy interface used by the MultiAction to map a request context to the name of an action execution method.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -157,8 +152,7 @@ public class MultiAction extends AbstractAction {
|
||||
/**
|
||||
* Resolve a method name from given flow execution request context.
|
||||
* @param context the flow execution request context
|
||||
* @return the name of the method that should handle action
|
||||
* execution
|
||||
* @return the name of the method that should handle action execution
|
||||
*/
|
||||
public String resolveMethod(RequestContext context);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* A strategy for creating an {@link Event} object from an arbitrary object
|
||||
* such as an expression evaluation result or bean method return value.
|
||||
* A strategy for creating an {@link Event} object from an arbitrary object such as an expression evaluation result or
|
||||
* bean method return value.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -29,8 +29,7 @@ public interface ResultEventFactory {
|
||||
/**
|
||||
* Create an event instance from the result object.
|
||||
* @param source the source of the event
|
||||
* @param resultObject the result object, typically the return value of a
|
||||
* bean method
|
||||
* @param resultObject the result object, typically the return value of a bean method
|
||||
* @param context a flow execution request context
|
||||
* @return the event
|
||||
*/
|
||||
|
||||
@@ -18,8 +18,7 @@ package org.springframework.webflow.action;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Helper that selects the {@link ResultEventFactory} to use for
|
||||
* a particular result object.
|
||||
* Helper that selects the {@link ResultEventFactory} to use for a particular result object.
|
||||
*
|
||||
* @see EvaluateAction
|
||||
* @see BeanInvokingActionFactory
|
||||
@@ -34,14 +33,13 @@ public class ResultEventFactorySelector {
|
||||
private SuccessEventFactory successEventFactory = new SuccessEventFactory();
|
||||
|
||||
/**
|
||||
* The event factory instance for mapping a result object to an event, using
|
||||
* the type of the result object as the mapping criteria.
|
||||
* The event factory instance for mapping a result object to an event, using the type of the result object as the
|
||||
* mapping criteria.
|
||||
*/
|
||||
private ResultObjectBasedEventFactory resultObjectBasedEventFactory = new ResultObjectBasedEventFactory();
|
||||
|
||||
/**
|
||||
* Select the appropriate result event factory for attempts to invoke the
|
||||
* given method.
|
||||
* Select the appropriate result event factory for attempts to invoke the given method.
|
||||
* @param method the method
|
||||
* @return the result event factory
|
||||
*/
|
||||
@@ -57,26 +55,23 @@ public class ResultEventFactorySelector {
|
||||
public ResultEventFactory forResult(Object result) {
|
||||
if (result == null) {
|
||||
return successEventFactory;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return forType(result.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Select the appropriate result event factory for given result type.
|
||||
* This implementation returns {@link ResultObjectBasedEventFactory} if the
|
||||
* type is {@link ResultObjectBasedEventFactory#isMappedValueType(Class) mapped}
|
||||
* by that result event factory, otherwise {@link SuccessEventFactory} is
|
||||
* returned.
|
||||
* Select the appropriate result event factory for given result type. This implementation returns
|
||||
* {@link ResultObjectBasedEventFactory} if the type is
|
||||
* {@link ResultObjectBasedEventFactory#isMappedValueType(Class) mapped} by that result event factory, otherwise
|
||||
* {@link SuccessEventFactory} is returned.
|
||||
* @param resultType the result type
|
||||
* @return the result event factory
|
||||
*/
|
||||
protected ResultEventFactory forType(Class resultType) {
|
||||
if (resultObjectBasedEventFactory.isMappedValueType(resultType)) {
|
||||
return resultObjectBasedEventFactory;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return successEventFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,8 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.support.EventFactorySupport;
|
||||
|
||||
/**
|
||||
* Result object-to-event adapter interface that tries to do a
|
||||
* sensible conversion of the result object into a web flow event.
|
||||
* It uses the following conversion table:
|
||||
* <table border="1">
|
||||
* Result object-to-event adapter interface that tries to do a sensible conversion of the result object into a web flow
|
||||
* event. It uses the following conversion table: <table border="1">
|
||||
* <tr>
|
||||
* <th>Result object type</th>
|
||||
* <th>Event id</th>
|
||||
@@ -45,14 +43,12 @@ import org.springframework.webflow.execution.support.EventFactorySupport;
|
||||
* <tr>
|
||||
* <td>{@link org.springframework.core.enums.LabeledEnum}</td>
|
||||
* <td>{@link org.springframework.core.enums.LabeledEnum#getLabel()}</td>
|
||||
* <td>The result object will included in the event as an attribute
|
||||
* named "result".</td>
|
||||
* <td>The result object will included in the event as an attribute named "result".</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link java.lang.Enum}</td>
|
||||
* <td>{@link java.lang.Enum#name()}</td>
|
||||
* <td>The result object will included in the event as an attribute
|
||||
* named "result".</td>
|
||||
* <td>The result object will included in the event as an attribute named "result".</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link java.lang.String}</td>
|
||||
@@ -70,44 +66,37 @@ import org.springframework.webflow.execution.support.EventFactorySupport;
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class ResultObjectBasedEventFactory extends EventFactorySupport implements ResultEventFactory {
|
||||
|
||||
|
||||
public Event createResultEvent(Object source, Object resultObject, RequestContext context) {
|
||||
if (resultObject == null) {
|
||||
// this handles the case where the declared result return type is mapped
|
||||
// by this class but the value is null
|
||||
return event(source, getNullEventId());
|
||||
}
|
||||
else if (isBoolean(resultObject.getClass())) {
|
||||
return event(source, ((Boolean)resultObject).booleanValue());
|
||||
}
|
||||
else if (isLabeledEnum(resultObject.getClass())) {
|
||||
String resultId = ((LabeledEnum)resultObject).getLabel();
|
||||
} else if (isBoolean(resultObject.getClass())) {
|
||||
return event(source, ((Boolean) resultObject).booleanValue());
|
||||
} else if (isLabeledEnum(resultObject.getClass())) {
|
||||
String resultId = ((LabeledEnum) resultObject).getLabel();
|
||||
return event(source, resultId, getResultAttributeName(), resultObject);
|
||||
}
|
||||
else if (isJdk5Enum(resultObject.getClass())) {
|
||||
} else if (isJdk5Enum(resultObject.getClass())) {
|
||||
String eventId = EnumNameResolver.getEnumName(resultObject);
|
||||
return event(source, eventId, getResultAttributeName(), resultObject);
|
||||
}
|
||||
else if (isString(resultObject.getClass())) {
|
||||
return event(source, (String)resultObject);
|
||||
}
|
||||
else if (isEvent(resultObject.getClass())) {
|
||||
return (Event)resultObject;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Cannot deal with result object '" + resultObject +
|
||||
"' of type '" + resultObject.getClass() + "'");
|
||||
} else if (isString(resultObject.getClass())) {
|
||||
return event(source, (String) resultObject);
|
||||
} else if (isEvent(resultObject.getClass())) {
|
||||
return (Event) resultObject;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot deal with result object '" + resultObject + "' of type '"
|
||||
+ resultObject.getClass() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not given type is mapped to a corresponding
|
||||
* event using special mapping rules.
|
||||
* Check whether or not given type is mapped to a corresponding event using special mapping rules.
|
||||
*/
|
||||
public boolean isMappedValueType(Class type) {
|
||||
return isBoolean(type) || isLabeledEnum(type) || isJdk5Enum(type) || isString(type) || isEvent(type);
|
||||
}
|
||||
|
||||
|
||||
// internal helpers to determine the 'type' of a class
|
||||
|
||||
private boolean isBoolean(Class type) {
|
||||
@@ -121,8 +110,7 @@ public class ResultObjectBasedEventFactory extends EventFactorySupport implement
|
||||
private boolean isJdk5Enum(Class type) {
|
||||
if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15) {
|
||||
return type.isEnum();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -130,18 +118,17 @@ public class ResultObjectBasedEventFactory extends EventFactorySupport implement
|
||||
private boolean isString(Class type) {
|
||||
return String.class.equals(type);
|
||||
}
|
||||
|
||||
|
||||
private boolean isEvent(Class type) {
|
||||
return Event.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple helper class with Java 5 specific code factored out to keep
|
||||
* the containing class JDK 1.3 compatible.
|
||||
* Simple helper class with Java 5 specific code factored out to keep the containing class JDK 1.3 compatible.
|
||||
*/
|
||||
private static class EnumNameResolver {
|
||||
public static String getEnumName(Object enumValue) {
|
||||
return ((java.lang.Enum)enumValue).name();
|
||||
return ((java.lang.Enum) enumValue).name();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,7 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ScopeType;
|
||||
|
||||
/**
|
||||
* An action that sets an attribute in a {@link ScopeType scope} when executed.
|
||||
* Always returns the "success" event.
|
||||
* An action that sets an attribute in a {@link ScopeType scope} when executed. Always returns the "success" event.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -43,7 +42,7 @@ public class SetAction extends AbstractAction {
|
||||
private ScopeType scope;
|
||||
|
||||
/**
|
||||
* The expression for resolving the scoped attribute value.
|
||||
* The expression for resolving the scoped attribute value.
|
||||
*/
|
||||
private Expression valueExpression;
|
||||
|
||||
@@ -71,8 +70,8 @@ public class SetAction extends AbstractAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method subclasses may override to customize the expression
|
||||
* evaluation context. This implementation returns null.
|
||||
* Template method subclasses may override to customize the expression evaluation context. This implementation
|
||||
* returns null.
|
||||
* @param context the request context
|
||||
* @return the evaluation context
|
||||
*/
|
||||
|
||||
@@ -20,13 +20,12 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.support.EventFactorySupport;
|
||||
|
||||
/**
|
||||
* Default implementation of the resultObject-to-event mapping interface.
|
||||
* Always returns the "success" event.
|
||||
* Default implementation of the resultObject-to-event mapping interface. Always returns the "success" event.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class SuccessEventFactory extends EventFactorySupport implements ResultEventFactory {
|
||||
|
||||
|
||||
public Event createResultEvent(Object source, Object resultObject, RequestContext context) {
|
||||
return success(source, resultObject);
|
||||
}
|
||||
|
||||
@@ -26,16 +26,14 @@ import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Action implementation that changes a PortletResponse mode. The action only
|
||||
* generates the
|
||||
* {@link org.springframework.webflow.action.AbstractAction#success()} event.
|
||||
* All error cases result in an exception being thrown.
|
||||
* Action implementation that changes a PortletResponse mode. The action only generates the
|
||||
* {@link org.springframework.webflow.action.AbstractAction#success()} event. All error cases result in an exception
|
||||
* being thrown.
|
||||
* <p>
|
||||
* This class is usefull when you want to change the current PortletMode before
|
||||
* entering a specific state, e.g. it can be the first state in a subflow.
|
||||
* This class is usefull when you want to change the current PortletMode before entering a specific state, e.g. it can
|
||||
* be the first state in a subflow.
|
||||
* <p>
|
||||
* Note: if you can, change the PortletMode using Portlet URLs (PortletURL class
|
||||
* or portlet TAG).
|
||||
* Note: if you can, change the PortletMode using Portlet URLs (PortletURL class or portlet TAG).
|
||||
*
|
||||
* @author J.Enrique Ruiz
|
||||
* @author Cesar Ordinana
|
||||
@@ -44,8 +42,7 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
public class SetPortletModeAction extends AbstractAction {
|
||||
|
||||
/**
|
||||
* The portlet mode to set can be specified in an action state action
|
||||
* attribute with this name ("portletMode").
|
||||
* The portlet mode to set can be specified in an action state action attribute with this name ("portletMode").
|
||||
*/
|
||||
public static final String PORTLET_MODE_ATTRIBUTE = "portletMode";
|
||||
|
||||
@@ -71,29 +68,25 @@ public class SetPortletModeAction extends AbstractAction {
|
||||
|
||||
/**
|
||||
* Sets the PortletMode.
|
||||
* @param context the action execution context, for accessing and setting
|
||||
* data in "flow scope" or "request scope"
|
||||
* @param context the action execution context, for accessing and setting data in "flow scope" or "request scope"
|
||||
* @return the action result event
|
||||
* @throws Exception an <b>unrecoverable</b> exception occured, either
|
||||
* checked or unchecked
|
||||
* @throws Exception an <b>unrecoverable</b> exception occured, either checked or unchecked
|
||||
*/
|
||||
protected Event doExecute(RequestContext context) throws Exception {
|
||||
Assert.isInstanceOf(PortletExternalContext.class, context.getExternalContext(), "'"
|
||||
+ ClassUtils.getShortName(this.getClass()) + "' can only work with 'PortletExternalContext': ");
|
||||
PortletExternalContext portletContext = (PortletExternalContext)context.getExternalContext();
|
||||
PortletExternalContext portletContext = (PortletExternalContext) context.getExternalContext();
|
||||
if (portletContext.getResponse() instanceof ActionResponse) {
|
||||
PortletMode mode =
|
||||
(PortletMode)context.getAttributes().get(PORTLET_MODE_ATTRIBUTE, PortletMode.class, getPortletMode());
|
||||
((ActionResponse)portletContext.getResponse()).setPortletMode(mode);
|
||||
PortletMode mode = (PortletMode) context.getAttributes().get(PORTLET_MODE_ATTRIBUTE, PortletMode.class,
|
||||
getPortletMode());
|
||||
((ActionResponse) portletContext.getResponse()).setPortletMode(mode);
|
||||
return success();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// portlet mode and the window state can be changed through
|
||||
// ActionResponse only, if this is not the case, it means that this
|
||||
// action has been invoked directly in a RenderRequest
|
||||
throw new IllegalStateException(
|
||||
"SetPortletModeAction can only be invoked within a Action request -- " +
|
||||
"make sure you are not invoking it in a RenderRequest");
|
||||
throw new IllegalStateException("SetPortletModeAction can only be invoked within a Action request -- "
|
||||
+ "make sure you are not invoking it in a RenderRequest");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} for the <code><enable-scopes></code> tag.
|
||||
*
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @since 1.1
|
||||
*/
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.w3c.dom.Element;
|
||||
* @author Ben Hale
|
||||
*/
|
||||
class ExecutionAttributesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
|
||||
// elements and attributes
|
||||
|
||||
private static final String ATTRIBUTE_ELEMENT = "attribute";
|
||||
@@ -68,7 +68,7 @@ class ExecutionAttributesBeanDefinitionParser extends AbstractSingleBeanDefiniti
|
||||
*/
|
||||
private void putAttributes(Map attributeMap, List attributeElements) {
|
||||
for (Iterator i = attributeElements.iterator(); i.hasNext();) {
|
||||
Element attributeElement = (Element)i.next();
|
||||
Element attributeElement = (Element) i.next();
|
||||
String type = attributeElement.getAttribute(TYPE_ATTRIBUTE);
|
||||
Object value;
|
||||
if (StringUtils.hasText(type)) {
|
||||
@@ -81,17 +81,15 @@ class ExecutionAttributesBeanDefinitionParser extends AbstractSingleBeanDefiniti
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all non-generic (special) attributes defined in given element
|
||||
* to given map.
|
||||
* Add all non-generic (special) attributes defined in given element to given map.
|
||||
*/
|
||||
private void putSpecialAttributes(Map attributeMap, Element element) {
|
||||
putAlwaysRedirectOnPauseAttribute(attributeMap,
|
||||
DomUtils.getChildElementByTagName(element, ApplicationViewSelector.ALWAYS_REDIRECT_ON_PAUSE_ATTRIBUTE));
|
||||
putAlwaysRedirectOnPauseAttribute(attributeMap, DomUtils.getChildElementByTagName(element,
|
||||
ApplicationViewSelector.ALWAYS_REDIRECT_ON_PAUSE_ATTRIBUTE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the "alwaysRedirectOnPause" attribute from given element and
|
||||
* add it to given map.
|
||||
* Parse the "alwaysRedirectOnPause" attribute from given element and add it to given map.
|
||||
*/
|
||||
private void putAlwaysRedirectOnPauseAttribute(Map attributeMap, Element element) {
|
||||
if (element != null) {
|
||||
|
||||
@@ -29,21 +29,20 @@ import org.springframework.webflow.execution.factory.ConditionalFlowExecutionLis
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} for the <code><execution-listeners></code>
|
||||
* tag.
|
||||
* {@link BeanDefinitionParser} for the <code><execution-listeners></code> tag.
|
||||
*
|
||||
* @author Ben Hale
|
||||
*/
|
||||
class ExecutionListenersBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
|
||||
// elements and attributes
|
||||
|
||||
private static final String LISTENER_ELEMENT= "listener";
|
||||
|
||||
private static final String LISTENER_ELEMENT = "listener";
|
||||
|
||||
// properties
|
||||
|
||||
private static final String LISTENERS_PROPERTY = "listeners";
|
||||
|
||||
|
||||
private static final String CRITERIA_ATTRIBUTE = "criteria";
|
||||
|
||||
private static final String REF_ATTRIBUTE = "ref";
|
||||
@@ -60,13 +59,13 @@ class ExecutionListenersBeanDefinitionParser extends AbstractSingleBeanDefinitio
|
||||
/**
|
||||
* Creates a map of listeners with their associated criteria.
|
||||
* @param listeners the list of listener elements from the bean definition
|
||||
* @return a map containing keys that are references to given listeners
|
||||
* and values of string that represent the criteria
|
||||
* @return a map containing keys that are references to given listeners and values of string that represent the
|
||||
* criteria
|
||||
*/
|
||||
private Map getListenersWithCriteria(List listeners) {
|
||||
Map listenersWithCriteria = new ManagedMap(listeners.size());
|
||||
for (Iterator i = listeners.iterator(); i.hasNext();) {
|
||||
Element listenerElement = (Element)i.next();
|
||||
Element listenerElement = (Element) i.next();
|
||||
RuntimeBeanReference ref = new RuntimeBeanReference(listenerElement.getAttribute(REF_ATTRIBUTE));
|
||||
String criteria = listenerElement.getAttribute(CRITERIA_ATTRIBUTE);
|
||||
listenersWithCriteria.put(ref, criteria);
|
||||
|
||||
@@ -33,48 +33,46 @@ import org.w3c.dom.Element;
|
||||
class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
// elements and attributes
|
||||
|
||||
|
||||
private static final String CONVERSATION_MANAGER_REF_ATTRIBUTE = "conversation-manager-ref";
|
||||
|
||||
|
||||
private static final String EXECUTION_ATTRIBUTES_ELEMENT = "execution-attributes";
|
||||
|
||||
private static final String EXECUTION_LISTENERS_ELEMENT = "execution-listeners";
|
||||
|
||||
|
||||
private static final String MAX_CONTINUATIONS_ATTRIBUTE = "max-continuations";
|
||||
|
||||
|
||||
private static final String MAX_CONVERSATIONS_ATTRIBUTE = "max-conversations";
|
||||
|
||||
private static final String REGISTRY_REF_ATTRIBUTE = "registry-ref";
|
||||
|
||||
|
||||
private static final String REPOSITORY_ELEMENT = "repository";
|
||||
|
||||
private static final String REPOSITORY_TYPE_ATTRIBUTE = "repository-type";
|
||||
|
||||
|
||||
private static final String TYPE_ATTRIBUTE = "type";
|
||||
|
||||
// properties
|
||||
|
||||
private static final String CONVERSATION_MANAGER_PROPERTY = "conversationManager";
|
||||
|
||||
|
||||
private static final String DEFINITION_LOCATOR_PROPERTY = "definitionLocator";
|
||||
|
||||
private static final String EXECUTION_ATTRIBUTES_PROPERTY = "executionAttributes";
|
||||
|
||||
private static final String EXECUTION_LISTENER_LOADER_PROPERTY = "executionListenerLoader";
|
||||
|
||||
|
||||
private static final String MAX_CONTINUATIONS_PROPERTY = "maxContinuations";
|
||||
|
||||
|
||||
private static final String MAX_CONVERSATIONS_PROPERTY = "maxConversations";
|
||||
|
||||
private static final String REPOSITORY_TYPE_PROPERTY = "repositoryType";
|
||||
|
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(FlowExecutorFactoryBean.class);
|
||||
definitionBuilder.setSource(parserContext.extractSource(element));
|
||||
definitionBuilder.addPropertyReference(DEFINITION_LOCATOR_PROPERTY,
|
||||
getRegistryRef(element, parserContext));
|
||||
definitionBuilder.addPropertyReference(DEFINITION_LOCATOR_PROPERTY, getRegistryRef(element, parserContext));
|
||||
addExecutionAttributes(element, parserContext, definitionBuilder);
|
||||
addExecutionListenerLoader(element, parserContext, definitionBuilder);
|
||||
configureRepository(element, definitionBuilder, parserContext);
|
||||
@@ -82,29 +80,27 @@ class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a repository based on the <code>repository-type</code> attribute
|
||||
* or a <code>repository</code> tag.
|
||||
* Configures a repository based on the <code>repository-type</code> attribute or a <code>repository</code> tag.
|
||||
* @param element the root element to extract repository configuration from
|
||||
* @param definitionBuilder the builder
|
||||
* @param parserContext the parserContext
|
||||
*/
|
||||
private void configureRepository(Element element, BeanDefinitionBuilder definitionBuilder,
|
||||
private void configureRepository(Element element, BeanDefinitionBuilder definitionBuilder,
|
||||
ParserContext parserContext) {
|
||||
Element repositoryElement = DomUtils.getChildElementByTagName(element, REPOSITORY_ELEMENT);
|
||||
String repositoryTypeAttribute = getRepositoryType(element);
|
||||
if (repositoryElement != null) {
|
||||
if (StringUtils.hasText(repositoryTypeAttribute)) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The 'repositoryType' attribute of the 'executor' element must " +
|
||||
"not have a value if there is a 'repository' element", element);
|
||||
"The 'repositoryType' attribute of the 'executor' element must "
|
||||
+ "not have a value if there is a 'repository' element", element);
|
||||
}
|
||||
definitionBuilder.addPropertyValue(REPOSITORY_TYPE_PROPERTY, getType(repositoryElement));
|
||||
configureContinuations(repositoryElement, definitionBuilder, parserContext);
|
||||
configureConversationManager(repositoryElement, definitionBuilder, parserContext);
|
||||
}
|
||||
else if (StringUtils.hasText(repositoryTypeAttribute)) {
|
||||
} else if (StringUtils.hasText(repositoryTypeAttribute)) {
|
||||
definitionBuilder.addPropertyValue(REPOSITORY_TYPE_PROPERTY, repositoryTypeAttribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,8 +115,8 @@ class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
if (StringUtils.hasText(maxContinuations)) {
|
||||
if (!getType(repositoryElement).equals("CONTINUATION")) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The 'max-continuations' attribute of the 'repository' element must not " +
|
||||
"have a value if the 'type' attribute is not 'continuation'", repositoryElement);
|
||||
"The 'max-continuations' attribute of the 'repository' element must not "
|
||||
+ "have a value if the 'type' attribute is not 'continuation'", repositoryElement);
|
||||
}
|
||||
definitionBuilder.addPropertyValue(MAX_CONTINUATIONS_PROPERTY, maxContinuations);
|
||||
}
|
||||
@@ -132,24 +128,23 @@ class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
* @param definitionBuilder the builder
|
||||
* @param parserContext the parserContext
|
||||
*/
|
||||
private void configureConversationManager(Element repositoryElement, BeanDefinitionBuilder definitionBuilder,
|
||||
private void configureConversationManager(Element repositoryElement, BeanDefinitionBuilder definitionBuilder,
|
||||
ParserContext parserContext) {
|
||||
String conversationManagerRef = getConversationManagerRef(repositoryElement);
|
||||
String maxConversations = getMaxConversations(repositoryElement);
|
||||
if (StringUtils.hasText(conversationManagerRef)) {
|
||||
if(StringUtils.hasText(maxConversations)) {
|
||||
if (StringUtils.hasText(maxConversations)) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The 'max-conversations' attribute of the 'repository' element must not " +
|
||||
"have a value if there is a value for the 'conversation-manager-ref' attribute",
|
||||
"The 'max-conversations' attribute of the 'repository' element must not "
|
||||
+ "have a value if there is a value for the 'conversation-manager-ref' attribute",
|
||||
repositoryElement);
|
||||
}
|
||||
definitionBuilder.addPropertyReference(CONVERSATION_MANAGER_PROPERTY, conversationManagerRef);
|
||||
}
|
||||
else if (StringUtils.hasText(maxConversations)) {
|
||||
} else if (StringUtils.hasText(maxConversations)) {
|
||||
definitionBuilder.addPropertyValue(MAX_CONVERSATIONS_PROPERTY, maxConversations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the registry detailed in the bean definition.
|
||||
* @param element the element to extract the registry name from
|
||||
@@ -166,25 +161,23 @@ class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the repository type enum field detailed in the bean
|
||||
* definition.
|
||||
* Returns the name of the repository type enum field detailed in the bean definition.
|
||||
* @param element the element to extract the repository type from
|
||||
* @return the type of the repository
|
||||
*/
|
||||
private String getRepositoryType(Element element) {
|
||||
return element.getAttribute(REPOSITORY_TYPE_ATTRIBUTE).toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the repository type enum field detailed in the bean
|
||||
* definition.
|
||||
* Returns the name of the repository type enum field detailed in the bean definition.
|
||||
* @param element the element to extract the repository type from
|
||||
* @return the type of the repository
|
||||
*/
|
||||
private String getType(Element element) {
|
||||
return element.getAttribute(TYPE_ATTRIBUTE).toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the maximum number of continuations detailed in the bean definition.
|
||||
* @param element the element to extract the max continuations from
|
||||
@@ -193,7 +186,7 @@ class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
private String getMaxContinuations(Element element) {
|
||||
return element.getAttribute(MAX_CONTINUATIONS_ATTRIBUTE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the maximum number of conversations detailed in the bean definition.
|
||||
* @param element the element to extract the max conversations from
|
||||
@@ -202,7 +195,7 @@ class ExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
private String getMaxConversations(Element element) {
|
||||
return element.getAttribute(MAX_CONVERSATIONS_ATTRIBUTE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the conversation manager detailed in the bean definition.
|
||||
* @param element the element to extract the conversation manager name from
|
||||
|
||||
@@ -45,21 +45,18 @@ import org.springframework.webflow.executor.FlowExecutor;
|
||||
import org.springframework.webflow.executor.FlowExecutorImpl;
|
||||
|
||||
/**
|
||||
* The default flow executor factory implementation. As a <code>FactoryBean</code>,
|
||||
* this class has been designed for use as a Spring managed bean.
|
||||
* The default flow executor factory implementation. As a <code>FactoryBean</code>, this class has been designed for
|
||||
* use as a Spring managed bean.
|
||||
* <p>
|
||||
* This factory encapsulates the construction and assembly of a
|
||||
* {@link FlowExecutor}, including the provision of its
|
||||
* This factory encapsulates the construction and assembly of a {@link FlowExecutor}, including the provision of its
|
||||
* {@link FlowExecutionRepository} strategy.
|
||||
* <p>
|
||||
* The {@link #setDefinitionLocator(FlowDefinitionLocator) definition locator}
|
||||
* property is required, all other properties are optional.
|
||||
* The {@link #setDefinitionLocator(FlowDefinitionLocator) definition locator} property is required, all other
|
||||
* properties are optional.
|
||||
* <p>
|
||||
* This class has been designed with subclassing in mind. If you want to do advanced
|
||||
* Spring Web Flow customization, e.g. using a custom
|
||||
* {@link org.springframework.webflow.executor.FlowExecutor} implementation,
|
||||
* consider subclassing this class and overriding one or more of the provided
|
||||
* hook methods.
|
||||
* This class has been designed with subclassing in mind. If you want to do advanced Spring Web Flow customization, e.g.
|
||||
* using a custom {@link org.springframework.webflow.executor.FlowExecutor} implementation, consider subclassing this
|
||||
* class and overriding one or more of the provided hook methods.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -67,8 +64,7 @@ import org.springframework.webflow.executor.FlowExecutorImpl;
|
||||
public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
/**
|
||||
* The locator the executor will use to access flow definitions registered
|
||||
* in a central registry. Required.
|
||||
* The locator the executor will use to access flow definitions registered in a central registry. Required.
|
||||
*/
|
||||
private FlowDefinitionLocator definitionLocator;
|
||||
|
||||
@@ -76,39 +72,38 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
* Execution attributes to apply.
|
||||
*/
|
||||
private MutableAttributeMap executionAttributes;
|
||||
|
||||
|
||||
/**
|
||||
* The loader that will determine which listeners to attach to flow definition executions.
|
||||
* The loader that will determine which listeners to attach to flow definition executions.
|
||||
*/
|
||||
private FlowExecutionListenerLoader executionListenerLoader;
|
||||
|
||||
|
||||
/**
|
||||
* The conversation manager to be used by the flow execution repository to
|
||||
* store state associated with conversations driven by Spring Web Flow.
|
||||
* The conversation manager to be used by the flow execution repository to store state associated with conversations
|
||||
* driven by Spring Web Flow.
|
||||
*/
|
||||
private ConversationManager conversationManager;
|
||||
|
||||
|
||||
/**
|
||||
* The maximum number of allowed concurrent conversations in the session.
|
||||
*/
|
||||
private Integer maxConversations;
|
||||
|
||||
|
||||
/**
|
||||
* The type of execution repository to configure with executors created by
|
||||
* this factory. Optional. Will fallback to default value if not set.
|
||||
* The type of execution repository to configure with executors created by this factory. Optional. Will fallback to
|
||||
* default value if not set.
|
||||
*/
|
||||
private RepositoryType repositoryType;
|
||||
|
||||
|
||||
/**
|
||||
* The maximum number of allowed continuations for a single conversation.
|
||||
* Only used when the repository type is {@link RepositoryType#CONTINUATION}.
|
||||
* The maximum number of allowed continuations for a single conversation. Only used when the repository type is
|
||||
* {@link RepositoryType#CONTINUATION}.
|
||||
*/
|
||||
private Integer maxContinuations;
|
||||
|
||||
|
||||
/**
|
||||
* A custom attribute mapper to use for mapping attributes of an
|
||||
* {@link ExternalContext} to a new {@link FlowExecution} during the
|
||||
* {@link FlowExecutor#launch(String, ExternalContext) launch flow} operation.
|
||||
* A custom attribute mapper to use for mapping attributes of an {@link ExternalContext} to a new
|
||||
* {@link FlowExecution} during the {@link FlowExecutor#launch(String, ExternalContext) launch flow} operation.
|
||||
*/
|
||||
private AttributeMapper inputMapper;
|
||||
|
||||
@@ -118,13 +113,13 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
/**
|
||||
* Spring Web Flow executor system defaults.
|
||||
* Spring Web Flow executor system defaults.
|
||||
*/
|
||||
private FlowSystemDefaults defaults = new FlowSystemDefaults();
|
||||
|
||||
|
||||
/**
|
||||
* Sets the flow definition locator that will locate flow definitions needed
|
||||
* for execution. Typically also a {@link FlowDefinitionRegistry}. Required.
|
||||
* Sets the flow definition locator that will locate flow definitions needed for execution. Typically also a
|
||||
* {@link FlowDefinitionRegistry}. Required.
|
||||
* @param definitionLocator the flow definition locator (registry)
|
||||
*/
|
||||
public void setDefinitionLocator(FlowDefinitionLocator definitionLocator) {
|
||||
@@ -132,13 +127,11 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the system attributes that apply to flow executions launched by the
|
||||
* executor created by this factory. Execution attributes may affect flow
|
||||
* execution behavior.
|
||||
* Sets the system attributes that apply to flow executions launched by the executor created by this factory.
|
||||
* Execution attributes may affect flow execution behavior.
|
||||
* <p>
|
||||
* Note: this method simply accepts a generic <code>java.util.Map</code>
|
||||
* to allow for easy configuration by Spring. The map entries should consist
|
||||
* of non-null String keys with object values.
|
||||
* Note: this method simply accepts a generic <code>java.util.Map</code> to allow for easy configuration by
|
||||
* Spring. The map entries should consist of non-null String keys with object values.
|
||||
* @param executionAttributes the flow execution system attributes
|
||||
*/
|
||||
public void setExecutionAttributes(Map executionAttributes) {
|
||||
@@ -146,8 +139,8 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience setter that sets a single listener that always applies to flow
|
||||
* executions launched by the executor created by this factory.
|
||||
* Convenience setter that sets a single listener that always applies to flow executions launched by the executor
|
||||
* created by this factory.
|
||||
* @param executionListener the flow execution listener
|
||||
*/
|
||||
public void setExecutionListener(FlowExecutionListener executionListener) {
|
||||
@@ -155,8 +148,8 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience setter that sets a list of listeners that always apply to
|
||||
* flow executions launched by the executor created by this factory.
|
||||
* Convenience setter that sets a list of listeners that always apply to flow executions launched by the executor
|
||||
* created by this factory.
|
||||
* @param executionListeners the flow execution listeners
|
||||
*/
|
||||
public void setExecutionListeners(FlowExecutionListener[] executionListeners) {
|
||||
@@ -164,43 +157,38 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy for loading the listeners that will observe executions
|
||||
* of a flow definition. Allows full control over what listeners should
|
||||
* apply to executions of a flow definition launched by the executor created
|
||||
* by this factory.
|
||||
* Sets the strategy for loading the listeners that will observe executions of a flow definition. Allows full
|
||||
* control over what listeners should apply to executions of a flow definition launched by the executor created by
|
||||
* this factory.
|
||||
*/
|
||||
public void setExecutionListenerLoader(FlowExecutionListenerLoader executionListenerLoader) {
|
||||
this.executionListenerLoader = executionListenerLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of flow execution repository that should be configured for
|
||||
* the flow executors created by this factory. This factory encapsulates the
|
||||
* construction of the repository implementation corresponding to the
|
||||
* Sets the type of flow execution repository that should be configured for the flow executors created by this
|
||||
* factory. This factory encapsulates the construction of the repository implementation corresponding to the
|
||||
* provided type.
|
||||
* @param repositoryType the flow execution repository type
|
||||
*/
|
||||
public void setRepositoryType(RepositoryType repositoryType) {
|
||||
this.repositoryType = repositoryType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the maximum number of continuation snapshots allowed for a single
|
||||
* conversation when using the {@link RepositoryType#CONTINUATION continuation}
|
||||
* flow execution repository.
|
||||
* Set the maximum number of continuation snapshots allowed for a single conversation when using the
|
||||
* {@link RepositoryType#CONTINUATION continuation} flow execution repository.
|
||||
* @see ContinuationFlowExecutionRepository#setMaxContinuations(int)
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public void setMaxContinuations(int maxContinuations) {
|
||||
this.maxContinuations = new Integer(maxContinuations);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the configured maximum number of continuation snapshots allowed
|
||||
* for a single conversation when using the
|
||||
* Returns the configured maximum number of continuation snapshots allowed for a single conversation when using the
|
||||
* {@link RepositoryType#CONTINUATION continuation} flow execution repository.
|
||||
* @return the configured value or null if the user did not explicitly
|
||||
* specify a value and wants to use the default
|
||||
* @return the configured value or null if the user did not explicitly specify a value and wants to use the default
|
||||
* @since 1.0.1
|
||||
*/
|
||||
protected Integer getMaxContinuations() {
|
||||
@@ -208,38 +196,35 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy for managing conversations that should be configured
|
||||
* for flow executors created by this factory.
|
||||
* Sets the strategy for managing conversations that should be configured for flow executors created by this
|
||||
* factory.
|
||||
* <p>
|
||||
* The conversation manager is used by the flow execution repository
|
||||
* subsystem to begin and end new conversations that store execution state.
|
||||
* The conversation manager is used by the flow execution repository subsystem to begin and end new conversations
|
||||
* that store execution state.
|
||||
* <p>
|
||||
* By default, a {@link SessionBindingConversationManager} is used. Do not
|
||||
* use {@link #setMaxConversations(int)} when using this method.
|
||||
* By default, a {@link SessionBindingConversationManager} is used. Do not use {@link #setMaxConversations(int)}
|
||||
* when using this method.
|
||||
*/
|
||||
public void setConversationManager(ConversationManager conversationManager) {
|
||||
this.conversationManager = conversationManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the maximum number of allowed concurrent conversations in the session. This
|
||||
* is a convenience setter to allow easy configuration of the maxConversations
|
||||
* property of the default {@link SessionBindingConversationManager}. Do not use
|
||||
* this when using {@link #setConversationManager(ConversationManager)}.
|
||||
* Set the maximum number of allowed concurrent conversations in the session. This is a convenience setter to allow
|
||||
* easy configuration of the maxConversations property of the default {@link SessionBindingConversationManager}. Do
|
||||
* not use this when using {@link #setConversationManager(ConversationManager)}.
|
||||
* @see SessionBindingConversationManager#setMaxConversations(int)
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public void setMaxConversations(int maxConversations) {
|
||||
this.maxConversations = new Integer(maxConversations);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the configured maximum number of allowed concurrent conversations
|
||||
* in the session. Will only be used when using the default conversation manager,
|
||||
* e.g. when no explicit conversation manager has been configured using
|
||||
* Returns the configured maximum number of allowed concurrent conversations in the session. Will only be used when
|
||||
* using the default conversation manager, e.g. when no explicit conversation manager has been configured using
|
||||
* {@link #setConversationManager(ConversationManager)}.
|
||||
* @return the configured value or null if the user did not explicitly
|
||||
* specify a value and wants to use the default
|
||||
* @return the configured value or null if the user did not explicitly specify a value and wants to use the default
|
||||
* @since 1.0.1
|
||||
*/
|
||||
protected Integer getMaxConversations() {
|
||||
@@ -247,12 +232,11 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the service responsible for mapping attributes of an
|
||||
* {@link ExternalContext} to a new {@link FlowExecution} during the
|
||||
* {@link FlowExecutor#launch(String, ExternalContext) launch flow} operation.
|
||||
* Set the service responsible for mapping attributes of an {@link ExternalContext} to a new {@link FlowExecution}
|
||||
* during the {@link FlowExecutor#launch(String, ExternalContext) launch flow} operation.
|
||||
* <p>
|
||||
* This is optional. If not set, a default implementation will be used
|
||||
* that simply exposes all request parameters as flow execution input attributes.
|
||||
* This is optional. If not set, a default implementation will be used that simply exposes all request parameters as
|
||||
* flow execution input attributes.
|
||||
*/
|
||||
public void setInputMapper(AttributeMapper inputMapper) {
|
||||
this.inputMapper = inputMapper;
|
||||
@@ -277,37 +261,35 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(definitionLocator, "The flow definition locator is required");
|
||||
|
||||
// apply defaults
|
||||
executionAttributes = defaults.applyExecutionAttributes(executionAttributes);
|
||||
repositoryType = defaults.applyIfNecessary(repositoryType);
|
||||
|
||||
// pass all available parameters to the hook methods so that they
|
||||
// can participate in the construction process
|
||||
|
||||
// a factory for flow executions
|
||||
FlowExecutionFactory executionFactory =
|
||||
createFlowExecutionFactory(executionAttributes, executionListenerLoader);
|
||||
|
||||
// a strategy to restore deserialized flow executions
|
||||
FlowExecutionStateRestorer executionStateRestorer =
|
||||
createFlowExecutionStateRestorer(definitionLocator, executionAttributes, executionListenerLoader);
|
||||
|
||||
// a repository to store flow executions
|
||||
FlowExecutionRepository executionRepository =
|
||||
createExecutionRepository(repositoryType, executionStateRestorer, conversationManager);
|
||||
|
||||
// combine all pieces of the puzzle to get an operational flow executor
|
||||
flowExecutor = createFlowExecutor(definitionLocator, executionFactory, executionRepository);
|
||||
|
||||
// apply defaults
|
||||
executionAttributes = defaults.applyExecutionAttributes(executionAttributes);
|
||||
repositoryType = defaults.applyIfNecessary(repositoryType);
|
||||
|
||||
// pass all available parameters to the hook methods so that they
|
||||
// can participate in the construction process
|
||||
|
||||
// a factory for flow executions
|
||||
FlowExecutionFactory executionFactory = createFlowExecutionFactory(executionAttributes, executionListenerLoader);
|
||||
|
||||
// a strategy to restore deserialized flow executions
|
||||
FlowExecutionStateRestorer executionStateRestorer = createFlowExecutionStateRestorer(definitionLocator,
|
||||
executionAttributes, executionListenerLoader);
|
||||
|
||||
// a repository to store flow executions
|
||||
FlowExecutionRepository executionRepository = createExecutionRepository(repositoryType, executionStateRestorer,
|
||||
conversationManager);
|
||||
|
||||
// combine all pieces of the puzzle to get an operational flow executor
|
||||
flowExecutor = createFlowExecutor(definitionLocator, executionFactory, executionRepository);
|
||||
}
|
||||
|
||||
// subclassing hook methods
|
||||
|
||||
|
||||
/**
|
||||
* Create the conversation manager to be used in the default case, e.g. when no
|
||||
* explicit conversation manager has been configured using
|
||||
* {@link #setConversationManager(ConversationManager)}. This implementation
|
||||
* return a {@link SessionBindingConversationManager}.
|
||||
* Create the conversation manager to be used in the default case, e.g. when no explicit conversation manager has
|
||||
* been configured using {@link #setConversationManager(ConversationManager)}. This implementation return a
|
||||
* {@link SessionBindingConversationManager}.
|
||||
* @return the default conversation manager
|
||||
*/
|
||||
protected ConversationManager createDefaultConversationManager() {
|
||||
@@ -317,121 +299,107 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
return conversationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the flow execution factory to be used by the executor produced by this
|
||||
* factory bean. Configure the execution factory appropriately. Subclasses may
|
||||
* override if they which to use a custom execution factory, e.g. to use a custom
|
||||
* FlowExecution implementation.
|
||||
* @param executionAttributes execution attributes to apply to created executions
|
||||
* @param executionListenerLoader decides which listeners to apply to created executions
|
||||
* @return a new flow execution factory instance
|
||||
*/
|
||||
protected FlowExecutionFactory createFlowExecutionFactory(
|
||||
AttributeMap executionAttributes, FlowExecutionListenerLoader executionListenerLoader) {
|
||||
FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory();
|
||||
executionFactory.setExecutionAttributes(executionAttributes);
|
||||
if (executionListenerLoader != null) {
|
||||
executionFactory.setExecutionListenerLoader(executionListenerLoader);
|
||||
}
|
||||
return executionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the flow execution state restorer to be used by the executor produced by
|
||||
* this factory bean. Configure the state restorer appropriately. Subclasses may
|
||||
* override if they which to use a custom state restorer implementation.
|
||||
* @param definitionLocator the definition locator to use
|
||||
* @param executionAttributes execution attributes to apply to restored executions
|
||||
* @param executionListenerLoader decides which listeners should apply to restored
|
||||
* flow executions
|
||||
* @return a new state restorer instance
|
||||
*/
|
||||
protected FlowExecutionStateRestorer createFlowExecutionStateRestorer(
|
||||
FlowDefinitionLocator definitionLocator, AttributeMap executionAttributes,
|
||||
FlowExecutionListenerLoader executionListenerLoader) {
|
||||
FlowExecutionImplStateRestorer executionStateRestorer = new FlowExecutionImplStateRestorer(definitionLocator);
|
||||
executionStateRestorer.setExecutionAttributes(executionAttributes);
|
||||
if (executionListenerLoader != null) {
|
||||
executionStateRestorer.setExecutionListenerLoader(executionListenerLoader);
|
||||
}
|
||||
return executionStateRestorer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating the flow execution repository for saving and
|
||||
* loading executing flows. Subclasses may override to customize the
|
||||
* repository implementation used.
|
||||
* @param repositoryType a hint indicating what type of repository to create
|
||||
* @param executionStateRestorer the execution state restorer strategy to be used by
|
||||
* the repository
|
||||
* @param conversationManager the conversation manager specified by the user,
|
||||
* could be null in which case the default conversation manager should be used
|
||||
* Create the flow execution factory to be used by the executor produced by this factory bean. Configure the
|
||||
* execution factory appropriately. Subclasses may override if they which to use a custom execution factory, e.g. to
|
||||
* use a custom FlowExecution implementation.
|
||||
* @param executionAttributes execution attributes to apply to created executions
|
||||
* @param executionListenerLoader decides which listeners to apply to created executions
|
||||
* @return a new flow execution factory instance
|
||||
*/
|
||||
protected FlowExecutionFactory createFlowExecutionFactory(AttributeMap executionAttributes,
|
||||
FlowExecutionListenerLoader executionListenerLoader) {
|
||||
FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory();
|
||||
executionFactory.setExecutionAttributes(executionAttributes);
|
||||
if (executionListenerLoader != null) {
|
||||
executionFactory.setExecutionListenerLoader(executionListenerLoader);
|
||||
}
|
||||
return executionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the flow execution state restorer to be used by the executor produced by this factory bean. Configure the
|
||||
* state restorer appropriately. Subclasses may override if they which to use a custom state restorer
|
||||
* implementation.
|
||||
* @param definitionLocator the definition locator to use
|
||||
* @param executionAttributes execution attributes to apply to restored executions
|
||||
* @param executionListenerLoader decides which listeners should apply to restored flow executions
|
||||
* @return a new state restorer instance
|
||||
*/
|
||||
protected FlowExecutionStateRestorer createFlowExecutionStateRestorer(FlowDefinitionLocator definitionLocator,
|
||||
AttributeMap executionAttributes, FlowExecutionListenerLoader executionListenerLoader) {
|
||||
FlowExecutionImplStateRestorer executionStateRestorer = new FlowExecutionImplStateRestorer(definitionLocator);
|
||||
executionStateRestorer.setExecutionAttributes(executionAttributes);
|
||||
if (executionListenerLoader != null) {
|
||||
executionStateRestorer.setExecutionListenerLoader(executionListenerLoader);
|
||||
}
|
||||
return executionStateRestorer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating the flow execution repository for saving and loading executing flows. Subclasses may
|
||||
* override to customize the repository implementation used.
|
||||
* @param repositoryType a hint indicating what type of repository to create
|
||||
* @param executionStateRestorer the execution state restorer strategy to be used by the repository
|
||||
* @param conversationManager the conversation manager specified by the user, could be null in which case the
|
||||
* default conversation manager should be used
|
||||
* @return a new flow execution repository instance
|
||||
*/
|
||||
protected FlowExecutionRepository createExecutionRepository(
|
||||
RepositoryType repositoryType, FlowExecutionStateRestorer executionStateRestorer,
|
||||
ConversationManager conversationManager) {
|
||||
protected FlowExecutionRepository createExecutionRepository(RepositoryType repositoryType,
|
||||
FlowExecutionStateRestorer executionStateRestorer, ConversationManager conversationManager) {
|
||||
if (repositoryType == RepositoryType.CLIENT) {
|
||||
if (conversationManager == null) {
|
||||
// use the default no-op conversation manager
|
||||
return new ClientContinuationFlowExecutionRepository(executionStateRestorer);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// use the conversation manager specified by the user
|
||||
return new ClientContinuationFlowExecutionRepository(executionStateRestorer, conversationManager);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// determine the conversation manager to use
|
||||
ConversationManager conversationManagerToUse = conversationManager;
|
||||
if (conversationManagerToUse == null) {
|
||||
conversationManagerToUse = createDefaultConversationManager();
|
||||
}
|
||||
|
||||
|
||||
if (repositoryType == RepositoryType.SIMPLE) {
|
||||
return new SimpleFlowExecutionRepository(executionStateRestorer, conversationManagerToUse);
|
||||
}
|
||||
else if (repositoryType == RepositoryType.CONTINUATION) {
|
||||
ContinuationFlowExecutionRepository repository =
|
||||
new ContinuationFlowExecutionRepository(executionStateRestorer, conversationManagerToUse);
|
||||
} else if (repositoryType == RepositoryType.CONTINUATION) {
|
||||
ContinuationFlowExecutionRepository repository = new ContinuationFlowExecutionRepository(
|
||||
executionStateRestorer, conversationManagerToUse);
|
||||
if (getMaxContinuations() != null) {
|
||||
repository.setMaxContinuations(getMaxContinuations().intValue());
|
||||
}
|
||||
return repository;
|
||||
}
|
||||
else if (repositoryType == RepositoryType.SINGLEKEY) {
|
||||
SimpleFlowExecutionRepository repository = new SimpleFlowExecutionRepository(
|
||||
executionStateRestorer, conversationManagerToUse);
|
||||
} else if (repositoryType == RepositoryType.SINGLEKEY) {
|
||||
SimpleFlowExecutionRepository repository = new SimpleFlowExecutionRepository(executionStateRestorer,
|
||||
conversationManagerToUse);
|
||||
repository.setAlwaysGenerateNewNextKey(false);
|
||||
return repository;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot create execution repository - unsupported repository type "
|
||||
+ repositoryType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the flow executor instance created by this factory bean and configure
|
||||
* it appropriately. Subclasses may override if they which to use a custom executor
|
||||
* implementation.
|
||||
* @param definitionLocator the definition locator to use
|
||||
* @param executionFactory the execution factory to use
|
||||
* @param executionRepository the execution repository to use
|
||||
* @return a new flow executor instance
|
||||
*/
|
||||
protected FlowExecutor createFlowExecutor(
|
||||
FlowDefinitionLocator definitionLocator, FlowExecutionFactory executionFactory,
|
||||
FlowExecutionRepository executionRepository) {
|
||||
FlowExecutorImpl flowExecutor =
|
||||
new FlowExecutorImpl(definitionLocator, executionFactory, executionRepository);
|
||||
if (getInputMapper() != null) {
|
||||
flowExecutor.setInputMapper(inputMapper);
|
||||
}
|
||||
return flowExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the flow executor instance created by this factory bean and configure it appropriately. Subclasses may
|
||||
* override if they which to use a custom executor implementation.
|
||||
* @param definitionLocator the definition locator to use
|
||||
* @param executionFactory the execution factory to use
|
||||
* @param executionRepository the execution repository to use
|
||||
* @return a new flow executor instance
|
||||
*/
|
||||
protected FlowExecutor createFlowExecutor(FlowDefinitionLocator definitionLocator,
|
||||
FlowExecutionFactory executionFactory, FlowExecutionRepository executionRepository) {
|
||||
FlowExecutorImpl flowExecutor = new FlowExecutorImpl(definitionLocator, executionFactory, executionRepository);
|
||||
if (getInputMapper() != null) {
|
||||
flowExecutor.setInputMapper(inputMapper);
|
||||
}
|
||||
return flowExecutor;
|
||||
}
|
||||
|
||||
// implementing FactoryBean
|
||||
|
||||
@@ -446,7 +414,7 @@ public class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
public Object getObject() throws Exception {
|
||||
return getFlowExecutor();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the flow executor constructed by the factory bean.
|
||||
* @since 1.0.2
|
||||
|
||||
@@ -23,9 +23,8 @@ import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.engine.support.ApplicationViewSelector;
|
||||
|
||||
/**
|
||||
* Encapsulates overall flow system configuration defaults. Allows for
|
||||
* centralized application of, and if necessary, overridding of system-wide
|
||||
* default values.
|
||||
* Encapsulates overall flow system configuration defaults. Allows for centralized application of, and if necessary,
|
||||
* overridding of system-wide default values.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -42,8 +41,7 @@ public class FlowSystemDefaults implements Serializable {
|
||||
private RepositoryType repositoryType = RepositoryType.CONTINUATION;
|
||||
|
||||
/**
|
||||
* Overrides the alwaysRedirectOnPause execution attribute default. Defaults
|
||||
* to "true".
|
||||
* Overrides the alwaysRedirectOnPause execution attribute default. Defaults to "true".
|
||||
* @param alwaysRedirectOnPause the new default value
|
||||
* @see ApplicationViewSelector#ALWAYS_REDIRECT_ON_PAUSE_ATTRIBUTE
|
||||
*/
|
||||
@@ -60,9 +58,8 @@ public class FlowSystemDefaults implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies default execution attributes if necessary. Defaults will only
|
||||
* apply in the case where the user did not configure a value, or explicitly
|
||||
* requested the 'default' value.
|
||||
* Applies default execution attributes if necessary. Defaults will only apply in the case where the user did not
|
||||
* configure a value, or explicitly requested the 'default' value.
|
||||
* @param executionAttributes the user-configured execution attribute map
|
||||
* @return the map with defaults applied as appropriate
|
||||
*/
|
||||
@@ -71,23 +68,21 @@ public class FlowSystemDefaults implements Serializable {
|
||||
executionAttributes = new LocalAttributeMap(1, 1);
|
||||
}
|
||||
if (!executionAttributes.contains(ApplicationViewSelector.ALWAYS_REDIRECT_ON_PAUSE_ATTRIBUTE)) {
|
||||
executionAttributes.put(ApplicationViewSelector.ALWAYS_REDIRECT_ON_PAUSE_ATTRIBUTE,
|
||||
new Boolean(alwaysRedirectOnPause));
|
||||
executionAttributes.put(ApplicationViewSelector.ALWAYS_REDIRECT_ON_PAUSE_ATTRIBUTE, new Boolean(
|
||||
alwaysRedirectOnPause));
|
||||
}
|
||||
return executionAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the default repository type if requested by the user.
|
||||
* @param selectedType the selected repository type (may be null if no
|
||||
* selection was made)
|
||||
* @param selectedType the selected repository type (may be null if no selection was made)
|
||||
* @return the repository type, with the default applied if necessary
|
||||
*/
|
||||
public RepositoryType applyIfNecessary(RepositoryType selectedType) {
|
||||
if (selectedType == null) {
|
||||
return repositoryType;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return selectedType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.w3c.dom.Element;
|
||||
* @author Ben Hale
|
||||
*/
|
||||
class RegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
|
||||
// elements and attributes
|
||||
|
||||
private static final String LOCATION_ELEMENT = "location";
|
||||
@@ -60,7 +60,7 @@ class RegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
private List getLocations(List locationElements) {
|
||||
List locations = new ArrayList(locationElements.size());
|
||||
for (Iterator i = locationElements.iterator(); i.hasNext();) {
|
||||
Element locationElement = (Element)i.next();
|
||||
Element locationElement = (Element) i.next();
|
||||
String path = locationElement.getAttribute(PATH_ATTRIBUTE);
|
||||
if (StringUtils.hasText(path)) {
|
||||
locations.add(path);
|
||||
|
||||
@@ -53,7 +53,7 @@ public class RepositoryType extends StaticLabeledEnum {
|
||||
* @see SimpleFlowExecutionRepository#setAlwaysGenerateNewNextKey(boolean)
|
||||
*/
|
||||
public static final RepositoryType SINGLEKEY = new RepositoryType(3, "Single Key");
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor because this is a typesafe enum!
|
||||
*/
|
||||
|
||||
@@ -21,17 +21,13 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
/**
|
||||
* <code>NamespaceHandler</code> for the <code>webflow-config</code> namespace.
|
||||
* <p>
|
||||
* Provides {@link BeanDefinitionParser bean definition parsers} for the
|
||||
* <code><executor></code> and <code><registry></code> tags. An
|
||||
* <code>executor</code> tag can include an <code>execution-listeners</code>
|
||||
* tag and a <code>registry</code> tag can include <code>location</code>
|
||||
* tags.
|
||||
* Provides {@link BeanDefinitionParser bean definition parsers} for the <code><executor></code> and
|
||||
* <code><registry></code> tags. An <code>executor</code> tag can include an <code>execution-listeners</code>
|
||||
* tag and a <code>registry</code> tag can include <code>location</code> tags.
|
||||
* <p>
|
||||
* Using the <code>executor</code> tag you can configure a
|
||||
* {@link FlowExecutorFactoryBean} that creates a
|
||||
* {@link org.springframework.webflow.executor.FlowExecutor}. The
|
||||
* <code>executor</code> tag allows you to specify the repository type and a
|
||||
* reference to a registry.
|
||||
* Using the <code>executor</code> tag you can configure a {@link FlowExecutorFactoryBean} that creates a
|
||||
* {@link org.springframework.webflow.executor.FlowExecutor}. The <code>executor</code> tag allows you to specify the
|
||||
* repository type and a reference to a registry.
|
||||
*
|
||||
* <pre class="code">
|
||||
* <flow:executor id="registry" registry-ref="registry" repository-type="continuation" >
|
||||
@@ -45,9 +41,8 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
*
|
||||
* <p>
|
||||
* Using the <code>registry</code> tag you can configure an
|
||||
* {@link org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean}
|
||||
* to create a registry for use by any number of <code>executor</code>s. The
|
||||
* <code>registry</code> tag supports in-line flow definition locations.
|
||||
* {@link org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean} to create a registry for use by any
|
||||
* number of <code>executor</code>s. The <code>registry</code> tag supports in-line flow definition locations.
|
||||
*
|
||||
* <pre class="code">
|
||||
* <flow:registry id="registry">
|
||||
|
||||
@@ -25,11 +25,11 @@ import org.springframework.webflow.execution.FlowExecutionContextHolder;
|
||||
import org.springframework.webflow.execution.FlowSession;
|
||||
|
||||
/**
|
||||
* Base class for {@link Scope} implementations that access a Web Flow scope
|
||||
* from the current thread-bound {@link FlowExecutionContext} object.
|
||||
* Base class for {@link Scope} implementations that access a Web Flow scope from the current thread-bound
|
||||
* {@link FlowExecutionContext} object.
|
||||
* <p>
|
||||
* Subclasses simply need to implement {@link #getScope()} to return the
|
||||
* {@link MutableAttributeMap scope map} to access.
|
||||
* Subclasses simply need to implement {@link #getScope()} to return the {@link MutableAttributeMap scope map} to
|
||||
* access.
|
||||
* <p>
|
||||
* Relies on a thread-bound
|
||||
* @{link FlowExecutionContext} instance located through the
|
||||
@@ -57,8 +57,7 @@ public abstract class AbstractWebFlowScope implements Scope {
|
||||
}
|
||||
scopedObject = objectFactory.getObject();
|
||||
scope.put(name, scopedObject);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning scoped instance '" + name + "'");
|
||||
}
|
||||
@@ -80,11 +79,10 @@ public abstract class AbstractWebFlowScope implements Scope {
|
||||
* @throws IllegalStateException if the scope could not be accessed
|
||||
*/
|
||||
protected abstract MutableAttributeMap getScope() throws IllegalStateException;
|
||||
|
||||
|
||||
/**
|
||||
* Always returns <code>null</code> as most Spring Web Flow scopes do not
|
||||
* have obvious conversation ids. Subclasses should override this method
|
||||
* where conversation ids can be intelligently returned.
|
||||
* Always returns <code>null</code> as most Spring Web Flow scopes do not have obvious conversation ids.
|
||||
* Subclasses should override this method where conversation ids can be intelligently returned.
|
||||
* @return always returns <code>null</code>
|
||||
*/
|
||||
public String getConversationId() {
|
||||
@@ -92,9 +90,8 @@ public abstract class AbstractWebFlowScope implements Scope {
|
||||
}
|
||||
|
||||
/**
|
||||
* Will not register a destruction callback as Spring Web Flow does not
|
||||
* support destruction of scoped beans. Subclasses should override this
|
||||
* method where where destruction can adequately be accomplished.
|
||||
* Will not register a destruction callback as Spring Web Flow does not support destruction of scoped beans.
|
||||
* Subclasses should override this method where where destruction can adequately be accomplished.
|
||||
* @param name the name of the bean to register the callback for
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
@@ -104,8 +101,8 @@ public abstract class AbstractWebFlowScope implements Scope {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current flow execution context. Used by subclasses to easily
|
||||
* get access to the thread-bound flow execution context.
|
||||
* Returns the current flow execution context. Used by subclasses to easily get access to the thread-bound flow
|
||||
* execution context.
|
||||
* @return the current thread-bound flow execution context
|
||||
* @throws IllegalStateException if the current flow execution context is not bound
|
||||
*/
|
||||
|
||||
@@ -20,18 +20,15 @@ import org.springframework.webflow.core.collection.ParameterMap;
|
||||
import org.springframework.webflow.core.collection.SharedAttributeMap;
|
||||
|
||||
/**
|
||||
* A facade that provides normalized access to an external system that has
|
||||
* interacted with Spring Web Flow.
|
||||
* A facade that provides normalized access to an external system that has interacted with Spring Web Flow.
|
||||
* <p>
|
||||
* This context object provides a normalized interface for internal web flow
|
||||
* artifacts to use to reason on and manipulate the state of an external actor
|
||||
* calling into SWF to execute flows. It represents the context about a single,
|
||||
* <i>external</i> client request to manipulate a flow execution.
|
||||
* This context object provides a normalized interface for internal web flow artifacts to use to reason on and
|
||||
* manipulate the state of an external actor calling into SWF to execute flows. It represents the context about a
|
||||
* single, <i>external</i> client request to manipulate a flow execution.
|
||||
* <p>
|
||||
* The design of this interface was inspired by JSF's own ExternalContext
|
||||
* abstraction and shares the same name for consistency. If a particular
|
||||
* external client type does not support all methods defined by this interface,
|
||||
* they can just be implemented as returning an empty map or <code>null</code>.
|
||||
* The design of this interface was inspired by JSF's own ExternalContext abstraction and shares the same name for
|
||||
* consistency. If a particular external client type does not support all methods defined by this interface, they can
|
||||
* just be implemented as returning an empty map or <code>null</code>.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -45,8 +42,7 @@ public interface ExternalContext {
|
||||
public String getContextPath();
|
||||
|
||||
/**
|
||||
* Returns the path (or identifier) of the dispatcher <i>within</i> the
|
||||
* application that dispatched this request.
|
||||
* Returns the path (or identifier) of the dispatcher <i>within</i> the application that dispatched this request.
|
||||
* @return the dispatcher path (e.g. "/dispatcher")
|
||||
*/
|
||||
public String getDispatcherPath();
|
||||
@@ -58,46 +54,40 @@ public interface ExternalContext {
|
||||
public String getRequestPathInfo();
|
||||
|
||||
/**
|
||||
* Provides access to the parameters associated with the user request that
|
||||
* led to SWF being called. This map is expected to be immutable and cannot
|
||||
* be changed.
|
||||
* Provides access to the parameters associated with the user request that led to SWF being called. This map is
|
||||
* expected to be immutable and cannot be changed.
|
||||
* @return the immutable request parameter map
|
||||
*/
|
||||
public ParameterMap getRequestParameterMap();
|
||||
|
||||
/**
|
||||
* Provides access to the external request attribute map, providing a
|
||||
* storage for data local to the current user request and accessible to both
|
||||
* internal and external SWF artifacts.
|
||||
* Provides access to the external request attribute map, providing a storage for data local to the current user
|
||||
* request and accessible to both internal and external SWF artifacts.
|
||||
* @return the mutable request attribute map
|
||||
*/
|
||||
public MutableAttributeMap getRequestMap();
|
||||
|
||||
/**
|
||||
* Provides access to the external session map, providing a storage for data
|
||||
* local to the current user session and accessible to both internal and
|
||||
* external SWF artifacts.
|
||||
* Provides access to the external session map, providing a storage for data local to the current user session and
|
||||
* accessible to both internal and external SWF artifacts.
|
||||
* @return the mutable session attribute map
|
||||
*/
|
||||
public SharedAttributeMap getSessionMap();
|
||||
|
||||
/**
|
||||
* Provides access to the <i>global</i> external session map, providing a storage for data
|
||||
* globally accross the user session and accessible to both internal and
|
||||
* external SWF artifacts.
|
||||
* Provides access to the <i>global</i> external session map, providing a storage for data globally accross the
|
||||
* user session and accessible to both internal and external SWF artifacts.
|
||||
* <p>
|
||||
* Note: most external context implementations do not distinguish between the concept of a
|
||||
* "local" user session scope and a "global" session scope. The Portlet world does, but
|
||||
* not the Servlet for example. In those cases calling this method returns the same
|
||||
* map as calling {@link #getSessionMap()}.
|
||||
* Note: most external context implementations do not distinguish between the concept of a "local" user session
|
||||
* scope and a "global" session scope. The Portlet world does, but not the Servlet for example. In those cases
|
||||
* calling this method returns the same map as calling {@link #getSessionMap()}.
|
||||
* @return the mutable global session attribute map
|
||||
*/
|
||||
public SharedAttributeMap getGlobalSessionMap();
|
||||
|
||||
|
||||
/**
|
||||
* Provides access to the external application map, providing a storage for
|
||||
* data local to the current user application and accessible to both
|
||||
* internal and external SWF artifacts.
|
||||
* Provides access to the external application map, providing a storage for data local to the current user
|
||||
* application and accessible to both internal and external SWF artifacts.
|
||||
* @return the mutable application attribute map
|
||||
*/
|
||||
public SharedAttributeMap getApplicationMap();
|
||||
|
||||
@@ -18,13 +18,11 @@ package org.springframework.webflow.context;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple holder class that associates an {@link ExternalContext} instance with
|
||||
* the current thread. The ExternalContext will not be inherited by any child
|
||||
* threads spawned by the current thread.
|
||||
* Simple holder class that associates an {@link ExternalContext} instance with the current thread. The ExternalContext
|
||||
* will not be inherited by any child threads spawned by the current thread.
|
||||
* <p>
|
||||
* Used as a central holder for the current ExternalContext in Spring Web Flow,
|
||||
* wherever necessary. Often used by artifacts needing access to the current
|
||||
* application session.
|
||||
* Used as a central holder for the current ExternalContext in Spring Web Flow, wherever necessary. Often used by
|
||||
* artifacts needing access to the current application session.
|
||||
*
|
||||
* @see ExternalContext
|
||||
*
|
||||
@@ -36,8 +34,7 @@ public final class ExternalContextHolder {
|
||||
|
||||
/**
|
||||
* Associate the given ExternalContext with the current thread.
|
||||
* @param externalContext the current ExternalContext, or <code>null</code>
|
||||
* to reset the thread-bound context
|
||||
* @param externalContext the current ExternalContext, or <code>null</code> to reset the thread-bound context
|
||||
*/
|
||||
public static void setExternalContext(ExternalContext externalContext) {
|
||||
externalContextHolder.set(externalContext);
|
||||
@@ -46,11 +43,11 @@ public final class ExternalContextHolder {
|
||||
/**
|
||||
* Return the ExternalContext associated with the current thread, if any.
|
||||
* @return the current ExternalContext
|
||||
* @throws IllegalStateException if no ExternalContext is bound to this thread
|
||||
* @throws IllegalStateException if no ExternalContext is bound to this thread
|
||||
*/
|
||||
public static ExternalContext getExternalContext() {
|
||||
Assert.state(externalContextHolder.get() != null, "No external context is bound to this thread");
|
||||
return (ExternalContext)externalContextHolder.get();
|
||||
return (ExternalContext) externalContextHolder.get();
|
||||
}
|
||||
|
||||
// not instantiable
|
||||
|
||||
@@ -24,8 +24,7 @@ import org.springframework.binding.collection.StringKeyedMapAdapter;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
|
||||
/**
|
||||
* A shared map backed by the Portlet context for accessing application scoped
|
||||
* attributes.
|
||||
* A shared map backed by the Portlet context for accessing application scoped attributes.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
|
||||
@@ -32,8 +32,7 @@ import org.springframework.webflow.core.collection.ParameterMap;
|
||||
import org.springframework.webflow.core.collection.SharedAttributeMap;
|
||||
|
||||
/**
|
||||
* Provides contextual information about a JSR-168 Portlet environment that has
|
||||
* called into Spring Web Flow.
|
||||
* Provides contextual information about a JSR-168 Portlet environment that has called into Spring Web Flow.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -53,7 +52,7 @@ public class PortletExternalContext implements ExternalContext {
|
||||
* The response.
|
||||
*/
|
||||
private PortletResponse response;
|
||||
|
||||
|
||||
/**
|
||||
* An accessor for the portlet request parameter map.
|
||||
*/
|
||||
@@ -78,7 +77,7 @@ public class PortletExternalContext implements ExternalContext {
|
||||
* An accessor for the portlet context application map.
|
||||
*/
|
||||
private SharedAttributeMap applicationMap;
|
||||
|
||||
|
||||
/**
|
||||
* An accessor for the portlet user info map.
|
||||
*/
|
||||
@@ -97,9 +96,10 @@ public class PortletExternalContext implements ExternalContext {
|
||||
this.requestParameterMap = new LocalParameterMap(new PortletRequestParameterMap(request));
|
||||
this.requestMap = new LocalAttributeMap(new PortletRequestMap(request));
|
||||
this.sessionMap = new LocalSharedAttributeMap(new PortletSessionMap(request, PortletSession.PORTLET_SCOPE));
|
||||
this.globalSessionMap = new LocalSharedAttributeMap(new PortletSessionMap(request, PortletSession.APPLICATION_SCOPE));
|
||||
this.globalSessionMap = new LocalSharedAttributeMap(new PortletSessionMap(request,
|
||||
PortletSession.APPLICATION_SCOPE));
|
||||
this.applicationMap = new LocalSharedAttributeMap(new PortletContextMap(context));
|
||||
Map userInfo = (Map)request.getAttribute(PortletRequest.USER_INFO);
|
||||
Map userInfo = (Map) request.getAttribute(PortletRequest.USER_INFO);
|
||||
this.userInfoMap = userInfo != null ? new LocalAttributeMap(userInfo) : null;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ public class PortletExternalContext implements ExternalContext {
|
||||
public MutableAttributeMap getRequestMap() {
|
||||
return requestMap;
|
||||
}
|
||||
|
||||
|
||||
public SharedAttributeMap getSessionMap() {
|
||||
return sessionMap;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ import org.springframework.web.portlet.multipart.MultipartActionRequest;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Map backed by the Portlet request parameter map for accessing request local
|
||||
* portlet parameters.
|
||||
* Map backed by the Portlet request parameter map for accessing request local portlet parameters.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -46,7 +45,7 @@ public class PortletRequestParameterMap extends StringKeyedMapAdapter {
|
||||
|
||||
protected Object getAttribute(String key) {
|
||||
if (request instanceof MultipartActionRequest) {
|
||||
MultipartActionRequest multipartRequest = (MultipartActionRequest)request;
|
||||
MultipartActionRequest multipartRequest = (MultipartActionRequest) request;
|
||||
Object data = multipartRequest.getFileMap().get(key);
|
||||
if (data != null) {
|
||||
return data;
|
||||
@@ -72,13 +71,12 @@ public class PortletRequestParameterMap extends StringKeyedMapAdapter {
|
||||
|
||||
protected Iterator getAttributeNames() {
|
||||
if (request instanceof MultipartActionRequest) {
|
||||
MultipartActionRequest multipartRequest = (MultipartActionRequest)request;
|
||||
MultipartActionRequest multipartRequest = (MultipartActionRequest) request;
|
||||
CompositeIterator iterator = new CompositeIterator();
|
||||
iterator.add(multipartRequest.getFileMap().keySet().iterator());
|
||||
iterator.add(CollectionUtils.toIterator(request.getParameterNames()));
|
||||
return iterator;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return CollectionUtils.toIterator(request.getParameterNames());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,7 @@ import org.springframework.webflow.core.collection.AttributeMapBindingListener;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Shared map backed by the Portlet session for accessing session scoped
|
||||
* attributes in a Portlet environment.
|
||||
* Shared map backed by the Portlet session for accessing session scoped attributes in a Portlet environment.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -41,16 +40,14 @@ public class PortletSessionMap extends StringKeyedMapAdapter implements SharedMa
|
||||
private PortletRequest request;
|
||||
|
||||
/**
|
||||
* The scope to access in the session, either APPLICATION (global) or
|
||||
* PORTLET.
|
||||
* The scope to access in the session, either APPLICATION (global) or PORTLET.
|
||||
*/
|
||||
private int scope;
|
||||
|
||||
/**
|
||||
* Create a new map wrapping the session associated with given request.
|
||||
* @param request the current portlet request
|
||||
* @param scope the scope to access in the session, either
|
||||
* {@link PortletSession#APPLICATION_SCOPE} (global) or
|
||||
* @param scope the scope to access in the session, either {@link PortletSession#APPLICATION_SCOPE} (global) or
|
||||
* {@link PortletSession#PORTLET_SCOPE}
|
||||
*/
|
||||
public PortletSessionMap(PortletRequest request, int scope) {
|
||||
@@ -59,8 +56,7 @@ public class PortletSessionMap extends StringKeyedMapAdapter implements SharedMa
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the portlet session associated with the wrapped request, or null
|
||||
* if no such session exits.
|
||||
* Return the portlet session associated with the wrapped request, or null if no such session exits.
|
||||
*/
|
||||
private PortletSession getSession() {
|
||||
return request.getPortletSession(false);
|
||||
@@ -74,7 +70,7 @@ public class PortletSessionMap extends StringKeyedMapAdapter implements SharedMa
|
||||
Object value = session.getAttribute(key, scope);
|
||||
if (value instanceof HttpSessionMapBindingListener) {
|
||||
// unwrap
|
||||
return ((HttpSessionMapBindingListener)value).getListener();
|
||||
return ((HttpSessionMapBindingListener) value).getListener();
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
@@ -84,9 +80,9 @@ public class PortletSessionMap extends StringKeyedMapAdapter implements SharedMa
|
||||
PortletSession session = request.getPortletSession(true);
|
||||
if (value instanceof AttributeMapBindingListener) {
|
||||
// wrap
|
||||
session.setAttribute(key, new HttpSessionMapBindingListener((AttributeMapBindingListener)value, this), scope);
|
||||
}
|
||||
else {
|
||||
session.setAttribute(key, new HttpSessionMapBindingListener((AttributeMapBindingListener) value, this),
|
||||
scope);
|
||||
} else {
|
||||
session.setAttribute(key, value, scope);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ import org.springframework.binding.collection.StringKeyedMapAdapter;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Map backed by the Servlet context for accessing application scoped
|
||||
* attributes.
|
||||
* Map backed by the Servlet context for accessing application scoped attributes.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
|
||||
@@ -23,8 +23,7 @@ import org.springframework.binding.collection.StringKeyedMapAdapter;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Map backed by the Servlet HTTP request attribute map for accessing request
|
||||
* local attributes.
|
||||
* Map backed by the Servlet HTTP request attribute map for accessing request local attributes.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
|
||||
@@ -25,9 +25,8 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Map backed by the Servlet HTTP request parameter map for accessing request
|
||||
* parameters. Also provides support for multi-part requests, providing
|
||||
* transparent access to the request "fileMap" as a request parameter entry.
|
||||
* Map backed by the Servlet HTTP request parameter map for accessing request parameters. Also provides support for
|
||||
* multi-part requests, providing transparent access to the request "fileMap" as a request parameter entry.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -47,7 +46,7 @@ public class HttpServletRequestParameterMap extends StringKeyedMapAdapter {
|
||||
|
||||
protected Object getAttribute(String key) {
|
||||
if (request instanceof MultipartHttpServletRequest) {
|
||||
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
|
||||
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
||||
Object data = multipartRequest.getFileMap().get(key);
|
||||
if (data != null) {
|
||||
return data;
|
||||
@@ -73,13 +72,12 @@ public class HttpServletRequestParameterMap extends StringKeyedMapAdapter {
|
||||
|
||||
protected Iterator getAttributeNames() {
|
||||
if (request instanceof MultipartHttpServletRequest) {
|
||||
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
|
||||
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
||||
CompositeIterator iterator = new CompositeIterator();
|
||||
iterator.add(multipartRequest.getFileMap().keySet().iterator());
|
||||
iterator.add(CollectionUtils.toIterator(request.getParameterNames()));
|
||||
return iterator;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return CollectionUtils.toIterator(request.getParameterNames());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,7 @@ import org.springframework.webflow.core.collection.AttributeMapBindingListener;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
|
||||
/**
|
||||
* A Shared Map backed by the Servlet HTTP session, for accessing session scoped
|
||||
* attributes.
|
||||
* A Shared Map backed by the Servlet HTTP session, for accessing session scoped attributes.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -47,8 +46,7 @@ public class HttpSessionMap extends StringKeyedMapAdapter implements SharedMap {
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper to get the HTTP session associated with the wrapped
|
||||
* request, or null if there is no such session.
|
||||
* Internal helper to get the HTTP session associated with the wrapped request, or null if there is no such session.
|
||||
* <p>
|
||||
* Note that this method will not force session creation.
|
||||
*/
|
||||
@@ -64,7 +62,7 @@ public class HttpSessionMap extends StringKeyedMapAdapter implements SharedMap {
|
||||
Object value = session.getAttribute(key);
|
||||
if (value instanceof HttpSessionMapBindingListener) {
|
||||
// unwrap
|
||||
return ((HttpSessionMapBindingListener)value).getListener();
|
||||
return ((HttpSessionMapBindingListener) value).getListener();
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
@@ -75,10 +73,8 @@ public class HttpSessionMap extends StringKeyedMapAdapter implements SharedMap {
|
||||
HttpSession session = request.getSession(true);
|
||||
if (value instanceof AttributeMapBindingListener) {
|
||||
// wrap
|
||||
session.setAttribute(key,
|
||||
new HttpSessionMapBindingListener((AttributeMapBindingListener)value, this));
|
||||
}
|
||||
else {
|
||||
session.setAttribute(key, new HttpSessionMapBindingListener((AttributeMapBindingListener) value, this));
|
||||
} else {
|
||||
session.setAttribute(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,8 @@ import org.springframework.webflow.core.collection.AttributeMapBindingListener;
|
||||
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
||||
|
||||
/**
|
||||
* Helper class that adapts a generic {@link AttributeMapBindingListener} to a
|
||||
* HTTP specific {@link HttpSessionBindingListener}. Calls will be forwarded to
|
||||
* the wrapped listener.
|
||||
* Helper class that adapts a generic {@link AttributeMapBindingListener} to a HTTP specific
|
||||
* {@link HttpSessionBindingListener}. Calls will be forwarded to the wrapped listener.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -70,8 +69,7 @@ public class HttpSessionMapBindingListener implements HttpSessionBindingListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a attribute map binding event for given HTTP session binding
|
||||
* event.
|
||||
* Create a attribute map binding event for given HTTP session binding event.
|
||||
*/
|
||||
private AttributeMapBindingEvent getContextBindingEvent(HttpSessionBindingEvent event) {
|
||||
return new AttributeMapBindingEvent(new LocalAttributeMap(sessionMap), event.getName(), listener);
|
||||
|
||||
@@ -16,18 +16,15 @@
|
||||
package org.springframework.webflow.conversation;
|
||||
|
||||
/**
|
||||
* A service interface for working with state associated with a single logical
|
||||
* user interaction called a "conversation" in the scope of a single request.
|
||||
* Conversation objects are not thread safe and should not be shared among
|
||||
* multiple threads.
|
||||
* A service interface for working with state associated with a single logical user interaction called a "conversation"
|
||||
* in the scope of a single request. Conversation objects are not thread safe and should not be shared among multiple
|
||||
* threads.
|
||||
* <p>
|
||||
* A conversation provides a "task" context that is begun and eventually ends.
|
||||
* Between the beginning and the end attributes can be placed in and read from a
|
||||
* conversation's context.
|
||||
* A conversation provides a "task" context that is begun and eventually ends. Between the beginning and the end
|
||||
* attributes can be placed in and read from a conversation's context.
|
||||
* <p>
|
||||
* A conversation needs to be {@link #lock() locked} to obtain exclusive
|
||||
* access to it before it can be manipulated. Once manipulation is finished, you need to
|
||||
* {@link #unlock() unlock} the conversation. So code interacting with a
|
||||
* A conversation needs to be {@link #lock() locked} to obtain exclusive access to it before it can be manipulated. Once
|
||||
* manipulation is finished, you need to {@link #unlock() unlock} the conversation. So code interacting with a
|
||||
* conversation always looks like this:
|
||||
*
|
||||
* <pre>
|
||||
@@ -43,10 +40,8 @@ package org.springframework.webflow.conversation;
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that the attributes associated with a conversation are not
|
||||
* "conversation scope" as defined for a flow execution. They can be
|
||||
* any attributes, possibly technical in nature, associated with the
|
||||
* conversation.
|
||||
* Note that the attributes associated with a conversation are not "conversation scope" as defined for a flow execution.
|
||||
* They can be any attributes, possibly technical in nature, associated with the conversation.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -54,52 +49,47 @@ package org.springframework.webflow.conversation;
|
||||
public interface Conversation {
|
||||
|
||||
/**
|
||||
* Returns the unique id assigned to this conversation. This id remains the
|
||||
* same throughout the life of the conversation. This method can be safely
|
||||
* called without owning the lock of this conversation.
|
||||
* Returns the unique id assigned to this conversation. This id remains the same throughout the life of the
|
||||
* conversation. This method can be safely called without owning the lock of this conversation.
|
||||
* @return the conversation id
|
||||
*/
|
||||
public ConversationId getId();
|
||||
|
||||
/**
|
||||
* Lock this conversation. May block until the lock is available, if someone
|
||||
* else has acquired the lock.
|
||||
* Lock this conversation. May block until the lock is available, if someone else has acquired the lock.
|
||||
*/
|
||||
public void lock();
|
||||
|
||||
/**
|
||||
* Returns the conversation attribute with the specified name.
|
||||
* You need to aquire the lock on this conversation before calling this method.
|
||||
* Returns the conversation attribute with the specified name. You need to aquire the lock on this conversation
|
||||
* before calling this method.
|
||||
* @param name the attribute name
|
||||
* @return the attribute value
|
||||
*/
|
||||
public Object getAttribute(Object name);
|
||||
|
||||
/**
|
||||
* Puts a conversation attribute into this context.
|
||||
* You need to aquire the lock on this conversation before calling this method.
|
||||
* Puts a conversation attribute into this context. You need to aquire the lock on this conversation before calling
|
||||
* this method.
|
||||
* @param name the attribute name
|
||||
* @param value the attribute value
|
||||
*/
|
||||
public void putAttribute(Object name, Object value);
|
||||
|
||||
/**
|
||||
* Removes a conversation attribute.
|
||||
* You need to aquire the lock on this conversation before calling this method.
|
||||
* Removes a conversation attribute. You need to aquire the lock on this conversation before calling this method.
|
||||
* @param name the attribute name
|
||||
*/
|
||||
public void removeAttribute(Object name);
|
||||
|
||||
/**
|
||||
* Ends this conversation. This method should only be called once to
|
||||
* terminate the conversation and cleanup any allocated resources.
|
||||
* You need to aquire the lock on this conversation before calling this method.
|
||||
* Ends this conversation. This method should only be called once to terminate the conversation and cleanup any
|
||||
* allocated resources. You need to aquire the lock on this conversation before calling this method.
|
||||
*/
|
||||
public void end();
|
||||
|
||||
/**
|
||||
* Unlock this conversation, making it available to others for
|
||||
* manipulation.
|
||||
* Unlock this conversation, making it available to others for manipulation.
|
||||
*/
|
||||
public void unlock();
|
||||
}
|
||||
@@ -18,8 +18,7 @@ package org.springframework.webflow.conversation;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An id that uniquely identifies a conversation managed by a
|
||||
* {@link ConversationManager}.
|
||||
* An id that uniquely identifies a conversation managed by a {@link ConversationManager}.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @author Keith Donald
|
||||
@@ -27,8 +26,7 @@ import java.io.Serializable;
|
||||
public abstract class ConversationId implements Serializable {
|
||||
|
||||
/**
|
||||
* Subclasses should override toString to return a parseable string form of
|
||||
* the key.
|
||||
* Subclasses should override toString to return a parseable string form of the key.
|
||||
* @see java.lang.Object#toString()
|
||||
* @see ConversationManager#parseConversationId(String)
|
||||
*/
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
package org.springframework.webflow.conversation;
|
||||
|
||||
/**
|
||||
* A service for managing conversations. This interface is the entry point into
|
||||
* the conversation subsystem.
|
||||
* A service for managing conversations. This interface is the entry point into the conversation subsystem.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -35,12 +34,11 @@ public interface ConversationManager {
|
||||
/**
|
||||
* Get the conversation with the provided id.
|
||||
* <p>
|
||||
* Implementors should take care to manage conversation identity correctly.
|
||||
* Although it is not strictly required to return the same (==) Conversation
|
||||
* object every time this method is called with a particular conversation
|
||||
* id in a single execution thread, callers will expect to recieve an object
|
||||
* that allows them to manipulate the identified conversation. In other words,
|
||||
* the following is legal ConversationManager client code:
|
||||
* Implementors should take care to manage conversation identity correctly. Although it is not strictly required to
|
||||
* return the same (==) Conversation object every time this method is called with a particular conversation id in a
|
||||
* single execution thread, callers will expect to recieve an object that allows them to manipulate the identified
|
||||
* conversation. In other words, the following is legal ConversationManager client code:
|
||||
*
|
||||
* <pre>
|
||||
* ConversationManager manager = ...;
|
||||
* ConversationId id = ...;
|
||||
@@ -50,13 +48,14 @@ public interface ConversationManager {
|
||||
* Conversation localReference = manager.getConversation(id);
|
||||
* // no need to lock since conversation 'id' is already locked
|
||||
* // even though possibly conv != localReference
|
||||
* localReference.putAttribute("foo", "bar");
|
||||
* Object foo = conv.getAttribute("foo");
|
||||
* localReference.putAttribute("foo", "bar");
|
||||
* Object foo = conv.getAttribute("foo");
|
||||
* }
|
||||
* finally {
|
||||
* conv.unlock();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param id the conversation id
|
||||
* @return the conversation
|
||||
* @throws NoSuchConversationException the id provided was invalid
|
||||
@@ -64,8 +63,8 @@ public interface ConversationManager {
|
||||
public Conversation getConversation(ConversationId id) throws ConversationException;
|
||||
|
||||
/**
|
||||
* Parse the string-encoded conversationId into its object form.
|
||||
* Essentially, the reverse of {@link ConversationId#toString()}.
|
||||
* Parse the string-encoded conversationId into its object form. Essentially, the reverse of
|
||||
* {@link ConversationId#toString()}.
|
||||
* @param encodedId the encoded id
|
||||
* @return the parsed conversation id
|
||||
* @throws ConversationException an exception occured parsing the id
|
||||
|
||||
@@ -20,8 +20,7 @@ import java.io.Serializable;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* Simple parameter object for clumping together input needed to begin a new
|
||||
* conversation.
|
||||
* Simple parameter object for clumping together input needed to begin a new conversation.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -77,7 +76,7 @@ public class ConversationParameters implements Serializable {
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("name", name).toString();
|
||||
}
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
package org.springframework.webflow.conversation;
|
||||
|
||||
/**
|
||||
* Thrown when no logical conversation exists with the specified
|
||||
* <code>conversationId</code>. This might occur if the conversation ended,
|
||||
* expired, or was otherwise invalidated, but a client view still references it.
|
||||
* Thrown when no logical conversation exists with the specified <code>conversationId</code>. This might occur if the
|
||||
* conversation ended, expired, or was otherwise invalidated, but a client view still references it.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
|
||||
@@ -30,8 +30,7 @@ import org.springframework.webflow.conversation.ConversationId;
|
||||
import org.springframework.webflow.core.collection.SharedAttributeMap;
|
||||
|
||||
/**
|
||||
* Internal {@link Conversation} implementation used by the conversation
|
||||
* container.
|
||||
* Internal {@link Conversation} implementation used by the conversation container.
|
||||
* <p>
|
||||
* This is an internal helper class of the {@link SessionBindingConversationManager}.
|
||||
*
|
||||
@@ -68,7 +67,7 @@ class ContainedConversation implements Conversation, Serializable {
|
||||
public void lock() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Locking conversation " + id);
|
||||
}
|
||||
}
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
@@ -79,21 +78,21 @@ class ContainedConversation implements Conversation, Serializable {
|
||||
public void putAttribute(Object name, Object value) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Putting conversation attribute '" + name + "' with value " + value);
|
||||
}
|
||||
}
|
||||
attributes.put(name, value);
|
||||
}
|
||||
|
||||
public void removeAttribute(Object name) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Removing conversation attribute '" + name + "'");
|
||||
}
|
||||
}
|
||||
attributes.remove(name);
|
||||
}
|
||||
|
||||
public void end() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Ending conversation " + id);
|
||||
}
|
||||
}
|
||||
container.removeConversation(getId());
|
||||
}
|
||||
|
||||
@@ -102,7 +101,7 @@ class ContainedConversation implements Conversation, Serializable {
|
||||
logger.debug("Unlocking conversation " + id);
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
|
||||
// re-bind the conversation container in the session
|
||||
// this is required to make session replication work correctly in
|
||||
// a clustered environment
|
||||
@@ -124,7 +123,7 @@ class ContainedConversation implements Conversation, Serializable {
|
||||
if (!(obj instanceof ContainedConversation)) {
|
||||
return false;
|
||||
}
|
||||
return id.equals(((ContainedConversation)obj).id);
|
||||
return id.equals(((ContainedConversation) obj).id);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
|
||||
@@ -26,22 +26,20 @@ import org.springframework.webflow.conversation.ConversationParameters;
|
||||
import org.springframework.webflow.conversation.NoSuchConversationException;
|
||||
|
||||
/**
|
||||
* Container for conversations that is stored in the session. When the
|
||||
* session expires this container will go with it, implicitly expiring all
|
||||
* contained conversations.
|
||||
* Container for conversations that is stored in the session. When the session expires this container will go with it,
|
||||
* implicitly expiring all contained conversations.
|
||||
* <p>
|
||||
* This is an internal helper class of the {@link SessionBindingConversationManager}.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
class ConversationContainer implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* Maximum number of conversations in this container. -1 for
|
||||
* unlimited.
|
||||
* Maximum number of conversations in this container. -1 for unlimited.
|
||||
*/
|
||||
private int maxConversations;
|
||||
|
||||
|
||||
/**
|
||||
* The key of this conversation container in the session.
|
||||
*/
|
||||
@@ -54,8 +52,7 @@ class ConversationContainer implements Serializable {
|
||||
|
||||
/**
|
||||
* Create a new conversation container.
|
||||
* @param maxConversations the maximum number of allowed concurrent
|
||||
* conversations, -1 for unlimited
|
||||
* @param maxConversations the maximum number of allowed concurrent conversations, -1 for unlimited
|
||||
* @param sessionKey the key of this conversation container in the session
|
||||
*/
|
||||
public ConversationContainer(int maxConversations, String sessionKey) {
|
||||
@@ -63,26 +60,23 @@ class ConversationContainer implements Serializable {
|
||||
this.sessionKey = sessionKey;
|
||||
this.conversations = new ArrayList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the key of this conversation container in the session.
|
||||
* For package level use only.
|
||||
* Returns the key of this conversation container in the session. For package level use only.
|
||||
*/
|
||||
String getSessionKey() {
|
||||
return sessionKey;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current size of the conversation container: the number
|
||||
* of conversations contained within it.
|
||||
* Returns the current size of the conversation container: the number of conversations contained within it.
|
||||
*/
|
||||
public int size() {
|
||||
return conversations.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new conversation based on given parameters and add it to the
|
||||
* container.
|
||||
* Create a new conversation based on given parameters and add it to the container.
|
||||
* @param id the unique id of the conversation
|
||||
* @param parameters descriptive parameters
|
||||
* @return the created conversation
|
||||
@@ -92,7 +86,7 @@ class ConversationContainer implements Serializable {
|
||||
conversations.add(conversation);
|
||||
if (maxExceeded()) {
|
||||
// end oldest conversation
|
||||
((Conversation)conversations.get(0)).end();
|
||||
((Conversation) conversations.get(0)).end();
|
||||
}
|
||||
return conversation;
|
||||
}
|
||||
@@ -101,12 +95,11 @@ class ConversationContainer implements Serializable {
|
||||
* Return the identified conversation.
|
||||
* @param id the id to lookup
|
||||
* @return the conversation
|
||||
* @throws NoSuchConversationException if the conversation cannot be
|
||||
* found
|
||||
* @throws NoSuchConversationException if the conversation cannot be found
|
||||
*/
|
||||
public synchronized Conversation getConversation(ConversationId id) throws NoSuchConversationException {
|
||||
for (Iterator it = conversations.iterator(); it.hasNext();) {
|
||||
ContainedConversation conversation = (ContainedConversation)it.next();
|
||||
ContainedConversation conversation = (ContainedConversation) it.next();
|
||||
if (conversation.getId().equals(id)) {
|
||||
return conversation;
|
||||
}
|
||||
@@ -119,7 +112,7 @@ class ConversationContainer implements Serializable {
|
||||
*/
|
||||
public synchronized void removeConversation(ConversationId id) {
|
||||
for (Iterator it = conversations.iterator(); it.hasNext();) {
|
||||
ContainedConversation conversation = (ContainedConversation)it.next();
|
||||
ContainedConversation conversation = (ContainedConversation) it.next();
|
||||
if (conversation.getId().equals(id)) {
|
||||
it.remove();
|
||||
break;
|
||||
@@ -128,8 +121,7 @@ class ConversationContainer implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the maximum number of allowed concurrent conversations in the
|
||||
* session been exceeded?
|
||||
* Has the maximum number of allowed concurrent conversations in the session been exceeded?
|
||||
*/
|
||||
private boolean maxExceeded() {
|
||||
return maxConversations > 0 && conversations.size() > maxConversations;
|
||||
|
||||
@@ -16,15 +16,14 @@
|
||||
package org.springframework.webflow.conversation.impl;
|
||||
|
||||
/**
|
||||
* A normalized interface for conversation locks, used to obtain exclusive
|
||||
* access to a conversation.
|
||||
* A normalized interface for conversation locks, used to obtain exclusive access to a conversation.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ConversationLock {
|
||||
|
||||
|
||||
/**
|
||||
* Acquire the conversation lock.
|
||||
* Acquire the conversation lock.
|
||||
*/
|
||||
public void lock();
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.JdkVersion;
|
||||
|
||||
/**
|
||||
* Simple utility class for creating conversation lock instances based on the
|
||||
* current execution environment.
|
||||
* Simple utility class for creating conversation lock instances based on the current execution environment.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Rob Harrop
|
||||
@@ -36,25 +35,21 @@ public class ConversationLockFactory {
|
||||
try {
|
||||
Class.forName("EDU.oswego.cs.dl.util.concurrent.ReentrantLock");
|
||||
utilConcurrentPresent = true;
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
} catch (ClassNotFoundException ex) {
|
||||
utilConcurrentPresent = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When running on Java 1.5+, returns a jdk5 concurrent lock. When running on older JDKs with
|
||||
* the 'util.concurrent' package available, returns a util concurrent lock.
|
||||
* In all other cases a "no-op" lock is returned.
|
||||
* When running on Java 1.5+, returns a jdk5 concurrent lock. When running on older JDKs with the 'util.concurrent'
|
||||
* package available, returns a util concurrent lock. In all other cases a "no-op" lock is returned.
|
||||
*/
|
||||
public static ConversationLock createLock() {
|
||||
if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15) {
|
||||
return new JdkConcurrentConversationLock();
|
||||
}
|
||||
else if (utilConcurrentPresent) {
|
||||
} else if (utilConcurrentPresent) {
|
||||
return new UtilConcurrentConversationLock();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logger.warn("Unable to enable conversation locking. Switch to Java 5 or above, "
|
||||
+ "or put the 'util.concurrent' package on the classpath "
|
||||
+ "to enable locking in your environment.");
|
||||
|
||||
@@ -20,8 +20,8 @@ import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* A conversation lock that relies on a {@link ReentrantLock} within Java 5's
|
||||
* <code>util.concurrent.locks</code> package.
|
||||
* A conversation lock that relies on a {@link ReentrantLock} within Java 5's <code>util.concurrent.locks</code>
|
||||
* package.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
|
||||
@@ -19,8 +19,8 @@ import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A singleton lock that doesn't do anything. For use when conversations don't
|
||||
* require or choose not to implement locking.
|
||||
* A singleton lock that doesn't do anything. For use when conversations don't require or choose not to implement
|
||||
* locking.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
|
||||
@@ -29,16 +29,13 @@ import org.springframework.webflow.util.RandomGuidUidGenerator;
|
||||
import org.springframework.webflow.util.UidGenerator;
|
||||
|
||||
/**
|
||||
* Simple implementation of a conversation manager that stores conversations in
|
||||
* the session attribute map.
|
||||
* Simple implementation of a conversation manager that stores conversations in the session attribute map.
|
||||
* <p>
|
||||
* Using the {@link #setMaxConversations(int) maxConversations} property, you can
|
||||
* limit the number of concurrently active conversations allowed in a single
|
||||
* session. If the maximum is exceeded, the conversation manager will automatically
|
||||
* end the oldest conversation. The default is 5, which should be fine for most
|
||||
* situations. Set it to -1 for no limit. Setting maxConversations to 1 allows
|
||||
* easy resource cleanup in situations where there should only be one active
|
||||
* conversation per session.
|
||||
* Using the {@link #setMaxConversations(int) maxConversations} property, you can limit the number of concurrently
|
||||
* active conversations allowed in a single session. If the maximum is exceeded, the conversation manager will
|
||||
* automatically end the oldest conversation. The default is 5, which should be fine for most situations. Set it to -1
|
||||
* for no limit. Setting maxConversations to 1 allows easy resource cleanup in situations where there should only be one
|
||||
* active conversation per session.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
@@ -47,26 +44,24 @@ public class SessionBindingConversationManager implements ConversationManager {
|
||||
private static final Log logger = LogFactory.getLog(SessionBindingConversationManager.class);
|
||||
|
||||
/**
|
||||
* Generate a unique key for the session attribute holding the conversation
|
||||
* container managed by this conversation manager.
|
||||
* Generate a unique key for the session attribute holding the conversation container managed by this conversation
|
||||
* manager.
|
||||
*/
|
||||
private final String sessionKey = "webflow.conversation.container." + new RandomGuid().toString();
|
||||
|
||||
|
||||
/**
|
||||
* The conversation uid generation strategy to use.
|
||||
*/
|
||||
private UidGenerator conversationIdGenerator = new RandomGuidUidGenerator();
|
||||
|
||||
/**
|
||||
* The maximum number of active conversations allowed in a session.
|
||||
* The default is 5. This is high enough for most practical situations and low enough
|
||||
* to avoid excessive resource usage or easy denial of service attacks.
|
||||
* The maximum number of active conversations allowed in a session. The default is 5. This is high enough for most
|
||||
* practical situations and low enough to avoid excessive resource usage or easy denial of service attacks.
|
||||
*/
|
||||
private int maxConversations = 5;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the used generator for conversation ids. Defaults to
|
||||
* {@link RandomGuidUidGenerator}.
|
||||
* Returns the used generator for conversation ids. Defaults to {@link RandomGuidUidGenerator}.
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public UidGenerator getConversationIdGenerator() {
|
||||
@@ -79,10 +74,9 @@ public class SessionBindingConversationManager implements ConversationManager {
|
||||
public void setConversationIdGenerator(UidGenerator uidGenerator) {
|
||||
this.conversationIdGenerator = uidGenerator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the maximum number of allowed concurrent conversations. The
|
||||
* default is 5.
|
||||
* Returns the maximum number of allowed concurrent conversations. The default is 5.
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public int getMaxConversations() {
|
||||
@@ -90,16 +84,15 @@ public class SessionBindingConversationManager implements ConversationManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of allowed concurrent conversations. Set to -1 for
|
||||
* no limit. The default is 5.
|
||||
* Set the maximum number of allowed concurrent conversations. Set to -1 for no limit. The default is 5.
|
||||
*/
|
||||
public void setMaxConversations(int maxConversations) {
|
||||
this.maxConversations = maxConversations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the key this conversation manager uses to store conversation
|
||||
* data in the session. The key is unique for this conversation manager instance.
|
||||
* Returns the key this conversation manager uses to store conversation data in the session. The key is unique for
|
||||
* this conversation manager instance.
|
||||
* @return the session key
|
||||
*/
|
||||
public String getSessionKey() {
|
||||
@@ -109,9 +102,9 @@ public class SessionBindingConversationManager implements ConversationManager {
|
||||
public Conversation beginConversation(ConversationParameters conversationParameters) throws ConversationException {
|
||||
ConversationId conversationId = new SimpleConversationId(conversationIdGenerator.generateUid());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Beginning conversation " + conversationParameters +
|
||||
"; unique conversation id = " + conversationId);
|
||||
}
|
||||
logger.debug("Beginning conversation " + conversationParameters + "; unique conversation id = "
|
||||
+ conversationId);
|
||||
}
|
||||
return getConversationContainer().createAndAddConversation(conversationId, conversationParameters);
|
||||
}
|
||||
|
||||
@@ -129,14 +122,13 @@ public class SessionBindingConversationManager implements ConversationManager {
|
||||
// internal helpers
|
||||
|
||||
/**
|
||||
* Obtain the conversation container from the session. Create a new empty
|
||||
* container and add it to the session if no existing container can be
|
||||
* found.
|
||||
* Obtain the conversation container from the session. Create a new empty container and add it to the session if no
|
||||
* existing container can be found.
|
||||
*/
|
||||
private ConversationContainer getConversationContainer() {
|
||||
SharedAttributeMap sessionMap = ExternalContextHolder.getExternalContext().getSessionMap();
|
||||
synchronized (sessionMap.getMutex()) {
|
||||
ConversationContainer container = (ConversationContainer)sessionMap.get(sessionKey);
|
||||
ConversationContainer container = (ConversationContainer) sessionMap.get(sessionKey);
|
||||
if (container == null) {
|
||||
container = new ConversationContainer(maxConversations, sessionKey);
|
||||
sessionMap.put(sessionKey, container);
|
||||
|
||||
@@ -21,8 +21,7 @@ import org.springframework.webflow.conversation.ConversationId;
|
||||
import org.springframework.webflow.conversation.ConversationManager;
|
||||
|
||||
/**
|
||||
* An id that uniquely identifies a conversation managed by a
|
||||
* {@link ConversationManager}.
|
||||
* An id that uniquely identifies a conversation managed by a {@link ConversationManager}.
|
||||
* <p>
|
||||
* This key consists of a unique string that is typically a GUID.
|
||||
*
|
||||
@@ -47,7 +46,7 @@ public class SimpleConversationId extends ConversationId {
|
||||
if (!(o instanceof SimpleConversationId)) {
|
||||
return false;
|
||||
}
|
||||
return id.equals(((SimpleConversationId)o).id);
|
||||
return id.equals(((SimpleConversationId) o).id);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
|
||||
@@ -15,16 +15,15 @@
|
||||
*/
|
||||
package org.springframework.webflow.conversation.impl;
|
||||
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
import EDU.oswego.cs.dl.util.concurrent.ReentrantLock;
|
||||
|
||||
/**
|
||||
* A conversation lock that relies on a {@link ReentrantLock} within Doug Lea's
|
||||
* <a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html">util.concurrent</a>
|
||||
* package. For use on JDK 1.3 and 1.4.
|
||||
*
|
||||
* A conversation lock that relies on a {@link ReentrantLock} within Doug Lea's <a
|
||||
* href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html">util.concurrent</a> package.
|
||||
* For use on JDK 1.3 and 1.4.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Rob Harrop
|
||||
*/
|
||||
@@ -42,8 +41,7 @@ class UtilConcurrentConversationLock implements ConversationLock {
|
||||
public void lock() {
|
||||
try {
|
||||
lock.acquire();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
} catch (InterruptedException e) {
|
||||
throw new SystemInterruptedException("Unable to acquire lock.", e);
|
||||
}
|
||||
}
|
||||
@@ -54,11 +52,10 @@ class UtilConcurrentConversationLock implements ConversationLock {
|
||||
public void unlock() {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <code>Exception</code> indicating that some {@link Thread} was
|
||||
* {@link Thread#interrupt() interrupted} during processing and as
|
||||
* such processing was halted.
|
||||
* <code>Exception</code> indicating that some {@link Thread} was {@link Thread#interrupt() interrupted} during
|
||||
* processing and as such processing was halted.
|
||||
* <p>
|
||||
* Only used to wrap the checked {@link InterruptedException java.lang.InterruptedException}.
|
||||
*/
|
||||
|
||||
@@ -24,7 +24,8 @@ import org.springframework.binding.expression.SettableExpression;
|
||||
* Static helper factory that creates instances of the default expression parser used by Spring Web Flow when requested.
|
||||
* Marked final with a private constructor to prevent subclassing.
|
||||
* <p>
|
||||
* The default is an OGNL based expression parser. Also asserts that OGNL is in the classpath the first time the parser is used.
|
||||
* The default is an OGNL based expression parser. Also asserts that OGNL is in the classpath the first time the parser
|
||||
* is used.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -83,14 +84,12 @@ public final class DefaultExpressionParserFactory {
|
||||
try {
|
||||
Class.forName("ognl.Ognl");
|
||||
return new WebFlowOgnlExpressionParser();
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to load the default expression parser: OGNL could not be found in the classpath. "
|
||||
+ "Please add OGNL 2.x to your classpath or set the default ExpressionParser instance to something that is in the classpath. "
|
||||
+ "Details: " + e.getMessage());
|
||||
}
|
||||
catch (NoClassDefFoundError e) {
|
||||
} catch (NoClassDefFoundError e) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to construct the default expression parser: ognl.Ognl could not be instantiated. "
|
||||
+ "Please add OGNL 2.x to your classpath or set the default ExpressionParser instance to something that is in the classpath. "
|
||||
|
||||
@@ -18,8 +18,8 @@ package org.springframework.webflow.core;
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Root class for exceptions thrown by the Spring Web Flow system. All other
|
||||
* exceptions within the system should be assignable to this class.
|
||||
* Root class for exceptions thrown by the Spring Web Flow system. All other exceptions within the system should be
|
||||
* assignable to this class.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
|
||||
@@ -25,8 +25,7 @@ import org.springframework.binding.expression.ognl.OgnlExpressionParser;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
|
||||
/**
|
||||
* An extension of {@link OgnlExpressionParser} that registers web flow specific
|
||||
* property accessors.
|
||||
* An extension of {@link OgnlExpressionParser} that registers web flow specific property accessors.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -47,7 +46,7 @@ class WebFlowOgnlExpressionParser extends OgnlExpressionParser {
|
||||
*/
|
||||
private static class MapAdaptablePropertyAccessor implements PropertyAccessor {
|
||||
public Object getProperty(Map context, Object target, Object name) throws OgnlException {
|
||||
return ((MapAdaptable)target).asMap().get(name);
|
||||
return ((MapAdaptable) target).asMap().get(name);
|
||||
}
|
||||
|
||||
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
|
||||
@@ -63,7 +62,7 @@ class WebFlowOgnlExpressionParser extends OgnlExpressionParser {
|
||||
*/
|
||||
private static class MutableAttributeMapPropertyAccessor extends MapAdaptablePropertyAccessor {
|
||||
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
|
||||
((MutableAttributeMap)target).put((String)name, value);
|
||||
((MutableAttributeMap) target).put((String) name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,16 +22,15 @@ import org.springframework.binding.collection.MapAdaptable;
|
||||
/**
|
||||
* An immutable interface for accessing attributes in a backing map with string keys.
|
||||
* <p>
|
||||
* Implementations can optionally support {@link AttributeMapBindingListener listeners}
|
||||
* that will be notified when they're bound in or unbound from the map.
|
||||
* Implementations can optionally support {@link AttributeMapBindingListener listeners} that will be notified when
|
||||
* they're bound in or unbound from the map.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface AttributeMap extends MapAdaptable {
|
||||
|
||||
/**
|
||||
* Get an attribute value out of this map, returning <code>null</code> if
|
||||
* not found.
|
||||
* Get an attribute value out of this map, returning <code>null</code> if not found.
|
||||
* @param attributeName the attribute name
|
||||
* @return the attribute value
|
||||
*/
|
||||
@@ -57,13 +56,11 @@ public interface AttributeMap extends MapAdaptable {
|
||||
public boolean contains(String attributeName);
|
||||
|
||||
/**
|
||||
* Does the attribute with the provided name exist in this map and is its
|
||||
* value of the specified required type?
|
||||
* Does the attribute with the provided name exist in this map and is its value of the specified required type?
|
||||
* @param attributeName the attribute name
|
||||
* @param requiredType the required class of the attribute value
|
||||
* @return true if so, false otherwise
|
||||
* @throws IllegalArgumentException when the value is not of the required
|
||||
* type
|
||||
* @throws IllegalArgumentException when the value is not of the required type
|
||||
*/
|
||||
public boolean contains(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
@@ -71,8 +68,7 @@ public interface AttributeMap extends MapAdaptable {
|
||||
* Get an attribute value, returning the default value if no value is found.
|
||||
* @param attributeName the name of the attribute
|
||||
* @param defaultValue the default value
|
||||
* @return the attribute value, falling back to the default if no such
|
||||
* attribute exists
|
||||
* @return the attribute value, falling back to the default if no such attribute exists
|
||||
*/
|
||||
public Object get(String attributeName, Object defaultValue);
|
||||
|
||||
@@ -81,26 +77,22 @@ public interface AttributeMap extends MapAdaptable {
|
||||
* @param attributeName the name of the attribute
|
||||
* @param requiredType the required type of the attribute value
|
||||
* @return the attribute value, or null if not found
|
||||
* @throws IllegalArgumentException when the value is not of the required
|
||||
* type
|
||||
* @throws IllegalArgumentException when the value is not of the required type
|
||||
*/
|
||||
public Object get(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Get an attribute value, asserting the value is of the required type and
|
||||
* returning the default value if not found.
|
||||
* Get an attribute value, asserting the value is of the required type and returning the default value if not found.
|
||||
* @param attributeName the name of the attribute
|
||||
* @param requiredType the value required type
|
||||
* @param defaultValue the default value
|
||||
* @return the attribute value, or the default if not found
|
||||
* @throws IllegalArgumentException when the value (if found) is not of the
|
||||
* required type
|
||||
* @throws IllegalArgumentException when the value (if found) is not of the required type
|
||||
*/
|
||||
public Object get(String attributeName, Class requiredType, Object defaultValue) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Get the value of a required attribute, throwing an exception of no
|
||||
* attribute is found.
|
||||
* Get the value of a required attribute, throwing an exception of no attribute is found.
|
||||
* @param attributeName the name of the attribute
|
||||
* @return the attribute value
|
||||
* @throws IllegalArgumentException when the attribute is not found
|
||||
@@ -108,44 +100,37 @@ public interface AttributeMap extends MapAdaptable {
|
||||
public Object getRequired(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Get the value of a required attribute and make sure it is of the required
|
||||
* type.
|
||||
* Get the value of a required attribute and make sure it is of the required type.
|
||||
* @param attributeName name of the attribute to get
|
||||
* @param requiredType the required type of the attribute value
|
||||
* @return the attribute value
|
||||
* @throws IllegalArgumentException when the attribute is not found or not
|
||||
* of the required type
|
||||
* @throws IllegalArgumentException when the attribute is not found or not of the required type
|
||||
*/
|
||||
public Object getRequired(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a string attribute value in the map, returning <code>null</code>
|
||||
* if no value was found.
|
||||
* Returns a string attribute value in the map, returning <code>null</code> if no value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @return the string attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* string
|
||||
* @throws IllegalArgumentException if the attribute is present but not a string
|
||||
*/
|
||||
public String getString(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a string attribute value in the map, returning the default value
|
||||
* if no value was found.
|
||||
* Returns a string attribute value in the map, returning the default value if no value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @param defaultValue the default
|
||||
* @return the string attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* string
|
||||
* @throws IllegalArgumentException if the attribute is present but not a string
|
||||
*/
|
||||
public String getString(String attributeName, String defaultValue) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a string attribute value in the map, throwing an exception if the
|
||||
* attribute is not present and of the correct type.
|
||||
* Returns a string attribute value in the map, throwing an exception if the attribute is not present and of the
|
||||
* correct type.
|
||||
* @param attributeName the attribute name
|
||||
* @return the string attribute value
|
||||
* @throws IllegalArgumentException if the attribute is not present or
|
||||
* present but not a string
|
||||
* @throws IllegalArgumentException if the attribute is not present or present but not a string
|
||||
*/
|
||||
public String getRequiredString(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
@@ -153,194 +138,169 @@ public interface AttributeMap extends MapAdaptable {
|
||||
* Returns a collection attribute value in the map.
|
||||
* @param attributeName the attribute name
|
||||
* @return the collection attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* collection
|
||||
* @throws IllegalArgumentException if the attribute is present but not a collection
|
||||
*/
|
||||
public Collection getCollection(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a collection attribute value in the map and make sure it is of
|
||||
* the required type.
|
||||
* Returns a collection attribute value in the map and make sure it is of the required type.
|
||||
* @param attributeName the attribute name
|
||||
* @param requiredType the required type of the attribute value
|
||||
* @return the collection attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* collection of the required type
|
||||
* @throws IllegalArgumentException if the attribute is present but not a collection of the required type
|
||||
*/
|
||||
public Collection getCollection(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a collection attribute value in the map, throwing an exception if
|
||||
* the attribute is not present or not a collection.
|
||||
* Returns a collection attribute value in the map, throwing an exception if the attribute is not present or not a
|
||||
* collection.
|
||||
* @param attributeName the attribute name
|
||||
* @return the collection attribute value
|
||||
* @throws IllegalArgumentException if the attribute is not present or is
|
||||
* present but not a collection
|
||||
* @throws IllegalArgumentException if the attribute is not present or is present but not a collection
|
||||
*/
|
||||
public Collection getRequiredCollection(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a collection attribute value in the map, throwing an exception if
|
||||
* the attribute is not present or not a collection of the required type.
|
||||
* Returns a collection attribute value in the map, throwing an exception if the attribute is not present or not a
|
||||
* collection of the required type.
|
||||
* @param attributeName the attribute name
|
||||
* @param requiredType the required collection type
|
||||
* @return the collection attribute value
|
||||
* @throws IllegalArgumentException if the attribute is not present or is
|
||||
* present but not a collection of the required type
|
||||
* @throws IllegalArgumentException if the attribute is not present or is present but not a collection of the
|
||||
* required type
|
||||
*/
|
||||
public Collection getRequiredCollection(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns an array attribute value in the map and makes sure it is of the
|
||||
* required type.
|
||||
* Returns an array attribute value in the map and makes sure it is of the required type.
|
||||
* @param attributeName the attribute name
|
||||
* @param requiredType the required type of the attribute value
|
||||
* @return the array attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not an
|
||||
* array of the required type
|
||||
* @throws IllegalArgumentException if the attribute is present but not an array of the required type
|
||||
*/
|
||||
public Object[] getArray(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns an array attribute value in the map, throwing an exception if the
|
||||
* attribute is not present or not an array of the required type.
|
||||
* Returns an array attribute value in the map, throwing an exception if the attribute is not present or not an
|
||||
* array of the required type.
|
||||
* @param attributeName the attribute name
|
||||
* @param requiredType the required array type
|
||||
* @return the collection attribute value
|
||||
* @throws IllegalArgumentException if the attribute is not present or is
|
||||
* present but not a array of the required type
|
||||
* @throws IllegalArgumentException if the attribute is not present or is present but not a array of the required
|
||||
* type
|
||||
*/
|
||||
public Object[] getRequiredArray(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a number attribute value in the map that is of the specified
|
||||
* type, returning <code>null</code> if no value was found.
|
||||
* Returns a number attribute value in the map that is of the specified type, returning <code>null</code> if no
|
||||
* value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @param requiredType the required number type
|
||||
* @return the number attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* number of the required type
|
||||
* @throws IllegalArgumentException if the attribute is present but not a number of the required type
|
||||
*/
|
||||
public Number getNumber(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a number attribute value in the map of the specified type,
|
||||
* returning the default value if no value was found.
|
||||
* Returns a number attribute value in the map of the specified type, returning the default value if no value was
|
||||
* found.
|
||||
* @param attributeName the attribute name
|
||||
* @param defaultValue the default
|
||||
* @return the number attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* number of the required type
|
||||
* @throws IllegalArgumentException if the attribute is present but not a number of the required type
|
||||
*/
|
||||
public Number getNumber(String attributeName, Class requiredType, Number defaultValue)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a number attribute value in the map, throwing an exception if the
|
||||
* attribute is not present and of the correct type.
|
||||
* Returns a number attribute value in the map, throwing an exception if the attribute is not present and of the
|
||||
* correct type.
|
||||
* @param attributeName the attribute name
|
||||
* @return the number attribute value
|
||||
* @throws IllegalArgumentException if the attribute is not present or
|
||||
* present but not a number of the required type
|
||||
* @throws IllegalArgumentException if the attribute is not present or present but not a number of the required type
|
||||
*/
|
||||
public Number getRequiredNumber(String attributeName, Class requiredType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns an integer attribute value in the map, returning
|
||||
* <code>null</code> if no value was found.
|
||||
* Returns an integer attribute value in the map, returning <code>null</code> if no value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @return the integer attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not an
|
||||
* integer
|
||||
* @throws IllegalArgumentException if the attribute is present but not an integer
|
||||
*/
|
||||
public Integer getInteger(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns an integer attribute value in the map, returning the default
|
||||
* value if no value was found.
|
||||
* Returns an integer attribute value in the map, returning the default value if no value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @param defaultValue the default
|
||||
* @return the integer attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not an
|
||||
* integer
|
||||
* @throws IllegalArgumentException if the attribute is present but not an integer
|
||||
*/
|
||||
public Integer getInteger(String attributeName, Integer defaultValue) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns an integer attribute value in the map, throwing an exception if
|
||||
* the attribute is not present and of the correct type.
|
||||
* Returns an integer attribute value in the map, throwing an exception if the attribute is not present and of the
|
||||
* correct type.
|
||||
* @param attributeName the attribute name
|
||||
* @return the integer attribute value
|
||||
* @throws IllegalArgumentException if the attribute is not present or
|
||||
* present but not an integer
|
||||
* @throws IllegalArgumentException if the attribute is not present or present but not an integer
|
||||
*/
|
||||
public Integer getRequiredInteger(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a long attribute value in the map, returning <code>null</code>
|
||||
* if no value was found.
|
||||
* Returns a long attribute value in the map, returning <code>null</code> if no value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @return the long attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* long
|
||||
* @throws IllegalArgumentException if the attribute is present but not a long
|
||||
*/
|
||||
public Long getLong(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a long attribute value in the map, returning the default value if
|
||||
* no value was found.
|
||||
* Returns a long attribute value in the map, returning the default value if no value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @param defaultValue the default
|
||||
* @return the long attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* long
|
||||
* @throws IllegalArgumentException if the attribute is present but not a long
|
||||
*/
|
||||
public Long getLong(String attributeName, Long defaultValue) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a long attribute value in the map, throwing an exception if the
|
||||
* attribute is not present and of the correct type.
|
||||
* Returns a long attribute value in the map, throwing an exception if the attribute is not present and of the
|
||||
* correct type.
|
||||
* @param attributeName the attribute name
|
||||
* @return the long attribute value
|
||||
* @throws IllegalArgumentException if the attribute is not present or
|
||||
* present but not a long
|
||||
* @throws IllegalArgumentException if the attribute is not present or present but not a long
|
||||
*/
|
||||
public Long getRequiredLong(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a boolean attribute value in the map, returning <code>null</code>
|
||||
* if no value was found.
|
||||
* Returns a boolean attribute value in the map, returning <code>null</code> if no value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @return the long attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* boolean
|
||||
* @throws IllegalArgumentException if the attribute is present but not a boolean
|
||||
*/
|
||||
public Boolean getBoolean(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a boolean attribute value in the map, returning the default value
|
||||
* if no value was found.
|
||||
* Returns a boolean attribute value in the map, returning the default value if no value was found.
|
||||
* @param attributeName the attribute name
|
||||
* @param defaultValue the default
|
||||
* @return the boolean attribute value
|
||||
* @throws IllegalArgumentException if the attribute is present but not a
|
||||
* boolean
|
||||
* @throws IllegalArgumentException if the attribute is present but not a boolean
|
||||
*/
|
||||
public Boolean getBoolean(String attributeName, Boolean defaultValue) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a boolean attribute value in the map, throwing an exception if
|
||||
* the attribute is not present and of the correct type.
|
||||
* Returns a boolean attribute value in the map, throwing an exception if the attribute is not present and of the
|
||||
* correct type.
|
||||
* @param attributeName the attribute name
|
||||
* @return the boolean attribute value
|
||||
* @throws IllegalArgumentException if the attribute is not present or
|
||||
* present but is not a boolean
|
||||
* @throws IllegalArgumentException if the attribute is not present or present but is not a boolean
|
||||
*/
|
||||
public Boolean getRequiredBoolean(String attributeName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns a new attribute map containing the union of this map with the
|
||||
* provided map.
|
||||
* Returns a new attribute map containing the union of this map with the provided map.
|
||||
* @param attributes the map to combine with this map
|
||||
* @return a new, combined map
|
||||
*/
|
||||
|
||||
@@ -18,8 +18,7 @@ package org.springframework.webflow.core.collection;
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* Holder for information about the binding or unbinding event in an
|
||||
* {@link AttributeMap}.
|
||||
* Holder for information about the binding or unbinding event in an {@link AttributeMap}.
|
||||
*
|
||||
* @see AttributeMapBindingListener
|
||||
*
|
||||
@@ -32,8 +31,7 @@ public class AttributeMapBindingEvent extends EventObject {
|
||||
private Object attributeValue;
|
||||
|
||||
/**
|
||||
* Creates an event for map binding that contains information about the
|
||||
* event.
|
||||
* Creates an event for map binding that contains information about the event.
|
||||
* @param source the source map that this attribute was bound in
|
||||
* @param attributeName the name that this attribute was bound with
|
||||
* @param attributeValue the attribute
|
||||
|
||||
@@ -16,11 +16,9 @@
|
||||
package org.springframework.webflow.core.collection;
|
||||
|
||||
/**
|
||||
* Causes an object to be notified when it is bound or unbound from
|
||||
* an {@link AttributeMap}.
|
||||
* Causes an object to be notified when it is bound or unbound from an {@link AttributeMap}.
|
||||
* <p>
|
||||
* Note that this is an optional feature and not all {@link AttributeMap}
|
||||
* implementations support it.
|
||||
* Note that this is an optional feature and not all {@link AttributeMap} implementations support it.
|
||||
*
|
||||
* @see AttributeMap
|
||||
*
|
||||
@@ -29,15 +27,13 @@ package org.springframework.webflow.core.collection;
|
||||
public interface AttributeMapBindingListener {
|
||||
|
||||
/**
|
||||
* Called when the implementing instance is bound into an
|
||||
* <code>AttributeMap</code>.
|
||||
* Called when the implementing instance is bound into an <code>AttributeMap</code>.
|
||||
* @param event information about the binding event
|
||||
*/
|
||||
void valueBound(AttributeMapBindingEvent event);
|
||||
|
||||
/**
|
||||
* Called when the implementing instance is unbound from an
|
||||
* <code>AttributeMap</code>.
|
||||
* Called when the implementing instance is unbound from an <code>AttributeMap</code>.
|
||||
* @param event information about the unbinding event
|
||||
*/
|
||||
void valueUnbound(AttributeMapBindingEvent event);
|
||||
|
||||
@@ -22,8 +22,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A utility class for working with attribute and parameter collections used by
|
||||
* Spring Web FLow.
|
||||
* A utility class for working with attribute and parameter collections used by Spring Web FLow.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -56,8 +55,7 @@ public class CollectionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that returns a unmodifiable attribute map with a single
|
||||
* entry.
|
||||
* Factory method that returns a unmodifiable attribute map with a single entry.
|
||||
* @param attributeName the attribute name
|
||||
* @param attributeValue the attribute value
|
||||
* @return the unmodifiable map with a single element
|
||||
@@ -67,9 +65,8 @@ public class CollectionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all given objects to given target list. No duplicates will be added.
|
||||
* The contains() method of the given target list will be used to determine
|
||||
* whether or not an object is already in the list.
|
||||
* Add all given objects to given target list. No duplicates will be added. The contains() method of the given
|
||||
* target list will be used to determine whether or not an object is already in the list.
|
||||
* @param target the collection to which to objects will be added
|
||||
* @param objects the objects to add
|
||||
* @return whether or not the target collection changed
|
||||
@@ -77,8 +74,7 @@ public class CollectionUtils {
|
||||
public static boolean addAllNoDuplicates(List target, Object[] objects) {
|
||||
if (objects == null || objects.length == 0) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
boolean changed = false;
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (!target.contains(objects[i])) {
|
||||
@@ -89,7 +85,7 @@ public class CollectionUtils {
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iterator iterating over no elements (hasNext() always returns false).
|
||||
*/
|
||||
|
||||
@@ -40,8 +40,7 @@ public class LocalAttributeMap implements MutableAttributeMap, Serializable {
|
||||
private Map attributes;
|
||||
|
||||
/**
|
||||
* A helper for accessing attributes. Marked transient and restored on
|
||||
* deserialization.
|
||||
* A helper for accessing attributes. Marked transient and restored on deserialization.
|
||||
*/
|
||||
private transient MapAccessor attributeAccessor;
|
||||
|
||||
@@ -54,8 +53,8 @@ public class LocalAttributeMap implements MutableAttributeMap, Serializable {
|
||||
|
||||
/**
|
||||
* Creates a new attribute map, initially empty.
|
||||
* @param size the initial size
|
||||
* @param loadFactor the load factor
|
||||
* @param size the initial size
|
||||
* @param loadFactor the load factor
|
||||
*/
|
||||
public LocalAttributeMap(int size, int loadFactor) {
|
||||
initAttributes(createTargetMap(size, loadFactor));
|
||||
@@ -211,8 +210,7 @@ public class LocalAttributeMap implements MutableAttributeMap, Serializable {
|
||||
public AttributeMap union(AttributeMap attributes) {
|
||||
if (attributes == null) {
|
||||
return new LocalAttributeMap(getMapInternal());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Map map = createTargetMap();
|
||||
map.putAll(getMapInternal());
|
||||
map.putAll(attributes.asMap());
|
||||
@@ -270,8 +268,7 @@ public class LocalAttributeMap implements MutableAttributeMap, Serializable {
|
||||
// helpers
|
||||
|
||||
/**
|
||||
* Factory method that returns the target map storing the data in this
|
||||
* attribute map.
|
||||
* Factory method that returns the target map storing the data in this attribute map.
|
||||
* @return the target map
|
||||
*/
|
||||
protected Map createTargetMap() {
|
||||
@@ -279,8 +276,7 @@ public class LocalAttributeMap implements MutableAttributeMap, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that returns the target map storing the data in this
|
||||
* attribute map.
|
||||
* Factory method that returns the target map storing the data in this attribute map.
|
||||
* @param size the initial size of the map
|
||||
* @param loadFactor the load factor
|
||||
* @return the target map
|
||||
@@ -293,7 +289,7 @@ public class LocalAttributeMap implements MutableAttributeMap, Serializable {
|
||||
if (!(o instanceof LocalAttributeMap)) {
|
||||
return false;
|
||||
}
|
||||
LocalAttributeMap other = (LocalAttributeMap)o;
|
||||
LocalAttributeMap other = (LocalAttributeMap) o;
|
||||
return getMapInternal().equals(other.getMapInternal());
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,8 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* An immutable parameter map storing String-keyed, String-valued parameters
|
||||
* in a backing {@link Map} implementation. This base provides convenient
|
||||
* operations for accessing parameters in a typed-manner.
|
||||
* An immutable parameter map storing String-keyed, String-valued parameters in a backing {@link Map} implementation.
|
||||
* This base provides convenient operations for accessing parameters in a typed-manner.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -49,23 +48,20 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
private Map parameters;
|
||||
|
||||
/**
|
||||
* A helper for accessing parameters. Marked transient and restored on
|
||||
* deserialization.
|
||||
* A helper for accessing parameters. Marked transient and restored on deserialization.
|
||||
*/
|
||||
private transient MapAccessor parameterAccessor;
|
||||
|
||||
/**
|
||||
* A helper for converting string parameter values. Marked transient and
|
||||
* restored on deserialization.
|
||||
* A helper for converting string parameter values. Marked transient and restored on deserialization.
|
||||
*/
|
||||
private transient ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Creates a new parameter map from the provided map.
|
||||
* <p>
|
||||
* It is expected that the contents of the backing map adhere to the
|
||||
* parameter map contract; that is, map entries have string keys, string
|
||||
* values, and remain unmodifiable.
|
||||
* It is expected that the contents of the backing map adhere to the parameter map contract; that is, map entries
|
||||
* have string keys, string values, and remain unmodifiable.
|
||||
* @param parameters the contents of this parameter map
|
||||
*/
|
||||
public LocalParameterMap(Map parameters) {
|
||||
@@ -75,12 +71,10 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
/**
|
||||
* Creates a new parameter map from the provided map.
|
||||
* <p>
|
||||
* It is expected that the contents of the backing map adhere to the
|
||||
* parameter map contract; that is, map entries have string keys, string
|
||||
* values, and remain unmodifiable.
|
||||
* It is expected that the contents of the backing map adhere to the parameter map contract; that is, map entries
|
||||
* have string keys, string values, and remain unmodifiable.
|
||||
* @param parameters the contents of this parameter map
|
||||
* @param conversionService a helper for performing type conversion of map
|
||||
* entry values
|
||||
* @param conversionService a helper for performing type conversion of map entry values
|
||||
*/
|
||||
public LocalParameterMap(Map parameters, ConversionService conversionService) {
|
||||
initParameters(parameters);
|
||||
@@ -91,7 +85,7 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
if (!(o instanceof LocalParameterMap)) {
|
||||
return false;
|
||||
}
|
||||
LocalParameterMap other = (LocalParameterMap)o;
|
||||
LocalParameterMap other = (LocalParameterMap) o;
|
||||
return parameters.equals(other.parameters);
|
||||
}
|
||||
|
||||
@@ -116,7 +110,7 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
}
|
||||
|
||||
public String get(String parameterName) {
|
||||
return get(parameterName, (String)null);
|
||||
return get(parameterName, (String) null);
|
||||
}
|
||||
|
||||
public String get(String parameterName, String defaultValue) {
|
||||
@@ -126,20 +120,18 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
Object value = parameters.get(parameterName);
|
||||
if (value.getClass().isArray()) {
|
||||
parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String[].class);
|
||||
String[] array = (String[])value;
|
||||
String[] array = (String[]) value;
|
||||
if (array.length == 0) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
Object first = ((String[])value)[0];
|
||||
} else {
|
||||
Object first = ((String[]) value)[0];
|
||||
parameterAccessor.assertKeyValueInstanceOf(parameterName, first, String.class);
|
||||
return (String)first;
|
||||
return (String) first;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String.class);
|
||||
return (String)value;
|
||||
return (String) value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,11 +142,10 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
Object value = parameters.get(parameterName);
|
||||
if (value.getClass().isArray()) {
|
||||
parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String[].class);
|
||||
return (String[])value;
|
||||
}
|
||||
else {
|
||||
return (String[]) value;
|
||||
} else {
|
||||
parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String.class);
|
||||
return new String[] { (String)value };
|
||||
return new String[] { (String) value };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,62 +189,62 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
|
||||
public Number getNumber(String parameterName, Class targetType) throws ConversionException {
|
||||
assertAssignableTo(Number.class, targetType);
|
||||
return (Number)get(parameterName, targetType);
|
||||
return (Number) get(parameterName, targetType);
|
||||
}
|
||||
|
||||
public Number getNumber(String parameterName, Class targetType, Number defaultValue) throws ConversionException {
|
||||
assertAssignableTo(Number.class, targetType);
|
||||
return (Number)get(parameterName, targetType, defaultValue);
|
||||
return (Number) get(parameterName, targetType, defaultValue);
|
||||
}
|
||||
|
||||
public Number getRequiredNumber(String parameterName, Class targetType) throws IllegalArgumentException,
|
||||
ConversionException {
|
||||
assertAssignableTo(Number.class, targetType);
|
||||
return (Number)getRequired(parameterName, targetType);
|
||||
return (Number) getRequired(parameterName, targetType);
|
||||
}
|
||||
|
||||
public Integer getInteger(String parameterName) throws ConversionException {
|
||||
return (Integer)get(parameterName, Integer.class);
|
||||
return (Integer) get(parameterName, Integer.class);
|
||||
}
|
||||
|
||||
public Integer getInteger(String parameterName, Integer defaultValue) throws ConversionException {
|
||||
return (Integer)get(parameterName, Integer.class, defaultValue);
|
||||
return (Integer) get(parameterName, Integer.class, defaultValue);
|
||||
}
|
||||
|
||||
public Integer getRequiredInteger(String parameterName) throws IllegalArgumentException, ConversionException {
|
||||
return (Integer)getRequired(parameterName, Integer.class);
|
||||
return (Integer) getRequired(parameterName, Integer.class);
|
||||
}
|
||||
|
||||
public Long getLong(String parameterName) throws ConversionException {
|
||||
return (Long)get(parameterName, Long.class);
|
||||
return (Long) get(parameterName, Long.class);
|
||||
}
|
||||
|
||||
public Long getLong(String parameterName, Long defaultValue) throws ConversionException {
|
||||
return (Long)get(parameterName, Long.class, defaultValue);
|
||||
return (Long) get(parameterName, Long.class, defaultValue);
|
||||
}
|
||||
|
||||
public Long getRequiredLong(String parameterName) throws IllegalArgumentException, ConversionException {
|
||||
return (Long)getRequired(parameterName, Long.class);
|
||||
return (Long) getRequired(parameterName, Long.class);
|
||||
}
|
||||
|
||||
public Boolean getBoolean(String parameterName) throws ConversionException {
|
||||
return (Boolean)get(parameterName, Boolean.class);
|
||||
return (Boolean) get(parameterName, Boolean.class);
|
||||
}
|
||||
|
||||
public Boolean getBoolean(String parameterName, Boolean defaultValue) throws ConversionException {
|
||||
return (Boolean)get(parameterName, Boolean.class, defaultValue);
|
||||
return (Boolean) get(parameterName, Boolean.class, defaultValue);
|
||||
}
|
||||
|
||||
public Boolean getRequiredBoolean(String parameterName) throws IllegalArgumentException, ConversionException {
|
||||
return (Boolean)getRequired(parameterName, Boolean.class);
|
||||
return (Boolean) getRequired(parameterName, Boolean.class);
|
||||
}
|
||||
|
||||
public MultipartFile getMultipartFile(String parameterName) {
|
||||
return (MultipartFile)parameterAccessor.get(parameterName, MultipartFile.class);
|
||||
return (MultipartFile) parameterAccessor.get(parameterName, MultipartFile.class);
|
||||
}
|
||||
|
||||
public MultipartFile getRequiredMultipartFile(String parameterName) throws IllegalArgumentException {
|
||||
return (MultipartFile)parameterAccessor.getRequired(parameterName, MultipartFile.class);
|
||||
return (MultipartFile) parameterAccessor.getRequired(parameterName, MultipartFile.class);
|
||||
}
|
||||
|
||||
public AttributeMap asAttributeMap() {
|
||||
@@ -286,8 +277,7 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert given array of String parameters to specified target type and
|
||||
* return the resulting array.
|
||||
* Convert given array of String parameters to specified target type and return the resulting array.
|
||||
*/
|
||||
private Object[] convert(String[] parameters, Class targetElementType) throws ConversionException {
|
||||
List list = new ArrayList(parameters.length);
|
||||
@@ -295,7 +285,7 @@ public class LocalParameterMap implements ParameterMap, Serializable {
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
list.add(converter.execute(parameters[i]));
|
||||
}
|
||||
return list.toArray((Object[])Array.newInstance(targetElementType, parameters.length));
|
||||
return list.toArray((Object[]) Array.newInstance(targetElementType, parameters.length));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,11 +18,10 @@ package org.springframework.webflow.core.collection;
|
||||
import org.springframework.binding.collection.SharedMap;
|
||||
|
||||
/**
|
||||
* An attribute map that exposes a mutex that application code can synchronize
|
||||
* on. This class wraps another shared map in an attribute map.
|
||||
* An attribute map that exposes a mutex that application code can synchronize on. This class wraps another shared map
|
||||
* in an attribute map.
|
||||
* <p>
|
||||
* The mutex can be used to serialize concurrent access to the shared map's
|
||||
* contents by multiple threads.
|
||||
* The mutex can be used to serialize concurrent access to the shared map's contents by multiple threads.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -39,11 +38,11 @@ public class LocalSharedAttributeMap extends LocalAttributeMap implements Shared
|
||||
public Object getMutex() {
|
||||
return getSharedMap().getMutex();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the wrapped shared map.
|
||||
*/
|
||||
protected SharedMap getSharedMap() {
|
||||
return (SharedMap)getMapInternal();
|
||||
return (SharedMap) getMapInternal();
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,10 @@
|
||||
package org.springframework.webflow.core.collection;
|
||||
|
||||
/**
|
||||
* An interface for accessing and modifying attributes in a backing map with
|
||||
* string keys.
|
||||
* An interface for accessing and modifying attributes in a backing map with string keys.
|
||||
* <p>
|
||||
* Implementations can optionally support {@link AttributeMapBindingListener listeners}
|
||||
* that will be notified when they're bound in or unbound from the map.
|
||||
* Implementations can optionally support {@link AttributeMapBindingListener listeners} that will be notified when
|
||||
* they're bound in or unbound from the map.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -29,15 +28,13 @@ public interface MutableAttributeMap extends AttributeMap {
|
||||
/**
|
||||
* Put the attribute into this map.
|
||||
* <p>
|
||||
* If the attribute value is an {@link AttributeMapBindingListener} this map
|
||||
* will publish {@link AttributeMapBindingEvent binding events} such as on
|
||||
* "bind" and "unbind" if supported.
|
||||
* If the attribute value is an {@link AttributeMapBindingListener} this map will publish
|
||||
* {@link AttributeMapBindingEvent binding events} such as on "bind" and "unbind" if supported.
|
||||
* <p>
|
||||
* <b>Note</b>: not all <code>MutableAttributeMap</code> implementations support this.
|
||||
* @param attributeName the attribute name
|
||||
* @param attributeValue the attribute value
|
||||
* @return the previous value of the attribute, or <tt>null</tt> of there
|
||||
* was no previous value
|
||||
* @return the previous value of the attribute, or <tt>null</tt> of there was no previous value
|
||||
*/
|
||||
public Object put(String attributeName, Object attributeValue);
|
||||
|
||||
@@ -51,8 +48,8 @@ public interface MutableAttributeMap extends AttributeMap {
|
||||
/**
|
||||
* Remove an attribute from this map.
|
||||
* @param attributeName the name of the attribute to remove
|
||||
* @return previous value associated with specified attribute name, or
|
||||
* <tt>null</tt> if there was no mapping for the name
|
||||
* @return previous value associated with specified attribute name, or <tt>null</tt> if there was no mapping for
|
||||
* the name
|
||||
*/
|
||||
public Object remove(String attributeName);
|
||||
|
||||
@@ -63,8 +60,7 @@ public interface MutableAttributeMap extends AttributeMap {
|
||||
public MutableAttributeMap clear();
|
||||
|
||||
/**
|
||||
* Replace the contents of this attribute map with the contents of the
|
||||
* provided collection.
|
||||
* Replace the contents of this attribute map with the contents of the provided collection.
|
||||
* @param attributes the attribute collection
|
||||
* @return this, to support call chaining
|
||||
*/
|
||||
|
||||
@@ -20,12 +20,11 @@ import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* An interface for accessing parameters in a backing map. Parameters are
|
||||
* immutable and have string keys and string values.
|
||||
* An interface for accessing parameters in a backing map. Parameters are immutable and have string keys and string
|
||||
* values.
|
||||
* <p>
|
||||
* The accessor methods offered by this class taking a target type argument
|
||||
* only need to support conversions to well know types like String, Number subclasses,
|
||||
* Boolean and so on.
|
||||
* The accessor methods offered by this class taking a target type argument only need to support conversions to well
|
||||
* know types like String, Number subclasses, Boolean and so on.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -51,8 +50,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public boolean contains(String parameterName);
|
||||
|
||||
/**
|
||||
* Get a parameter value, returning <code>null</code> if no value is
|
||||
* found.
|
||||
* Get a parameter value, returning <code>null</code> if no value is found.
|
||||
* @param parameterName the parameter name
|
||||
* @return the parameter value
|
||||
*/
|
||||
@@ -67,17 +65,16 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public String get(String parameterName, String defaultValue);
|
||||
|
||||
/**
|
||||
* Get a multi-valued parameter value, returning <code>null</code> if no
|
||||
* value is found. If the parameter is single valued an array with a single
|
||||
* element is returned.
|
||||
* Get a multi-valued parameter value, returning <code>null</code> if no value is found. If the parameter is
|
||||
* single valued an array with a single element is returned.
|
||||
* @param parameterName the parameter name
|
||||
* @return the parameter value array
|
||||
*/
|
||||
public String[] getArray(String parameterName);
|
||||
|
||||
/**
|
||||
* Get a multi-valued parameter value, converting each value to the target
|
||||
* type or returning <code>null</code> if no value is found.
|
||||
* Get a multi-valued parameter value, converting each value to the target type or returning <code>null</code> if
|
||||
* no value is found.
|
||||
* @param parameterName the parameter name
|
||||
* @param targetElementType the target type of the array's elements
|
||||
* @return the converterd parameter value array
|
||||
@@ -86,8 +83,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Object[] getArray(String parameterName, Class targetElementType) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Get a parameter value, converting it from <code>String</code> to the
|
||||
* target type.
|
||||
* Get a parameter value, converting it from <code>String</code> to the target type.
|
||||
* @param parameterName the name of the parameter
|
||||
* @param targetType the target type of the parameter value
|
||||
* @return the converted parameter value, or null if not found
|
||||
@@ -96,8 +92,8 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Object get(String parameterName, Class targetType) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Get a parameter value, converting it from <code>String</code> to the
|
||||
* target type or returning the defaultValue if not found.
|
||||
* Get a parameter value, converting it from <code>String</code> to the target type or returning the defaultValue
|
||||
* if not found.
|
||||
* @param parameterName name of the parameter to get
|
||||
* @param targetType the target type of the parameter value
|
||||
* @param defaultValue the default value
|
||||
@@ -123,8 +119,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public String[] getRequiredArray(String parameterName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Get a required multi-valued parameter value, converting each value to the
|
||||
* target type.
|
||||
* Get a required multi-valued parameter value, converting each value to the target type.
|
||||
* @param parameterName the name of the parameter
|
||||
* @return the parameter value
|
||||
* @throws IllegalArgumentException when the parameter is not found
|
||||
@@ -145,8 +140,8 @@ public interface ParameterMap extends MapAdaptable {
|
||||
ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a number parameter value in the map that is of the specified
|
||||
* type, returning <code>null</code> if no value was found.
|
||||
* Returns a number parameter value in the map that is of the specified type, returning <code>null</code> if no
|
||||
* value was found.
|
||||
* @param parameterName the parameter name
|
||||
* @param targetType the target number type
|
||||
* @return the number parameter value
|
||||
@@ -155,8 +150,8 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Number getNumber(String parameterName, Class targetType) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a number parameter value in the map of the specified type,
|
||||
* returning the defaultValue if no value was found.
|
||||
* Returns a number parameter value in the map of the specified type, returning the defaultValue if no value was
|
||||
* found.
|
||||
* @param parameterName the parameter name
|
||||
* @param defaultValue the default
|
||||
* @return the number parameter value
|
||||
@@ -165,8 +160,8 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Number getNumber(String parameterName, Class targetType, Number defaultValue) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a number parameter value in the map, throwing an exception if the
|
||||
* parameter is not present or could not be converted.
|
||||
* Returns a number parameter value in the map, throwing an exception if the parameter is not present or could not
|
||||
* be converted.
|
||||
* @param parameterName the parameter name
|
||||
* @return the number parameter value
|
||||
* @throws IllegalArgumentException if the parameter is not present
|
||||
@@ -176,8 +171,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
ConversionException;
|
||||
|
||||
/**
|
||||
* Returns an integer parameter value in the map, returning
|
||||
* <code>null</code> if no value was found.
|
||||
* Returns an integer parameter value in the map, returning <code>null</code> if no value was found.
|
||||
* @param parameterName the parameter name
|
||||
* @return the integer parameter value
|
||||
* @throws ConversionException when the value could not be converted
|
||||
@@ -185,8 +179,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Integer getInteger(String parameterName) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Returns an integer parameter value in the map, returning the defaultValue
|
||||
* if no value was found.
|
||||
* Returns an integer parameter value in the map, returning the defaultValue if no value was found.
|
||||
* @param parameterName the parameter name
|
||||
* @param defaultValue the default
|
||||
* @return the integer parameter value
|
||||
@@ -195,8 +188,8 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Integer getInteger(String parameterName, Integer defaultValue) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Returns an integer parameter value in the map, throwing an exception if
|
||||
* the parameter is not present or could not be converted.
|
||||
* Returns an integer parameter value in the map, throwing an exception if the parameter is not present or could not
|
||||
* be converted.
|
||||
* @param parameterName the parameter name
|
||||
* @return the integer parameter value
|
||||
* @throws IllegalArgumentException if the parameter is not present
|
||||
@@ -205,8 +198,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Integer getRequiredInteger(String parameterName) throws IllegalArgumentException, ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a long parameter value in the map, returning <code>null</code>
|
||||
* if no value was found.
|
||||
* Returns a long parameter value in the map, returning <code>null</code> if no value was found.
|
||||
* @param parameterName the parameter name
|
||||
* @return the long parameter value
|
||||
* @throws ConversionException when the value could not be converted
|
||||
@@ -214,8 +206,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Long getLong(String parameterName) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a long parameter value in the map, returning the defaultValue if
|
||||
* no value was found.
|
||||
* Returns a long parameter value in the map, returning the defaultValue if no value was found.
|
||||
* @param parameterName the parameter name
|
||||
* @param defaultValue the default
|
||||
* @return the long parameter value
|
||||
@@ -224,8 +215,8 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Long getLong(String parameterName, Long defaultValue) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a long parameter value in the map, throwing an exception if the
|
||||
* parameter is not present or could not be converted.
|
||||
* Returns a long parameter value in the map, throwing an exception if the parameter is not present or could not be
|
||||
* converted.
|
||||
* @param parameterName the parameter name
|
||||
* @return the long parameter value
|
||||
* @throws IllegalArgumentException if the parameter is not present
|
||||
@@ -234,8 +225,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Long getRequiredLong(String parameterName) throws IllegalArgumentException, ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a boolean parameter value in the map, returning <code>null</code>
|
||||
* if no value was found.
|
||||
* Returns a boolean parameter value in the map, returning <code>null</code> if no value was found.
|
||||
* @param parameterName the parameter name
|
||||
* @return the long parameter value
|
||||
* @throws ConversionException when the value could not be converted
|
||||
@@ -243,8 +233,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Boolean getBoolean(String parameterName) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a boolean parameter value in the map, returning the defaultValue
|
||||
* if no value was found.
|
||||
* Returns a boolean parameter value in the map, returning the defaultValue if no value was found.
|
||||
* @param parameterName the parameter name
|
||||
* @param defaultValue the default
|
||||
* @return the boolean parameter value
|
||||
@@ -253,8 +242,8 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Boolean getBoolean(String parameterName, Boolean defaultValue) throws ConversionException;
|
||||
|
||||
/**
|
||||
* Returns a boolean parameter value in the map, throwing an exception if
|
||||
* the parameter is not present or could not be converted.
|
||||
* Returns a boolean parameter value in the map, throwing an exception if the parameter is not present or could not
|
||||
* be converted.
|
||||
* @param parameterName the parameter name
|
||||
* @return the boolean parameter value
|
||||
* @throws IllegalArgumentException if the parameter is not present
|
||||
@@ -263,8 +252,7 @@ public interface ParameterMap extends MapAdaptable {
|
||||
public Boolean getRequiredBoolean(String parameterName) throws IllegalArgumentException, ConversionException;
|
||||
|
||||
/**
|
||||
* Get a multi-part file parameter value, returning <code>null</code> if
|
||||
* no value is found.
|
||||
* Get a multi-part file parameter value, returning <code>null</code> if no value is found.
|
||||
* @param parameterName the parameter name
|
||||
* @return the multipart file
|
||||
*/
|
||||
|
||||
@@ -16,16 +16,14 @@
|
||||
package org.springframework.webflow.core.collection;
|
||||
|
||||
/**
|
||||
* An interface to be implemented by mutable attribute maps accessed by
|
||||
* multiple threads that need to be synchronized.
|
||||
* An interface to be implemented by mutable attribute maps accessed by multiple threads that need to be synchronized.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface SharedAttributeMap extends MutableAttributeMap {
|
||||
|
||||
/**
|
||||
* Returns the shared map's mutex, which may be synchronized on to block
|
||||
* access to the map by other threads.
|
||||
* Returns the shared map's mutex, which may be synchronized on to block access to the map by other threads.
|
||||
*/
|
||||
public Object getMutex();
|
||||
}
|
||||
@@ -18,8 +18,7 @@ package org.springframework.webflow.definition;
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
|
||||
/**
|
||||
* An interface to be implemented by objects that are annotated with attributes
|
||||
* they wish to expose to clients.
|
||||
* An interface to be implemented by objects that are annotated with attributes they wish to expose to clients.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -27,8 +26,7 @@ import org.springframework.webflow.core.collection.AttributeMap;
|
||||
public interface Annotated {
|
||||
|
||||
/**
|
||||
* Returns a short summary of this object, suitable for display as
|
||||
* an icon caption or tool tip.
|
||||
* Returns a short summary of this object, suitable for display as an icon caption or tool tip.
|
||||
* @return the caption
|
||||
*/
|
||||
public String getCaption();
|
||||
@@ -40,9 +38,8 @@ public interface Annotated {
|
||||
public String getDescription();
|
||||
|
||||
/**
|
||||
* Returns an immutable attribute map containing the attributes annotating
|
||||
* this object. These attributes provide descriptive characteristics or
|
||||
* properties that may affect object behavior.
|
||||
* Returns an immutable attribute map containing the attributes annotating this object. These attributes provide
|
||||
* descriptive characteristics or properties that may affect object behavior.
|
||||
* @return the attribute map
|
||||
*/
|
||||
public AttributeMap getAttributes();
|
||||
|
||||
@@ -16,29 +16,23 @@
|
||||
package org.springframework.webflow.definition;
|
||||
|
||||
/**
|
||||
* The definition of a flow, a program that when executed carries out the
|
||||
* orchestration of a task on behalf of a single client.
|
||||
* The definition of a flow, a program that when executed carries out the orchestration of a task on behalf of a single
|
||||
* client.
|
||||
* <p>
|
||||
* A flow definition is a reusable, self-contained controller module that
|
||||
* defines a blue print for an executable user task. Flows typically orchestrate
|
||||
* controlled navigations or dialogs within web applications to guide users
|
||||
* through fulfillment of a business process/goal that takes place over a series
|
||||
* of steps, modeled as states.
|
||||
* A flow definition is a reusable, self-contained controller module that defines a blue print for an executable user
|
||||
* task. Flows typically orchestrate controlled navigations or dialogs within web applications to guide users through
|
||||
* fulfillment of a business process/goal that takes place over a series of steps, modeled as states.
|
||||
* <p>
|
||||
* Structurally a flow definition is composed of a set of states. A
|
||||
* {@link StateDefinition state} is a point in a flow where a behavior is
|
||||
* executed; for example, showing a view, executing an action, spawning a
|
||||
* subflow, or terminating the flow. Different types of states execute different
|
||||
* behaviors in a polymorphic fashion. Most states are
|
||||
* {@link TransitionableStateDefinition transitionable states}, meaning they
|
||||
* can respond to events by taking the flow from one state to another.
|
||||
* Structurally a flow definition is composed of a set of states. A {@link StateDefinition state} is a point in a flow
|
||||
* where a behavior is executed; for example, showing a view, executing an action, spawning a subflow, or terminating
|
||||
* the flow. Different types of states execute different behaviors in a polymorphic fashion. Most states are
|
||||
* {@link TransitionableStateDefinition transitionable states}, meaning they can respond to events by taking the flow
|
||||
* from one state to another.
|
||||
* <p>
|
||||
* Each flow has exactly one {@link #getStartState() start state} which defines
|
||||
* the starting point of the program.
|
||||
* Each flow has exactly one {@link #getStartState() start state} which defines the starting point of the program.
|
||||
* <p>
|
||||
* This interface exposes the flow's identifier, states, and other definitional
|
||||
* attributes. It is suitable for introspection by tools as well as user-code at
|
||||
* flow execution time.
|
||||
* This interface exposes the flow's identifier, states, and other definitional attributes. It is suitable for
|
||||
* introspection by tools as well as user-code at flow execution time.
|
||||
* <p>
|
||||
* Flow definitions may be annotated with attributes.
|
||||
*
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
package org.springframework.webflow.definition;
|
||||
|
||||
/**
|
||||
* A step within a {@link FlowDefinition flow definition} where behavior is
|
||||
* executed.
|
||||
* A step within a {@link FlowDefinition flow definition} where behavior is executed.
|
||||
* <p>
|
||||
* States have identifiers that are local to their containing flow definitions.
|
||||
* They may also be annotated with attributes.
|
||||
* States have identifiers that are local to their containing flow definitions. They may also be annotated with
|
||||
* attributes.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -32,10 +31,9 @@ public interface StateDefinition extends Annotated {
|
||||
* @return the owning flow definition
|
||||
*/
|
||||
public FlowDefinition getOwner();
|
||||
|
||||
|
||||
/**
|
||||
* Returns this state's identifier, locally unique to is containing flow
|
||||
* definition.
|
||||
* Returns this state's identifier, locally unique to is containing flow definition.
|
||||
* @return the state identifier
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
@@ -24,17 +24,15 @@ package org.springframework.webflow.definition;
|
||||
public interface TransitionDefinition extends Annotated {
|
||||
|
||||
/**
|
||||
* The identifier of this transition. This id value should be unique among
|
||||
* all other transitions in a set.
|
||||
* The identifier of this transition. This id value should be unique among all other transitions in a set.
|
||||
* @return the transition identifier
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Returns an identification of the target state of this transition.
|
||||
* This could be an actual static state id or something more dynamic,
|
||||
* like a string representation of an expression evaluating the target
|
||||
* state id at flow execution time.
|
||||
* Returns an identification of the target state of this transition. This could be an actual static state id or
|
||||
* something more dynamic, like a string representation of an expression evaluating the target state id at flow
|
||||
* execution time.
|
||||
* @return the target state identifier
|
||||
*/
|
||||
public String getTargetStateId();
|
||||
|
||||
@@ -22,7 +22,7 @@ package org.springframework.webflow.definition;
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public interface TransitionableStateDefinition extends StateDefinition {
|
||||
|
||||
|
||||
/**
|
||||
* Returns the available transitions out of this state.
|
||||
* @return the available state transitions
|
||||
|
||||
@@ -19,10 +19,9 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* A base class for factory beans that create populated flow definition registries.
|
||||
* Subclasses should override the {@link #doPopulate(FlowDefinitionRegistry)} method
|
||||
* to perform the registry population logic, typically delegating to a
|
||||
* {@link FlowDefinitionRegistrar} strategy to perform the population.
|
||||
* A base class for factory beans that create populated flow definition registries. Subclasses should override the
|
||||
* {@link #doPopulate(FlowDefinitionRegistry)} method to perform the registry population logic, typically delegating to
|
||||
* a {@link FlowDefinitionRegistrar} strategy to perform the population.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -34,11 +33,9 @@ public abstract class AbstractFlowDefinitionRegistryFactoryBean implements Facto
|
||||
private FlowDefinitionRegistry registry = createFlowDefinitionRegistry();
|
||||
|
||||
/**
|
||||
* Sets the parent registry of the registry constructed by this factory
|
||||
* bean.
|
||||
* Sets the parent registry of the registry constructed by this factory bean.
|
||||
* <p>
|
||||
* A child registry will delegate to its parent if it cannot fulfill a
|
||||
* request to locate a flow definition itself.
|
||||
* A child registry will delegate to its parent if it cannot fulfill a request to locate a flow definition itself.
|
||||
* @param parent the parent flow definition registry
|
||||
*/
|
||||
public void setParent(FlowDefinitionRegistry parent) {
|
||||
@@ -53,7 +50,7 @@ public abstract class AbstractFlowDefinitionRegistryFactoryBean implements Facto
|
||||
}
|
||||
|
||||
// implementing FactoryBean
|
||||
|
||||
|
||||
public Class getObjectType() {
|
||||
return FlowDefinitionRegistry.class;
|
||||
}
|
||||
@@ -75,26 +72,22 @@ public abstract class AbstractFlowDefinitionRegistryFactoryBean implements Facto
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
|
||||
/**
|
||||
* Create the flow definition registry to be populated in
|
||||
* {@link #doPopulate(FlowDefinitionRegistry)}. Subclasses can override
|
||||
* this method if they want to use a custom flow definition registry
|
||||
* implementation.
|
||||
* Create the flow definition registry to be populated in {@link #doPopulate(FlowDefinitionRegistry)}. Subclasses
|
||||
* can override this method if they want to use a custom flow definition registry implementation.
|
||||
*/
|
||||
protected FlowDefinitionRegistry createFlowDefinitionRegistry() {
|
||||
return new FlowDefinitionRegistryImpl();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Template method subclasses may override to perform factory bean initialization
|
||||
* logic before registry population. Will be called before
|
||||
* {@link #doPopulate(FlowDefinitionRegistry)}. The default implementation
|
||||
* is empty.
|
||||
* Template method subclasses may override to perform factory bean initialization logic before registry population.
|
||||
* Will be called before {@link #doPopulate(FlowDefinitionRegistry)}. The default implementation is empty.
|
||||
*/
|
||||
protected void init() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Template method subclasses must override to perform registry population.
|
||||
* @param registry the flow definition registry to populate
|
||||
|
||||
@@ -24,26 +24,21 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* A flow definition registrar that populates a flow definition registry from
|
||||
* flow definitions defined within externalized resources. Encapsulates
|
||||
* registration behavior common to all externalized registrars and is not tied
|
||||
* to a specific flow definition format (e.g. xml).
|
||||
* A flow definition registrar that populates a flow definition registry from flow definitions defined within
|
||||
* externalized resources. Encapsulates registration behavior common to all externalized registrars and is not tied to a
|
||||
* specific flow definition format (e.g. xml).
|
||||
* <p>
|
||||
* Concrete subclasses are expected to derive from this class to provide
|
||||
* knowledge about a particular kind of definition format by implementing the
|
||||
* abstract template methods in this class.
|
||||
* Concrete subclasses are expected to derive from this class to provide knowledge about a particular kind of definition
|
||||
* format by implementing the abstract template methods in this class.
|
||||
* <p>
|
||||
* By default, when configuring the {@link #setLocations(Resource[]) locations}
|
||||
* property, flow definitions at those locations will be assigned a registry
|
||||
* identifier equal to the filename of the underlying definition resource, minus
|
||||
* the filename extension. For example, a XML-based flow definition defined in
|
||||
* the file "flow1.xml" will be identified as "flow1" when registered in a
|
||||
* registry.
|
||||
* By default, when configuring the {@link #setLocations(Resource[]) locations} property, flow definitions at those
|
||||
* locations will be assigned a registry identifier equal to the filename of the underlying definition resource, minus
|
||||
* the filename extension. For example, a XML-based flow definition defined in the file "flow1.xml" will be identified
|
||||
* as "flow1" when registered in a registry.
|
||||
* <p>
|
||||
* For full control over the assignment of flow identifiers and flow properties,
|
||||
* configure formal
|
||||
* {@link org.springframework.webflow.definition.registry.FlowDefinitionResource}
|
||||
* instances using the {@link #setResources(FlowDefinitionResource[] resources)} property.
|
||||
* For full control over the assignment of flow identifiers and flow properties, configure formal
|
||||
* {@link org.springframework.webflow.definition.registry.FlowDefinitionResource} instances using the
|
||||
* {@link #setResources(FlowDefinitionResource[] resources)} property.
|
||||
*
|
||||
* @see org.springframework.webflow.definition.registry.FlowDefinitionResource
|
||||
* @see org.springframework.webflow.definition.registry.FlowDefinitionRegistry
|
||||
@@ -53,23 +48,19 @@ import org.springframework.core.style.ToStringCreator;
|
||||
public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* File locations of externalized flow definition resources to load.
|
||||
* A set of {@link Resource}} objects.
|
||||
* File locations of externalized flow definition resources to load. A set of {@link Resource}} objects.
|
||||
*/
|
||||
private Set locations = new HashSet();
|
||||
|
||||
/**
|
||||
* A set of formal externalized flow definitions to load.
|
||||
* A set of {@link FlowDefinitionResource} objects.
|
||||
* A set of formal externalized flow definitions to load. A set of {@link FlowDefinitionResource} objects.
|
||||
*/
|
||||
private Set resources = new HashSet();
|
||||
|
||||
/**
|
||||
* Sets the locations (file paths) pointing to externalized flow
|
||||
* definitions.
|
||||
* Sets the locations (file paths) pointing to externalized flow definitions.
|
||||
* <p>
|
||||
* Flows registered from this set will be automatically assigned an id based
|
||||
* on the filename of the flow resource.
|
||||
* Flows registered from this set will be automatically assigned an id based on the filename of the flow resource.
|
||||
* @param locations the resource locations
|
||||
*/
|
||||
public void setLocations(Resource[] locations) {
|
||||
@@ -77,11 +68,10 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the formal set of externalized flow definitions this registrar will
|
||||
* register.
|
||||
* Sets the formal set of externalized flow definitions this registrar will register.
|
||||
* <p>
|
||||
* Use this method when you want full control over the assigned flow id and
|
||||
* the set of properties applied to the externalized flow resources.
|
||||
* Use this method when you want full control over the assigned flow id and the set of properties applied to the
|
||||
* externalized flow resources.
|
||||
* @param resources the externalized flow definition specifications
|
||||
*/
|
||||
public void setResources(FlowDefinitionResource[] resources) {
|
||||
@@ -91,8 +81,8 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
/**
|
||||
* Adds a flow location pointing to an externalized flow resource.
|
||||
* <p>
|
||||
* The flow registered from this location will automatically assigned an id
|
||||
* based on the filename of the flow resource.
|
||||
* The flow registered from this location will automatically assigned an id based on the filename of the flow
|
||||
* resource.
|
||||
* @param location the definition location
|
||||
*/
|
||||
public boolean addLocation(Resource location) {
|
||||
@@ -102,8 +92,8 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
/**
|
||||
* Adds the flow locations pointing to externalized flow resources.
|
||||
* <p>
|
||||
* The flow registered from this location will automatically assigned an id
|
||||
* based on the filename of the flow resource.
|
||||
* The flow registered from this location will automatically assigned an id based on the filename of the flow
|
||||
* resource.
|
||||
* @param locations the definition locations
|
||||
*/
|
||||
public boolean addLocations(Resource[] locations) {
|
||||
@@ -114,11 +104,10 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an externalized flow definition specification pointing to an
|
||||
* externalized flow resource.
|
||||
* Adds an externalized flow definition specification pointing to an externalized flow resource.
|
||||
* <p>
|
||||
* Use this method when you want full control over the assigned flow id and
|
||||
* the set of properties applied to the externalized flow resource.
|
||||
* Use this method when you want full control over the assigned flow id and the set of properties applied to the
|
||||
* externalized flow resource.
|
||||
* @param resource the definition the definition resource
|
||||
*/
|
||||
public boolean addResource(FlowDefinitionResource resource) {
|
||||
@@ -126,11 +115,10 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the externalized flow definitions pointing to externalized flow
|
||||
* resources.
|
||||
* Adds the externalized flow definitions pointing to externalized flow resources.
|
||||
* <p>
|
||||
* Use this method when you want full control over the assigned flow id and
|
||||
* the set of properties applied to the externalized flow resources.
|
||||
* Use this method when you want full control over the assigned flow id and the set of properties applied to the
|
||||
* externalized flow resources.
|
||||
* @param resources the definitions
|
||||
*/
|
||||
public boolean addResources(FlowDefinitionResource[] resources) {
|
||||
@@ -144,7 +132,7 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
processLocations(registry);
|
||||
processResources(registry);
|
||||
}
|
||||
|
||||
|
||||
// internal helpers
|
||||
|
||||
/**
|
||||
@@ -154,7 +142,7 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
private void processLocations(FlowDefinitionRegistry registry) {
|
||||
Iterator it = locations.iterator();
|
||||
while (it.hasNext()) {
|
||||
Resource location = (Resource)it.next();
|
||||
Resource location = (Resource) it.next();
|
||||
if (isFlowDefinitionResource(location)) {
|
||||
FlowDefinitionResource resource = createFlowDefinitionResource(location);
|
||||
register(resource, registry);
|
||||
@@ -169,16 +157,14 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
private void processResources(FlowDefinitionRegistry registry) {
|
||||
Iterator it = resources.iterator();
|
||||
while (it.hasNext()) {
|
||||
FlowDefinitionResource resource = (FlowDefinitionResource)it.next();
|
||||
FlowDefinitionResource resource = (FlowDefinitionResource) it.next();
|
||||
register(resource, registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to register the flow built from an externalized resource in
|
||||
* the registry.
|
||||
* @param resource representation of the externalized flow definition
|
||||
* resource
|
||||
* Helper method to register the flow built from an externalized resource in the registry.
|
||||
* @param resource representation of the externalized flow definition resource
|
||||
* @param registry the flow registry to register the flow in
|
||||
*/
|
||||
protected final void register(FlowDefinitionResource resource, FlowDefinitionRegistry registry) {
|
||||
@@ -186,12 +172,10 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
|
||||
/**
|
||||
* Template method that calculates if the given file resource is actually a
|
||||
* flow definition resource. Resources that aren't flow definitions will be
|
||||
* ignored. Subclasses may override; this implementation simply returns
|
||||
* true.
|
||||
* Template method that calculates if the given file resource is actually a flow definition resource. Resources that
|
||||
* aren't flow definitions will be ignored. Subclasses may override; this implementation simply returns true.
|
||||
* @param resource the underlying resource
|
||||
* @return true if yes, false otherwise
|
||||
*/
|
||||
@@ -200,8 +184,7 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that creates a flow definition from an externalized
|
||||
* resource location.
|
||||
* Factory method that creates a flow definition from an externalized resource location.
|
||||
* @param location the location of the resource
|
||||
* @return the externalized flow definition pointer
|
||||
*/
|
||||
@@ -210,8 +193,8 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
}
|
||||
|
||||
/**
|
||||
* Template factory method subclasses must override to return the holder for
|
||||
* the flow definition to be registered loaded from the specified resource.
|
||||
* Template factory method subclasses must override to return the holder for the flow definition to be registered
|
||||
* loaded from the specified resource.
|
||||
* @param resource the externalized resource
|
||||
* @return the flow definition holder
|
||||
*/
|
||||
|
||||
@@ -18,19 +18,18 @@ package org.springframework.webflow.definition.registry;
|
||||
import org.springframework.webflow.core.FlowException;
|
||||
|
||||
/**
|
||||
* Thrown when a flow definition was found during a lookup operation
|
||||
* but could not be constructed.
|
||||
* Thrown when a flow definition was found during a lookup operation but could not be constructed.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public abstract class FlowDefinitionConstructionException extends FlowException {
|
||||
|
||||
|
||||
/**
|
||||
* The id of the flow that could not be constructed.
|
||||
*/
|
||||
private String flowId;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an exception indicating a flow definition could not be constructed.
|
||||
* @param flowId the flow id
|
||||
@@ -40,7 +39,7 @@ public abstract class FlowDefinitionConstructionException extends FlowException
|
||||
super("An exception occured constructing the flow with id '" + flowId + "'", cause);
|
||||
this.flowId = flowId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the id of the flow definition that could not be constructed.
|
||||
* @return the flow id
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
package org.springframework.webflow.definition.registry;
|
||||
|
||||
/**
|
||||
* A strategy to use to populate a flow definition registry with one or more flow
|
||||
* definitions.
|
||||
* A strategy to use to populate a flow definition registry with one or more flow definitions.
|
||||
* <p>
|
||||
* Flow definition registrars encapsulate the knowledge about the source of a set of flow
|
||||
* definition resources and the behavior necessary to add those resources to a
|
||||
* flow definition registry.
|
||||
* Flow definition registrars encapsulate the knowledge about the source of a set of flow definition resources and the
|
||||
* behavior necessary to add those resources to a flow definition registry.
|
||||
* <p>
|
||||
* The typical usage pattern is as follows:
|
||||
* <ol>
|
||||
@@ -30,9 +28,8 @@ package org.springframework.webflow.definition.registry;
|
||||
* {@link #registerFlowDefinitions(FlowDefinitionRegistry)}.
|
||||
* </ol>
|
||||
* <p>
|
||||
* This design where various registrars populate a generic registry was
|
||||
* inspired by Spring's GenericApplicationContext, which can use any number of
|
||||
* BeanDefinitionReaders to drive context population.
|
||||
* This design where various registrars populate a generic registry was inspired by Spring's GenericApplicationContext,
|
||||
* which can use any number of BeanDefinitionReaders to drive context population.
|
||||
*
|
||||
* @see FlowDefinitionRegistry
|
||||
*
|
||||
@@ -41,8 +38,7 @@ package org.springframework.webflow.definition.registry;
|
||||
public interface FlowDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* Register flow definition resources managed by this registrar in the
|
||||
* registry provided.
|
||||
* Register flow definition resources managed by this registrar in the registry provided.
|
||||
* @param registry the registry to register flow definitions in
|
||||
*/
|
||||
public void registerFlowDefinitions(FlowDefinitionRegistry registry);
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.webflow.definition.registry;
|
||||
|
||||
|
||||
/**
|
||||
* A container of flow definitions. Extends the {@link FlowDefinitionRegistryMBean} management interface exposing
|
||||
* registry monitoring and management operations. Also extends {@link FlowDefinitionLocator} for accessing registered
|
||||
|
||||
@@ -24,9 +24,8 @@ import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
|
||||
/**
|
||||
* A pointer to an externalized flow definition resource. Adds assigned
|
||||
* identification information about the resource including the flow id and
|
||||
* attributes.
|
||||
* A pointer to an externalized flow definition resource. Adds assigned identification information about the resource
|
||||
* including the flow id and attributes.
|
||||
*
|
||||
* @see ExternalizedFlowDefinitionRegistrar
|
||||
*
|
||||
@@ -50,17 +49,17 @@ public class FlowDefinitionResource implements Serializable {
|
||||
private Resource location;
|
||||
|
||||
/**
|
||||
* Creates a new externalized flow definition resource. The flow id assigned will be
|
||||
* the same name as the externalized resource's filename, excluding the extension.
|
||||
* Creates a new externalized flow definition resource. The flow id assigned will be the same name as the
|
||||
* externalized resource's filename, excluding the extension.
|
||||
* @param location the flow resource location
|
||||
*/
|
||||
public FlowDefinitionResource(Resource location) {
|
||||
init(conventionalFlowId(location), location, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new externalized flow definition resource. The flow id assigned will be
|
||||
* the same name as the externalized resource's filename, excluding the extension.
|
||||
* Creates a new externalized flow definition resource. The flow id assigned will be the same name as the
|
||||
* externalized resource's filename, excluding the extension.
|
||||
* @param location the flow resource location
|
||||
* @param attributes flow definition attributes to be assigned
|
||||
*/
|
||||
@@ -112,14 +111,14 @@ public class FlowDefinitionResource implements Serializable {
|
||||
if (!(o instanceof FlowDefinitionResource)) {
|
||||
return false;
|
||||
}
|
||||
FlowDefinitionResource other = (FlowDefinitionResource)o;
|
||||
FlowDefinitionResource other = (FlowDefinitionResource) o;
|
||||
return id.equals(other.id) && location.equals(other.location);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return id.hashCode() + location.hashCode();
|
||||
}
|
||||
|
||||
|
||||
// internal helpers
|
||||
|
||||
/**
|
||||
@@ -132,17 +131,16 @@ public class FlowDefinitionResource implements Serializable {
|
||||
this.location = location;
|
||||
if (attributes != null) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.attributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// public utilities
|
||||
|
||||
/**
|
||||
* Returns the flow id assigned to the flow definition contained in given resource.
|
||||
* By convention this will be the filename of the resource, excluding extension.
|
||||
* Returns the flow id assigned to the flow definition contained in given resource. By convention this will be the
|
||||
* filename of the resource, excluding extension.
|
||||
* @see FlowDefinitionResource#FlowDefinitionResource(Resource)
|
||||
* @see FlowDefinitionResource#FlowDefinitionResource(Resource, AttributeMap)
|
||||
* @since 1.0.1
|
||||
@@ -152,8 +150,7 @@ public class FlowDefinitionResource implements Serializable {
|
||||
int extensionIndex = fileName.lastIndexOf('.');
|
||||
if (extensionIndex != -1) {
|
||||
return fileName.substring(0, extensionIndex);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,7 @@ import org.springframework.core.style.StylerUtils;
|
||||
import org.springframework.webflow.core.FlowException;
|
||||
|
||||
/**
|
||||
* Thrown when no flow definition was found during a lookup operation by a flow
|
||||
* locator.
|
||||
* Thrown when no flow definition was found during a lookup operation by a flow locator.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -35,8 +34,7 @@ public class NoSuchFlowDefinitionException extends FlowException {
|
||||
/**
|
||||
* Creates an exception indicating a flow definition could not be found.
|
||||
* @param flowId the flow id
|
||||
* @param availableFlowIds all flow ids available to the locator generating
|
||||
* this exception
|
||||
* @param availableFlowIds all flow ids available to the locator generating this exception
|
||||
*/
|
||||
public NoSuchFlowDefinitionException(String flowId, String[] availableFlowIds) {
|
||||
super("No such flow definition with id '" + flowId + "' found; the flows available are: "
|
||||
|
||||
@@ -20,9 +20,8 @@ import org.springframework.webflow.execution.Action;
|
||||
import org.springframework.webflow.execution.FlowExecutionException;
|
||||
|
||||
/**
|
||||
* Thrown if an unhandled exception occurs when an action is executed. Typically
|
||||
* wraps another exception noting the root cause failure. The root cause may be
|
||||
* checked or unchecked.
|
||||
* Thrown if an unhandled exception occurs when an action is executed. Typically wraps another exception noting the root
|
||||
* cause failure. The root cause may be checked or unchecked.
|
||||
*
|
||||
* @see org.springframework.webflow.execution.Action
|
||||
* @see org.springframework.webflow.engine.ActionState
|
||||
@@ -40,8 +39,8 @@ public class ActionExecutionException extends FlowExecutionException {
|
||||
* @param executionAttributes action execution properties that may have contributed to this failure
|
||||
* @param cause the underlying cause
|
||||
*/
|
||||
public ActionExecutionException(String flowId, String stateId, Action action,
|
||||
AttributeMap executionAttributes, Throwable cause) {
|
||||
public ActionExecutionException(String flowId, String stateId, Action action, AttributeMap executionAttributes,
|
||||
Throwable cause) {
|
||||
super(flowId, stateId, "Exception thrown executing " + action + " in state '" + stateId + "' of flow '"
|
||||
+ flowId + "' -- action execution attributes were '" + executionAttributes + "'", cause);
|
||||
}
|
||||
@@ -55,8 +54,8 @@ public class ActionExecutionException extends FlowExecutionException {
|
||||
* @param message a descriptive message
|
||||
* @param cause the underlying cause
|
||||
*/
|
||||
public ActionExecutionException(String flowId, String stateId, Action action,
|
||||
AttributeMap executionAttributes, String message, Throwable cause) {
|
||||
public ActionExecutionException(String flowId, String stateId, Action action, AttributeMap executionAttributes,
|
||||
String message, Throwable cause) {
|
||||
super(flowId, stateId, message, cause);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,8 @@ import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* A simple static helper that performs action execution that encapsulates
|
||||
* common logging and exception handling logic. This is an internal helper class
|
||||
* that is not normally used by application code.
|
||||
* A simple static helper that performs action execution that encapsulates common logging and exception handling logic.
|
||||
* This is an internal helper class that is not normally used by application code.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -44,26 +43,23 @@ public class ActionExecutor {
|
||||
* @param action the action to execute
|
||||
* @param context the flow execution request context
|
||||
* @return result of action execution
|
||||
* @throws ActionExecutionException if the action threw an exception while
|
||||
* executing, the orginal exception is available as the cause if this exception
|
||||
* @throws ActionExecutionException if the action threw an exception while executing, the orginal exception is
|
||||
* available as the cause if this exception
|
||||
*/
|
||||
public static Event execute(Action action, RequestContext context) throws ActionExecutionException {
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (context.getCurrentState() == null) {
|
||||
logger.debug("Executing start " + action + " for flow '" + context.getActiveFlow().getId() + "'");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logger.debug("Executing " + action + " in state '" + context.getCurrentState().getId()
|
||||
+ "' of flow '" + context.getActiveFlow().getId() + "'");
|
||||
}
|
||||
}
|
||||
return action.execute(context);
|
||||
}
|
||||
catch (ActionExecutionException e) {
|
||||
} catch (ActionExecutionException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
// wrap the exception as an ActionExecutionException
|
||||
throw new ActionExecutionException(context.getActiveFlow().getId(),
|
||||
context.getCurrentState() != null ? context.getCurrentState().getId() : null, action, context
|
||||
|
||||
@@ -25,8 +25,7 @@ import org.springframework.webflow.execution.Action;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* An ordered, typed list of actions, mainly for use internally by flow artifacts
|
||||
* that can execute groups of actions.
|
||||
* An ordered, typed list of actions, mainly for use internally by flow artifacts that can execute groups of actions.
|
||||
*
|
||||
* @see Flow#getStartActionList()
|
||||
* @see Flow#getEndActionList()
|
||||
@@ -47,8 +46,7 @@ public class ActionList {
|
||||
/**
|
||||
* Add an action to this list.
|
||||
* @param action the action to add
|
||||
* @return true if this list's contents changed as a result of the add
|
||||
* operation
|
||||
* @return true if this list's contents changed as a result of the add operation
|
||||
*/
|
||||
public boolean add(Action action) {
|
||||
return actions.add(action);
|
||||
@@ -57,8 +55,7 @@ public class ActionList {
|
||||
/**
|
||||
* Add a collection of actions to this list.
|
||||
* @param actions the actions to add
|
||||
* @return true if this list's contents changed as a result of the add
|
||||
* operation
|
||||
* @return true if this list's contents changed as a result of the add operation
|
||||
*/
|
||||
public boolean addAll(Action[] actions) {
|
||||
if (actions == null) {
|
||||
@@ -79,8 +76,7 @@ public class ActionList {
|
||||
/**
|
||||
* Remove the action instance from this list.
|
||||
* @param action the action to add
|
||||
* @return true if this list's contents changed as a result of the remove
|
||||
* operation
|
||||
* @return true if this list's contents changed as a result of the remove operation
|
||||
*/
|
||||
public boolean remove(Action action) {
|
||||
return actions.remove(action);
|
||||
@@ -100,21 +96,19 @@ public class ActionList {
|
||||
* @return the action the action
|
||||
*/
|
||||
public Action get(int index) throws IndexOutOfBoundsException {
|
||||
return (Action)actions.get(index);
|
||||
return (Action) actions.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action in this list at the provided index, exposing it as an
|
||||
* annotated action. This allows clients to access specific properties about
|
||||
* a target action instance if they exist.
|
||||
* Returns the action in this list at the provided index, exposing it as an annotated action. This allows clients to
|
||||
* access specific properties about a target action instance if they exist.
|
||||
* @return the action, as an annotated action
|
||||
*/
|
||||
public AnnotatedAction getAnnotated(int index) throws IndexOutOfBoundsException {
|
||||
Action action = get(index);
|
||||
if (action instanceof AnnotatedAction) {
|
||||
return (AnnotatedAction)action;
|
||||
}
|
||||
else {
|
||||
return (AnnotatedAction) action;
|
||||
} else {
|
||||
// wrap the action; no annotations will be available
|
||||
return new AnnotatedAction(action);
|
||||
}
|
||||
@@ -132,13 +126,12 @@ public class ActionList {
|
||||
* @return the action list, as a typed array
|
||||
*/
|
||||
public Action[] toArray() {
|
||||
return (Action[])actions.toArray(new Action[actions.size()]);
|
||||
return (Action[]) actions.toArray(new Action[actions.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of actions in this list as a typed annotated action
|
||||
* array. This is a convenience method allowing clients to access properties
|
||||
* about an action if they exist.
|
||||
* Returns the list of actions in this list as a typed annotated action array. This is a convenience method allowing
|
||||
* clients to access properties about an action if they exist.
|
||||
* @return the annotated action list, as a typed array
|
||||
*/
|
||||
public AnnotatedAction[] toAnnotatedArray() {
|
||||
@@ -150,14 +143,14 @@ public class ActionList {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the actions contained within this action list. Simply iterates
|
||||
* over each action and calls execute. Action result events are ignored.
|
||||
* Executes the actions contained within this action list. Simply iterates over each action and calls execute.
|
||||
* Action result events are ignored.
|
||||
* @param context the action execution request context
|
||||
*/
|
||||
public void execute(RequestContext context) {
|
||||
Iterator it = actions.iterator();
|
||||
while (it.hasNext()) {
|
||||
ActionExecutor.execute((Action)it.next(), context);
|
||||
ActionExecutor.execute((Action) it.next(), context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,24 +26,18 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A transitionable state that executes one or more actions when entered. When
|
||||
* the action(s) are executed this state responds to their result(s) to decide
|
||||
* what state to transition to next.
|
||||
* A transitionable state that executes one or more actions when entered. When the action(s) are executed this state
|
||||
* responds to their result(s) to decide what state to transition to next.
|
||||
* <p>
|
||||
* If more than one action is configured they are executed in an ordered chain
|
||||
* until one returns a result event that matches a state transition out of
|
||||
* this state. This is a form of the Chain of Responsibility (CoR) pattern.
|
||||
* If more than one action is configured they are executed in an ordered chain until one returns a result event that
|
||||
* matches a state transition out of this state. This is a form of the Chain of Responsibility (CoR) pattern.
|
||||
* <p>
|
||||
* The result of an action's execution is typically the criteria for a
|
||||
* transition out of this state. Additional information in the current
|
||||
* {@link RequestContext} may also be tested as part of custom transitional
|
||||
* criteria, allowing for sophisticated transition expressions that reason on
|
||||
* contextual state.
|
||||
* The result of an action's execution is typically the criteria for a transition out of this state. Additional
|
||||
* information in the current {@link RequestContext} may also be tested as part of custom transitional criteria,
|
||||
* allowing for sophisticated transition expressions that reason on contextual state.
|
||||
* <p>
|
||||
* Each action executed by this action state may be provisioned with a set of
|
||||
* arbitrary execution properties. These properties are made available to the
|
||||
* action at execution time and may be used to influence action execution
|
||||
* behavior.
|
||||
* Each action executed by this action state may be provisioned with a set of arbitrary execution properties. These
|
||||
* properties are made available to the action at execution time and may be used to influence action execution behavior.
|
||||
* <p>
|
||||
* Common action execution properties include:
|
||||
* <p>
|
||||
@@ -52,17 +46,13 @@ import org.springframework.webflow.execution.ViewSelection;
|
||||
* <th>Description</th>
|
||||
* <tr>
|
||||
* <td valign="top">name</td>
|
||||
* <td>The 'name' property is used as a qualifier for an action's result event,
|
||||
* and is typically used to allow the flow to respond to a specific action's
|
||||
* outcome within a larger action chain. For example, if an action named
|
||||
* <code>myAction</code> returns a <code>success</code> result, a transition
|
||||
* that matches on event <code>myAction.success</code> will be searched, and
|
||||
* if found, executed. If this action is not assigned a name a transition for
|
||||
* the base <code>success</code> event will be searched and if found,
|
||||
* executed.<br>
|
||||
* This is useful in situations where you want to execute actions in an ordered
|
||||
* chain as part of one action state, and wish to transition on the result of
|
||||
* the last one in the chain. For example:
|
||||
* <td>The 'name' property is used as a qualifier for an action's result event, and is typically used to allow the flow
|
||||
* to respond to a specific action's outcome within a larger action chain. For example, if an action named
|
||||
* <code>myAction</code> returns a <code>success</code> result, a transition that matches on event
|
||||
* <code>myAction.success</code> will be searched, and if found, executed. If this action is not assigned a name a
|
||||
* transition for the base <code>success</code> event will be searched and if found, executed.<br>
|
||||
* This is useful in situations where you want to execute actions in an ordered chain as part of one action state, and
|
||||
* wish to transition on the result of the last one in the chain. For example:
|
||||
*
|
||||
* <pre>
|
||||
* <action-state id="setupForm">
|
||||
@@ -72,36 +62,29 @@ import org.springframework.webflow.execution.ViewSelection;
|
||||
* </action-state>
|
||||
* </pre>
|
||||
*
|
||||
* When the 'setupForm' state above is entered, the 'setup' action will execute,
|
||||
* followed by the 'referenceData' action. After 'referenceData' execution, the
|
||||
* flow will then respond to the 'referenceData.success' event by transitioning
|
||||
* to the 'displayForm' state. The 'setup.success' event that was signaled by
|
||||
* the 'setup' action will effectively be ignored.</td>
|
||||
* When the 'setupForm' state above is entered, the 'setup' action will execute, followed by the 'referenceData' action.
|
||||
* After 'referenceData' execution, the flow will then respond to the 'referenceData.success' event by transitioning to
|
||||
* the 'displayForm' state. The 'setup.success' event that was signaled by the 'setup' action will effectively be
|
||||
* ignored.</td>
|
||||
* <tr>
|
||||
* <td valign="top">method</td>
|
||||
* <td>The 'method' property is the name of a target method on a
|
||||
* <code>{@link org.springframework.webflow.action.MultiAction}</code> to
|
||||
* execute. In the MultiAction scenario the named method must have the signature
|
||||
* <code>public Event ${method}(RequestContext) throws Exception</code>.
|
||||
* As an example of this scenario, a method property with value <code>setupForm</code>
|
||||
* would bind to a method on a MultiAction instance with the signature:
|
||||
* <code>public Event setupForm(RequestContext context)</code>. <br>
|
||||
* As an alternative to a MultiAction method binding, this action state may
|
||||
* excute a
|
||||
* {@link org.springframework.webflow.action.AbstractBeanInvokingAction bean invoking action}
|
||||
* that invokes a method on a POJO (Plain Old Java Object). If the method
|
||||
* signature accepts arguments those arguments may be specified by using the
|
||||
* <code>{@link org.springframework.webflow.action.MultiAction}</code> to execute. In the MultiAction scenario the
|
||||
* named method must have the signature <code>public Event ${method}(RequestContext) throws Exception</code>. As an
|
||||
* example of this scenario, a method property with value <code>setupForm</code> would bind to a method on a
|
||||
* MultiAction instance with the signature: <code>public Event setupForm(RequestContext context)</code>. <br>
|
||||
* As an alternative to a MultiAction method binding, this action state may excute a
|
||||
* {@link org.springframework.webflow.action.AbstractBeanInvokingAction bean invoking action} that invokes a method on a
|
||||
* POJO (Plain Old Java Object). If the method signature accepts arguments those arguments may be specified by using the
|
||||
* format:
|
||||
*
|
||||
* <pre>
|
||||
* methodName(${arg1}, ${arg2}, ...)
|
||||
* </pre>
|
||||
*
|
||||
* Argument ${expressions} are evaluated against the current
|
||||
* <code>RequestContext</code>, allowing for data stored in flow scope or
|
||||
* request scope to be passed as arguments to the POJO. In addition, POJO return
|
||||
* values may be exposed to the flow automatically. See the bean invoking action
|
||||
* type hierarchy for more information. </td>
|
||||
* Argument ${expressions} are evaluated against the current <code>RequestContext</code>, allowing for data stored in
|
||||
* flow scope or request scope to be passed as arguments to the POJO. In addition, POJO return values may be exposed to
|
||||
* the flow automatically. See the bean invoking action type hierarchy for more information. </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
@@ -123,8 +106,7 @@ public class ActionState extends TransitionableState {
|
||||
* Creates a new action state.
|
||||
* @param flow the owning flow
|
||||
* @param id the state identifier (must be unique to the flow)
|
||||
* @throws IllegalArgumentException when this state cannot be added to given flow,
|
||||
* e.g. beasue the id is not unique
|
||||
* @throws IllegalArgumentException when this state cannot be added to given flow, e.g. beasue the id is not unique
|
||||
* @see #getActionList()
|
||||
*/
|
||||
public ActionState(Flow flow, String id) throws IllegalArgumentException {
|
||||
@@ -132,8 +114,7 @@ public class ActionState extends TransitionableState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of actions executable by this action state. The
|
||||
* returned list is mutable.
|
||||
* Returns the list of actions executable by this action state. The returned list is mutable.
|
||||
* @return the state action list
|
||||
*/
|
||||
public ActionList getActionList() {
|
||||
@@ -141,13 +122,10 @@ public class ActionState extends TransitionableState {
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides getRequiredTransition(RequestContext) to throw a local
|
||||
* NoMatchingActionResultTransitionException if a transition on the
|
||||
* occurence of an action result event cannot be matched. Used to facilitate
|
||||
* an action invocation chain.
|
||||
* <p>Note that we cannot catch NoMatchingTransitionException since that could lead to unwanted
|
||||
* situations where we're catching an exception that's generated by another
|
||||
* state, e.g. because of a configuration error!
|
||||
* Overrides getRequiredTransition(RequestContext) to throw a local NoMatchingActionResultTransitionException if a
|
||||
* transition on the occurence of an action result event cannot be matched. Used to facilitate an action invocation
|
||||
* chain. <p>Note that we cannot catch NoMatchingTransitionException since that could lead to unwanted situations
|
||||
* where we're catching an exception that's generated by another state, e.g. because of a configuration error!
|
||||
*/
|
||||
public Transition getRequiredTransition(RequestContext context) throws NoMatchingTransitionException {
|
||||
Transition transition = getTransitionSet().getTransition(context);
|
||||
@@ -158,17 +136,15 @@ public class ActionState extends TransitionableState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of State's <code>doEnter</code> template method that
|
||||
* executes behaviour specific to this state type in polymorphic fashion.
|
||||
* Specialization of State's <code>doEnter</code> template method that executes behaviour specific to this state
|
||||
* type in polymorphic fashion.
|
||||
* <p>
|
||||
* This implementation iterates over each configured <code>Action</code>
|
||||
* instance and executes it. Execution continues until an
|
||||
* <code>Action</code> returns a result event that matches a transition in
|
||||
* this request context, or the set of all actions is exhausted.
|
||||
* @param context the control context for the currently executing flow, used
|
||||
* by this state to manipulate the flow execution
|
||||
* @return a view selection signaling that control should be returned to the
|
||||
* client and a view rendered
|
||||
* This implementation iterates over each configured <code>Action</code> instance and executes it. Execution
|
||||
* continues until an <code>Action</code> returns a result event that matches a transition in this request
|
||||
* context, or the set of all actions is exhausted.
|
||||
* @param context the control context for the currently executing flow, used by this state to manipulate the flow
|
||||
* execution
|
||||
* @return a view selection signaling that control should be returned to the client and a view rendered
|
||||
* @throws FlowExecutionException if an exception occurs in this state
|
||||
*/
|
||||
protected ViewSelection doEnter(RequestControlContext context) throws FlowExecutionException {
|
||||
@@ -176,15 +152,14 @@ public class ActionState extends TransitionableState {
|
||||
String[] eventIds = new String[actionList.size()];
|
||||
Iterator it = actionList.iterator();
|
||||
while (it.hasNext()) {
|
||||
Action action = (Action)it.next();
|
||||
Action action = (Action) it.next();
|
||||
Event event = ActionExecutor.execute(action, context);
|
||||
if (event != null) {
|
||||
eventIds[executionCount] = event.getId();
|
||||
try {
|
||||
// will check both local state transitions and global transitions
|
||||
return context.signalEvent(event);
|
||||
}
|
||||
catch (NoMatchingActionResultTransitionException e) {
|
||||
} catch (NoMatchingActionResultTransitionException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Action execution ["
|
||||
+ (executionCount + 1)
|
||||
@@ -195,14 +170,14 @@ public class ActionState extends TransitionableState {
|
||||
: ": action list exhausted"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Action execution ["
|
||||
+ (executionCount + 1)
|
||||
+ "] returned a [null] event"
|
||||
+ (it.hasNext() ? ": proceeding to the next action in the list"
|
||||
: ": action list exhausted"));
|
||||
logger
|
||||
.debug("Action execution ["
|
||||
+ (executionCount + 1)
|
||||
+ "] returned a [null] event"
|
||||
+ (it.hasNext() ? ": proceeding to the next action in the list"
|
||||
: ": action list exhausted"));
|
||||
}
|
||||
eventIds[executionCount] = null;
|
||||
}
|
||||
@@ -211,17 +186,16 @@ public class ActionState extends TransitionableState {
|
||||
if (executionCount > 0) {
|
||||
throw new NoMatchingTransitionException(getFlow().getId(), getId(), context.getLastEvent(),
|
||||
"No transition was matched on the event(s) signaled by the [" + executionCount
|
||||
+ "] action(s) that executed in this action state '" + getId() + "' of flow '"
|
||||
+ getFlow().getId() + "'; transitions must be defined to handle action result outcomes -- "
|
||||
+ "possible flow configuration error? Note: the eventIds signaled were: '"
|
||||
+ StylerUtils.style(eventIds)
|
||||
+ "', while the supported set of transitional criteria for this action state is '"
|
||||
+ StylerUtils.style(getTransitionSet().getTransitionCriterias()) + "'");
|
||||
}
|
||||
else {
|
||||
+ "] action(s) that executed in this action state '" + getId() + "' of flow '"
|
||||
+ getFlow().getId() + "'; transitions must be defined to handle action result outcomes -- "
|
||||
+ "possible flow configuration error? Note: the eventIds signaled were: '"
|
||||
+ StylerUtils.style(eventIds)
|
||||
+ "', while the supported set of transitional criteria for this action state is '"
|
||||
+ StylerUtils.style(getTransitionSet().getTransitionCriterias()) + "'");
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"No actions were executed, thus I cannot execute any state transition "
|
||||
+ "-- programmer configuration error; make sure you add at least one action to this state's action list");
|
||||
+ "-- programmer configuration error; make sure you add at least one action to this state's action list");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,8 +205,8 @@ public class ActionState extends TransitionableState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Local "no transition found" exception used to report that an action
|
||||
* result could not be mapped to a state transition.
|
||||
* Local "no transition found" exception used to report that an action result could not be mapped to a state
|
||||
* transition.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
|
||||
@@ -24,14 +24,12 @@ import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* An action proxy/decorator that stores arbitrary properties about a target
|
||||
* <code>Action</code> implementation for use within a specific Action
|
||||
* execution context, for example an <code>ActionState</code> definition, a
|
||||
* An action proxy/decorator that stores arbitrary properties about a target <code>Action</code> implementation for
|
||||
* use within a specific Action execution context, for example an <code>ActionState</code> definition, a
|
||||
* <code>TransitionCriteria</code> definition, or in a test environment.
|
||||
* <p>
|
||||
* An annotated action is an action that wraps another action (referred to as
|
||||
* the <i>target</i> action), setting up the target action's execution attributes
|
||||
* before invoking {@link Action#execute}.
|
||||
* An annotated action is an action that wraps another action (referred to as the <i>target</i> action), setting up the
|
||||
* target action's execution attributes before invoking {@link Action#execute}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -43,9 +41,8 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
/**
|
||||
* The action name attribute ("name").
|
||||
* <p>
|
||||
* The name attribute is often used as a qualifier for an action's result
|
||||
* event, and is typically used to allow the flow to respond to a specific
|
||||
* action's outcome within a larger action execution chain.
|
||||
* The name attribute is often used as a qualifier for an action's result event, and is typically used to allow the
|
||||
* flow to respond to a specific action's outcome within a larger action execution chain.
|
||||
* @see ActionState
|
||||
*/
|
||||
public static final String NAME_ATTRIBUTE = "name";
|
||||
@@ -53,9 +50,8 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
/**
|
||||
* The action execution method attribute ("method").
|
||||
* <p>
|
||||
* The method property is a hint about what method should be invoked; for
|
||||
* example, the name of a specific target method on a
|
||||
* {@link org.springframework.webflow.action.MultiAction multi action}.
|
||||
* The method property is a hint about what method should be invoked; for example, the name of a specific target
|
||||
* method on a {@link org.springframework.webflow.action.MultiAction multi action}.
|
||||
* @see ActionState
|
||||
*/
|
||||
public static final String METHOD_ATTRIBUTE = "method";
|
||||
@@ -66,8 +62,7 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
private Action targetAction;
|
||||
|
||||
/**
|
||||
* Creates a new annotated action object for the specified action. No
|
||||
* contextual properties are provided.
|
||||
* Creates a new annotated action object for the specified action. No contextual properties are provided.
|
||||
* @param targetAction the action
|
||||
*/
|
||||
public AnnotatedAction(Action targetAction) {
|
||||
@@ -91,8 +86,8 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a named action, or <code>null</code> if the action
|
||||
* is unnamed. Used when mapping action result events to transitions.
|
||||
* Returns the name of a named action, or <code>null</code> if the action is unnamed. Used when mapping action
|
||||
* result events to transitions.
|
||||
* @see #isNamed()
|
||||
* @see #postProcessResult(Event)
|
||||
*/
|
||||
@@ -101,8 +96,7 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of a named action. This is optional and can be
|
||||
* <code>null</code>.
|
||||
* Sets the name of a named action. This is optional and can be <code>null</code>.
|
||||
* @param name the action name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
@@ -117,24 +111,22 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
public boolean isNamed() {
|
||||
return StringUtils.hasText(getName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the action method to invoke when the target action is
|
||||
* executed.
|
||||
* Returns the name of the action method to invoke when the target action is executed.
|
||||
*/
|
||||
public String getMethod() {
|
||||
return getAttributeMap().getString(METHOD_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the action method to invoke when the target action is
|
||||
* executed.
|
||||
* Sets the name of the action method to invoke when the target action is executed.
|
||||
* @param method the action method name
|
||||
*/
|
||||
public void setMethod(String method) {
|
||||
getAttributeMap().put(METHOD_ATTRIBUTE, method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set an attribute on this annotated object.
|
||||
* @param attributeName the name of the attribute to set
|
||||
@@ -145,7 +137,7 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
public AnnotatedAction putAttribute(String attributeName, Object attributeValue) {
|
||||
getAttributeMap().put(attributeName, attributeValue);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public Event execute(RequestContext context) throws Exception {
|
||||
AttributeMap originalAttributes = getAttributeMap();
|
||||
@@ -153,19 +145,17 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
context.setAttributes(getAttributeMap());
|
||||
Event result = getTargetAction().execute(context);
|
||||
return postProcessResult(result);
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
// restore original attributes
|
||||
context.setAttributes(originalAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the event id to be used as grounds for a transition in the containing
|
||||
* state, based on given result returned from action execution.
|
||||
* Get the event id to be used as grounds for a transition in the containing state, based on given result returned
|
||||
* from action execution.
|
||||
* <p>
|
||||
* If the wrapped action is named, the name will be used as a qualifier for
|
||||
* the event (e.g. "myAction.success").
|
||||
* If the wrapped action is named, the name will be used as a qualifier for the event (e.g. "myAction.success").
|
||||
* @param resultEvent the action result event
|
||||
*/
|
||||
protected Event postProcessResult(Event resultEvent) {
|
||||
@@ -181,7 +171,7 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("targetAction", getTargetAction())
|
||||
.append("attributes", getAttributeMap()).toString();
|
||||
return new ToStringCreator(this).append("targetAction", getTargetAction()).append("attributes",
|
||||
getAttributeMap()).toString();
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,8 @@ import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.definition.Annotated;
|
||||
|
||||
/**
|
||||
* A base class for all objects in the web flow system that support annotation
|
||||
* using arbitrary properties. Mainly used to ensure consistent configuration of
|
||||
* properties for all annotated objects.
|
||||
* A base class for all objects in the web flow system that support annotation using arbitrary properties. Mainly used
|
||||
* to ensure consistent configuration of properties for all annotated objects.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
* @author Keith Donald
|
||||
@@ -31,26 +30,24 @@ import org.springframework.webflow.definition.Annotated;
|
||||
public abstract class AnnotatedObject implements Annotated {
|
||||
|
||||
/**
|
||||
* The caption property name ("caption"). A caption is also known as a
|
||||
* "short description" and may be used in a GUI tooltip.
|
||||
* The caption property name ("caption"). A caption is also known as a "short description" and may be used in a GUI
|
||||
* tooltip.
|
||||
*/
|
||||
public static final String CAPTION_PROPERTY = "caption";
|
||||
|
||||
/**
|
||||
* The long description property name ("description"). A description
|
||||
* provides additional, free-form detail about this object and might be
|
||||
* shown in a GUI text area.
|
||||
* The long description property name ("description"). A description provides additional, free-form detail about
|
||||
* this object and might be shown in a GUI text area.
|
||||
*/
|
||||
public static final String DESCRIPTION_PROPERTY = "description";
|
||||
|
||||
/**
|
||||
* Additional properties further describing this object. The properties set
|
||||
* in this map may be arbitrary.
|
||||
* Additional properties further describing this object. The properties set in this map may be arbitrary.
|
||||
*/
|
||||
private LocalAttributeMap attributes = new LocalAttributeMap();
|
||||
|
||||
// implementing Annotated
|
||||
|
||||
|
||||
public String getCaption() {
|
||||
return attributes.getString(CAPTION_PROPERTY);
|
||||
}
|
||||
@@ -62,9 +59,9 @@ public abstract class AnnotatedObject implements Annotated {
|
||||
public AttributeMap getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
||||
// mutators
|
||||
|
||||
|
||||
/**
|
||||
* Sets the short description (suitable for display in a tooltip).
|
||||
* @param caption the caption
|
||||
@@ -82,8 +79,7 @@ public abstract class AnnotatedObject implements Annotated {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mutable attribute map for this annotated object. May be used
|
||||
* to set attributes after construction.
|
||||
* Returns the mutable attribute map for this annotated object. May be used to set attributes after construction.
|
||||
*/
|
||||
public MutableAttributeMap getAttributeMap() {
|
||||
return attributes;
|
||||
|
||||
@@ -20,12 +20,10 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A simple transitionable state that when entered will execute the first
|
||||
* transition whose matching criteria evaluates to <code>true</code> in the
|
||||
* {@link RequestContext context} of the current request.
|
||||
* A simple transitionable state that when entered will execute the first transition whose matching criteria evaluates
|
||||
* to <code>true</code> in the {@link RequestContext context} of the current request.
|
||||
* <p>
|
||||
* A decision state is a convenient, simple way to encapsulate reusable state
|
||||
* transition logic in one place.
|
||||
* A decision state is a convenient, simple way to encapsulate reusable state transition logic in one place.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -35,23 +33,21 @@ public class DecisionState extends TransitionableState {
|
||||
* Creates a new decision state.
|
||||
* @param flow the owning flow
|
||||
* @param stateId the state identifier (must be unique to the flow)
|
||||
* @throws IllegalArgumentException when this state cannot be added to given
|
||||
* flow, e.g. because the id is not unique
|
||||
* @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique
|
||||
*/
|
||||
public DecisionState(Flow flow, String stateId) throws IllegalArgumentException {
|
||||
super(flow, stateId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of State's <code>doEnter</code> template method that
|
||||
* executes behaviour specific to this state type in polymorphic fashion.
|
||||
* Specialization of State's <code>doEnter</code> template method that executes behaviour specific to this state
|
||||
* type in polymorphic fashion.
|
||||
* <p>
|
||||
* Simply looks up the first transition that matches the state of the
|
||||
* context and executes it.
|
||||
* @param context the control context for the currently executing flow, used
|
||||
* by this state to manipulate the flow execution
|
||||
* @return a view selection containing model and view information needed to
|
||||
* render the results of the state execution
|
||||
* Simply looks up the first transition that matches the state of the context and executes it.
|
||||
* @param context the control context for the currently executing flow, used by this state to manipulate the flow
|
||||
* execution
|
||||
* @return a view selection containing model and view information needed to render the results of the state
|
||||
* execution
|
||||
* @throws FlowExecutionException if an exception occurs in this state
|
||||
*/
|
||||
protected ViewSelection doEnter(RequestControlContext context) throws FlowExecutionException {
|
||||
|
||||
@@ -26,28 +26,23 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A state that ends a flow when entered. More specifically, this state ends the
|
||||
* active flow session of the active flow execution associated with the current
|
||||
* request context.
|
||||
* A state that ends a flow when entered. More specifically, this state ends the active flow session of the active flow
|
||||
* execution associated with the current request context.
|
||||
* <p>
|
||||
* If the ended session is the "root flow session" the entire flow execution
|
||||
* ends, signaling the end of a logical conversation.
|
||||
* If the ended session is the "root flow session" the entire flow execution ends, signaling the end of a logical
|
||||
* conversation.
|
||||
* <p>
|
||||
* If the terminated session was acting as a subflow the flow execution
|
||||
* continues and control is returned to the parent flow session. In that case,
|
||||
* this state returns an ending result event the resuming parent flow is
|
||||
* expected to respond to.
|
||||
* If the terminated session was acting as a subflow the flow execution continues and control is returned to the parent
|
||||
* flow session. In that case, this state returns an ending result event the resuming parent flow is expected to respond
|
||||
* to.
|
||||
* <p>
|
||||
* An end state may optionally be configured with the name of a view to render
|
||||
* when entered. This view will be rendered if the end state terminates the
|
||||
* entire flow execution as a kind of flow ending "confirmation page".
|
||||
* An end state may optionally be configured with the name of a view to render when entered. This view will be rendered
|
||||
* if the end state terminates the entire flow execution as a kind of flow ending "confirmation page".
|
||||
* <p>
|
||||
* Note: if no <code>viewName</code> property is specified <b>and</b> this
|
||||
* end state terminates the entire flow execution it is expected that some
|
||||
* action has already written the response (or else a blank response will
|
||||
* result). On the other hand, if no <code>viewName</code> is specified <b>and</b>
|
||||
* this end state relinquishes control back to a parent flow, view selection
|
||||
* responsibility falls on the parent flow.
|
||||
* Note: if no <code>viewName</code> property is specified <b>and</b> this end state terminates the entire flow
|
||||
* execution it is expected that some action has already written the response (or else a blank response will result). On
|
||||
* the other hand, if no <code>viewName</code> is specified <b>and</b> this end state relinquishes control back to a
|
||||
* parent flow, view selection responsibility falls on the parent flow.
|
||||
*
|
||||
* @see org.springframework.webflow.engine.ViewSelector
|
||||
* @see org.springframework.webflow.engine.SubflowState
|
||||
@@ -59,14 +54,12 @@ import org.springframework.webflow.execution.ViewSelection;
|
||||
public class EndState extends State {
|
||||
|
||||
/**
|
||||
* The optional view selector that will select a view to render if this end
|
||||
* state terminates a root flow session.
|
||||
* The optional view selector that will select a view to render if this end state terminates a root flow session.
|
||||
*/
|
||||
private ViewSelector viewSelector = NullViewSelector.INSTANCE;
|
||||
|
||||
/**
|
||||
* Attribute mapper for mapping output attributes exposed by this end state
|
||||
* when it is entered.
|
||||
* Attribute mapper for mapping output attributes exposed by this end state when it is entered.
|
||||
*/
|
||||
private AttributeMapper outputMapper;
|
||||
|
||||
@@ -74,8 +67,7 @@ public class EndState extends State {
|
||||
* Create a new end state with no associated view.
|
||||
* @param flow the owning flow
|
||||
* @param id the state identifier (must be unique to the flow)
|
||||
* @throws IllegalArgumentException when this state cannot be added to given
|
||||
* flow, e.g. because the id is not unique
|
||||
* @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique
|
||||
* @see State#State(Flow, String)
|
||||
* @see #setViewSelector(ViewSelector)
|
||||
* @see #setOutputMapper(AttributeMapper)
|
||||
@@ -85,16 +77,14 @@ public class EndState extends State {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the strategy used to select the view to render in this end state
|
||||
* if it terminates a root flow.
|
||||
* Returns the strategy used to select the view to render in this end state if it terminates a root flow.
|
||||
*/
|
||||
public ViewSelector getViewSelector() {
|
||||
return viewSelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy used to select the view to render when this end state
|
||||
* is entered and terminates a root flow.
|
||||
* Sets the strategy used to select the view to render when this end state is entered and terminates a root flow.
|
||||
*/
|
||||
public void setViewSelector(ViewSelector viewSelector) {
|
||||
Assert.notNull(viewSelector, "The view selector is required");
|
||||
@@ -102,33 +92,29 @@ public class EndState extends State {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured attribute mapper for mapping output attributes
|
||||
* exposed by this end state when it is entered.
|
||||
* Returns the configured attribute mapper for mapping output attributes exposed by this end state when it is
|
||||
* entered.
|
||||
*/
|
||||
public AttributeMapper getOutputMapper() {
|
||||
return outputMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attribute mapper to use for mapping output attributes exposed by
|
||||
* this end state when it is entered.
|
||||
* Sets the attribute mapper to use for mapping output attributes exposed by this end state when it is entered.
|
||||
*/
|
||||
public void setOutputMapper(AttributeMapper outputMapper) {
|
||||
this.outputMapper = outputMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of State's <code>doEnter</code> template method that
|
||||
* executes behaviour specific to this state type in polymorphic fashion.
|
||||
* Specialization of State's <code>doEnter</code> template method that executes behaviour specific to this state
|
||||
* type in polymorphic fashion.
|
||||
* <p>
|
||||
* This implementation pops the top (active) flow session off the execution
|
||||
* stack, ending it, and resumes control in the parent flow (if neccessary).
|
||||
* If the ended session is the root flow, a {@link ViewSelection} is
|
||||
* returned.
|
||||
* @param context the control context for the currently executing flow, used
|
||||
* by this state to manipulate the flow execution
|
||||
* @return a view selection signaling that control should be returned to the
|
||||
* client and a view rendered
|
||||
* This implementation pops the top (active) flow session off the execution stack, ending it, and resumes control in
|
||||
* the parent flow (if neccessary). If the ended session is the root flow, a {@link ViewSelection} is returned.
|
||||
* @param context the control context for the currently executing flow, used by this state to manipulate the flow
|
||||
* execution
|
||||
* @return a view selection signaling that control should be returned to the client and a view rendered
|
||||
* @throws FlowExecutionException if an exception occurs in this state
|
||||
*/
|
||||
protected ViewSelection doEnter(RequestControlContext context) throws FlowExecutionException {
|
||||
@@ -138,8 +124,7 @@ public class EndState extends State {
|
||||
ViewSelection selectedView = viewSelector.makeEntrySelection(context);
|
||||
context.endActiveFlowSession(createSessionOutput(context));
|
||||
return selectedView;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// there is a parent flow that will resume (this flow is a subflow)
|
||||
LocalAttributeMap sessionOutput = createSessionOutput(context);
|
||||
context.endActiveFlowSession(sessionOutput);
|
||||
@@ -148,9 +133,8 @@ public class EndState extends State {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subflow output map. This will invoke the output mapper (if any)
|
||||
* to map data available in the flow execution request context into a newly
|
||||
* created empty map.
|
||||
* Returns the subflow output map. This will invoke the output mapper (if any) to map data available in the flow
|
||||
* execution request context into a newly created empty map.
|
||||
*/
|
||||
protected LocalAttributeMap createSessionOutput(RequestContext context) {
|
||||
LocalAttributeMap outputMap = new LocalAttributeMap();
|
||||
|
||||
@@ -34,70 +34,53 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A single flow definition. A Flow definition is a reusable, self-contained
|
||||
* controller module that provides the blue print for a user dialog or
|
||||
* conversation. Flows typically orchestrate controlled navigations within web
|
||||
* applications to guide users through fulfillment of a business process/goal
|
||||
* that takes place over a series of steps, modeled as states.
|
||||
* A single flow definition. A Flow definition is a reusable, self-contained controller module that provides the blue
|
||||
* print for a user dialog or conversation. Flows typically orchestrate controlled navigations within web applications
|
||||
* to guide users through fulfillment of a business process/goal that takes place over a series of steps, modeled as
|
||||
* states.
|
||||
* <p>
|
||||
* A simple Flow definition could do nothing more than execute an action and
|
||||
* display a view all in one request. A more elaborate Flow definition may be
|
||||
* long-lived and execute across a series of requests, invoking many possible
|
||||
* paths, actions, and subflows.
|
||||
* A simple Flow definition could do nothing more than execute an action and display a view all in one request. A more
|
||||
* elaborate Flow definition may be long-lived and execute across a series of requests, invoking many possible paths,
|
||||
* actions, and subflows.
|
||||
* <p>
|
||||
* Especially in Intranet applications there are often "controlled navigations"
|
||||
* where the user is not free to do what he or she wants but must follow the
|
||||
* guidelines provided by the system to complete a process that is transactional
|
||||
* in nature (the quinessential example would be a 'checkout' flow of a shopping
|
||||
* cart application). This is a typical use case appropriate to model as a flow.
|
||||
* Especially in Intranet applications there are often "controlled navigations" where the user is not free to do what he
|
||||
* or she wants but must follow the guidelines provided by the system to complete a process that is transactional in
|
||||
* nature (the quinessential example would be a 'checkout' flow of a shopping cart application). This is a typical use
|
||||
* case appropriate to model as a flow.
|
||||
* <p>
|
||||
* Structurally a Flow is composed of a set of states. A {@link State} is a
|
||||
* point in a flow where a behavior is executed; for example, showing a view,
|
||||
* executing an action, spawning a subflow, or terminating the flow. Different
|
||||
* Structurally a Flow is composed of a set of states. A {@link State} is a point in a flow where a behavior is
|
||||
* executed; for example, showing a view, executing an action, spawning a subflow, or terminating the flow. Different
|
||||
* types of states execute different behaviors in a polymorphic fashion.
|
||||
* <p>
|
||||
* Each {@link TransitionableState} type has one or more transitions that when
|
||||
* executed move a flow to another state. These transitions define the supported
|
||||
* paths through the flow.
|
||||
* Each {@link TransitionableState} type has one or more transitions that when executed move a flow to another state.
|
||||
* These transitions define the supported paths through the flow.
|
||||
* <p>
|
||||
* A state transition is triggered by the occurence of an event. An event is
|
||||
* something that happens the flow should respond to, for example a user input
|
||||
* event like ("submit") or an action execution result event like ("success").
|
||||
* When an event occurs in a state of a Flow that event drives a state
|
||||
* transition that decides what to do next.
|
||||
* A state transition is triggered by the occurence of an event. An event is something that happens the flow should
|
||||
* respond to, for example a user input event like ("submit") or an action execution result event like ("success"). When
|
||||
* an event occurs in a state of a Flow that event drives a state transition that decides what to do next.
|
||||
* <p>
|
||||
* Each Flow has exactly one start state. A start state is simply a marker
|
||||
* noting the state executions of this Flow definition should start in. The
|
||||
* first state added to the flow will become the start state by default.
|
||||
* Each Flow has exactly one start state. A start state is simply a marker noting the state executions of this Flow
|
||||
* definition should start in. The first state added to the flow will become the start state by default.
|
||||
* <p>
|
||||
* Flow definitions may have one or more flow exception handlers. A
|
||||
* {@link FlowExecutionExceptionHandler} can execute custom behavior in response
|
||||
* to a specific exception (or set of exceptions) that occur in a state of one
|
||||
* of this flow's executions.
|
||||
* Flow definitions may have one or more flow exception handlers. A {@link FlowExecutionExceptionHandler} can execute
|
||||
* custom behavior in response to a specific exception (or set of exceptions) that occur in a state of one of this
|
||||
* flow's executions.
|
||||
* <p>
|
||||
* Instances of this class are typically built by
|
||||
* {@link org.springframework.webflow.engine.builder.FlowBuilder}
|
||||
* Instances of this class are typically built by {@link org.springframework.webflow.engine.builder.FlowBuilder}
|
||||
* implementations but may also be directly instantiated.
|
||||
* <p>
|
||||
* This class and the rest of the Spring Web Flow (SWF) engine have been designed
|
||||
* with minimal dependencies on other libraries. Spring Web Flow is usable in a
|
||||
* standalone fashion (as well as in the context of other frameworks like Spring
|
||||
* MVC, Struts, or JSF, for example). The engine system is fully usable outside an
|
||||
* HTTP servlet environment, for example in portlets, tests, or standalone
|
||||
* applications. One of the major architectural benefits of Spring Web Flow is
|
||||
* the ability to design reusable, high-level controller modules that may be
|
||||
* executed in <i>any</i> environment.
|
||||
* This class and the rest of the Spring Web Flow (SWF) engine have been designed with minimal dependencies on other
|
||||
* libraries. Spring Web Flow is usable in a standalone fashion (as well as in the context of other frameworks like
|
||||
* Spring MVC, Struts, or JSF, for example). The engine system is fully usable outside an HTTP servlet environment, for
|
||||
* example in portlets, tests, or standalone applications. One of the major architectural benefits of Spring Web Flow is
|
||||
* the ability to design reusable, high-level controller modules that may be executed in <i>any</i> environment.
|
||||
* <p>
|
||||
* Note: flows are singleton definition objects so they should be thread-safe.
|
||||
* You can think a flow definition as analagous somewhat to a Java class,
|
||||
* defining all the behavior of an application module. The core behaviors
|
||||
* {@link #start(RequestControlContext, MutableAttributeMap) start},
|
||||
* {@link #onEvent(RequestControlContext) on event}, and
|
||||
* {@link #end(RequestControlContext, MutableAttributeMap) end} each accept a
|
||||
* {@link RequestContext request context} that allows for this flow to access
|
||||
* execution state in a thread safe manner. A flow execution is what models a
|
||||
* running instance of this flow definition, somewhat analgous to a java object
|
||||
* that is an instance of a class.
|
||||
* Note: flows are singleton definition objects so they should be thread-safe. You can think a flow definition as
|
||||
* analagous somewhat to a Java class, defining all the behavior of an application module. The core behaviors
|
||||
* {@link #start(RequestControlContext, MutableAttributeMap) start}, {@link #onEvent(RequestControlContext) on event},
|
||||
* and {@link #end(RequestControlContext, MutableAttributeMap) end} each accept a {@link RequestContext request context}
|
||||
* that allows for this flow to access execution state in a thread safe manner. A flow execution is what models a
|
||||
* running instance of this flow definition, somewhat analgous to a java object that is an instance of a class.
|
||||
*
|
||||
* @see org.springframework.webflow.engine.State
|
||||
* @see org.springframework.webflow.engine.TransitionableState
|
||||
@@ -121,8 +104,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* An assigned flow identifier uniquely identifying this flow among all
|
||||
* other flows.
|
||||
* An assigned flow identifier uniquely identifying this flow among all other flows.
|
||||
*/
|
||||
private String id;
|
||||
|
||||
@@ -149,9 +131,8 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
/**
|
||||
* The list of actions to execute when this flow starts.
|
||||
* <p>
|
||||
* Start actions should execute with care as during startup a flow session
|
||||
* has not yet fully initialized and some properties like its "currentState"
|
||||
* have not yet been set.
|
||||
* Start actions should execute with care as during startup a flow session has not yet fully initialized and some
|
||||
* properties like its "currentState" have not yet been set.
|
||||
*/
|
||||
private ActionList startActionList = new ActionList();
|
||||
|
||||
@@ -181,8 +162,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
private Set inlineFlows = CollectionFactory.createLinkedSetIfPossible(3);
|
||||
|
||||
/**
|
||||
* Construct a new flow definition with the given id. The id should be
|
||||
* unique among all flows.
|
||||
* Construct a new flow definition with the given id. The id should be unique among all flows.
|
||||
* @param id the flow identifier
|
||||
*/
|
||||
public Flow(String id) {
|
||||
@@ -216,13 +196,11 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given state definition to this flow definition. Marked protected, as
|
||||
* this method is to be called by the (privileged) state definition classes
|
||||
* themselves during state construction as part of a FlowBuilder invocation.
|
||||
* Add given state definition to this flow definition. Marked protected, as this method is to be called by the
|
||||
* (privileged) state definition classes themselves during state construction as part of a FlowBuilder invocation.
|
||||
* @param state the state to add
|
||||
* @throws IllegalArgumentException when the state cannot be added to the
|
||||
* flow; for instance if another state shares the same id as the one
|
||||
* provided or if given state already belongs to another flow
|
||||
* @throws IllegalArgumentException when the state cannot be added to the flow; for instance if another state shares
|
||||
* the same id as the one provided or if given state already belongs to another flow
|
||||
*/
|
||||
protected void add(State state) throws IllegalArgumentException {
|
||||
if (this != state.getFlow() && state.getFlow() != null) {
|
||||
@@ -257,32 +235,28 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
public boolean containsState(String stateId) {
|
||||
Iterator it = states.iterator();
|
||||
while (it.hasNext()) {
|
||||
State state = (State)it.next();
|
||||
State state = (State) it.next();
|
||||
if (state.getId().equals(stateId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the start state for this flow to the state with the provided
|
||||
* <code>stateId</code>; a state must exist by the provided
|
||||
* <code>stateId</code>.
|
||||
* Set the start state for this flow to the state with the provided <code>stateId</code>; a state must exist by
|
||||
* the provided <code>stateId</code>.
|
||||
* @param stateId the id of the new start state
|
||||
* @throws IllegalArgumentException when no state exists with the id you
|
||||
* provided
|
||||
* @throws IllegalArgumentException when no state exists with the id you provided
|
||||
*/
|
||||
public void setStartState(String stateId) throws IllegalArgumentException {
|
||||
setStartState(getStateInstance(stateId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start state for this flow to the state provided; any state may be
|
||||
* the start state.
|
||||
* Set the start state for this flow to the state provided; any state may be the start state.
|
||||
* @param state the new start state
|
||||
* @throws IllegalArgumentException given state has not been added to this
|
||||
* flow
|
||||
* @throws IllegalArgumentException given state has not been added to this flow
|
||||
*/
|
||||
public void setStartState(State state) throws IllegalArgumentException {
|
||||
if (!states.contains(state)) {
|
||||
@@ -296,16 +270,15 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
* @param stateId id of the state to look up
|
||||
* @return the transitionable state
|
||||
* @throws IllegalArgumentException if the identified state cannot be found
|
||||
* @throws ClassCastException when the identified state is not
|
||||
* transitionable
|
||||
* @throws ClassCastException when the identified state is not transitionable
|
||||
*/
|
||||
public TransitionableState getTransitionableState(String stateId)
|
||||
throws IllegalArgumentException, ClassCastException {
|
||||
public TransitionableState getTransitionableState(String stateId) throws IllegalArgumentException,
|
||||
ClassCastException {
|
||||
State state = getStateInstance(stateId);
|
||||
if (state != null && !(state instanceof TransitionableState)) {
|
||||
throw new ClassCastException("The state '" + stateId + "' of flow '" + getId() + "' must be transitionable");
|
||||
}
|
||||
return (TransitionableState)state;
|
||||
return (TransitionableState) state;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,7 +293,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
Iterator it = states.iterator();
|
||||
while (it.hasNext()) {
|
||||
State state = (State)it.next();
|
||||
State state = (State) it.next();
|
||||
if (state.getId().equals(stateId)) {
|
||||
return state;
|
||||
}
|
||||
@@ -330,9 +303,8 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience accessor that returns an ordered array of the String
|
||||
* <code>ids</code> for the state definitions associated with this flow
|
||||
* definition.
|
||||
* Convenience accessor that returns an ordered array of the String <code>ids</code> for the state definitions
|
||||
* associated with this flow definition.
|
||||
* @return the state ids
|
||||
*/
|
||||
public String[] getStateIds() {
|
||||
@@ -340,7 +312,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
int i = 0;
|
||||
Iterator it = states.iterator();
|
||||
while (it.hasNext()) {
|
||||
stateIds[i++] = ((State)it.next()).getId();
|
||||
stateIds[i++] = ((State) it.next()).getId();
|
||||
}
|
||||
return stateIds;
|
||||
}
|
||||
@@ -365,12 +337,12 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
addVariable(variables[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the flow variables.
|
||||
*/
|
||||
public FlowVariable[] getVariables() {
|
||||
return (FlowVariable[])variables.toArray(new FlowVariable[variables.size()]);
|
||||
return (FlowVariable[]) variables.toArray(new FlowVariable[variables.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,8 +362,8 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of actions executed by this flow when an execution of
|
||||
* the flow <i>starts</i>. The returned list is mutable.
|
||||
* Returns the list of actions executed by this flow when an execution of the flow <i>starts</i>. The returned list
|
||||
* is mutable.
|
||||
* @return the start action list
|
||||
*/
|
||||
public ActionList getStartActionList() {
|
||||
@@ -399,8 +371,8 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of actions executed by this flow when an execution of
|
||||
* the flow <i>ends</i>. The returned list is mutable.
|
||||
* Returns the list of actions executed by this flow when an execution of the flow <i>ends</i>. The returned list
|
||||
* is mutable.
|
||||
* @return the end action list
|
||||
*/
|
||||
public ActionList getEndActionList() {
|
||||
@@ -424,13 +396,10 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of exception handlers, allowing manipulation of how
|
||||
* exceptions are handled when thrown during flow execution. Exception
|
||||
* handlers are invoked when an exception occurs at execution time
|
||||
* and can execute custom exception handling logic as well as select an
|
||||
* error view to display. Exception handlers attached at the flow
|
||||
* level have an opportunity to handle exceptions that aren't handled at the
|
||||
* state level.
|
||||
* Returns the set of exception handlers, allowing manipulation of how exceptions are handled when thrown during
|
||||
* flow execution. Exception handlers are invoked when an exception occurs at execution time and can execute custom
|
||||
* exception handling logic as well as select an error view to display. Exception handlers attached at the flow
|
||||
* level have an opportunity to handle exceptions that aren't handled at the state level.
|
||||
* @return the exception handler set
|
||||
*/
|
||||
public FlowExecutionExceptionHandlerSet getExceptionHandlerSet() {
|
||||
@@ -454,7 +423,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
int i = 0;
|
||||
Iterator it = inlineFlows.iterator();
|
||||
while (it.hasNext()) {
|
||||
flowIds[i++] = ((Flow)it.next()).getId();
|
||||
flowIds[i++] = ((Flow) it.next()).getId();
|
||||
}
|
||||
return flowIds;
|
||||
}
|
||||
@@ -464,7 +433,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
* @return the list of inline flows
|
||||
*/
|
||||
public Flow[] getInlineFlows() {
|
||||
return (Flow[])inlineFlows.toArray(new Flow[inlineFlows.size()]);
|
||||
return (Flow[]) inlineFlows.toArray(new Flow[inlineFlows.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -478,16 +447,14 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
/**
|
||||
* Tests if this flow contains an in-line flow with the specified id.
|
||||
* @param id the inline flow id
|
||||
* @return true if this flow contains a inline flow with that id, false
|
||||
* otherwise
|
||||
* @return true if this flow contains a inline flow with that id, false otherwise
|
||||
*/
|
||||
public boolean containsInlineFlow(String id) {
|
||||
return getInlineFlow(id) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inline flow with the provided id, or <code>null</code> if
|
||||
* no such inline flow exists.
|
||||
* Returns the inline flow with the provided id, or <code>null</code> if no such inline flow exists.
|
||||
* @param id the inline flow id
|
||||
* @return the inline flow
|
||||
* @throws IllegalArgumentException when an invalid flow id is provided
|
||||
@@ -499,7 +466,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
Iterator it = inlineFlows.iterator();
|
||||
while (it.hasNext()) {
|
||||
Flow flow = (Flow)it.next();
|
||||
Flow flow = (Flow) it.next();
|
||||
if (flow.getId().equals(id)) {
|
||||
return flow;
|
||||
}
|
||||
@@ -508,21 +475,21 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of transitions eligible for execution by this flow if no
|
||||
* state-level transition is matched. The returned set is mutable.
|
||||
* Returns the set of transitions eligible for execution by this flow if no state-level transition is matched. The
|
||||
* returned set is mutable.
|
||||
* @return the global transition set
|
||||
*/
|
||||
public TransitionSet getGlobalTransitionSet() {
|
||||
return globalTransitionSet;
|
||||
}
|
||||
|
||||
|
||||
// id based equality
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Flow)) {
|
||||
return false;
|
||||
}
|
||||
Flow other = (Flow)o;
|
||||
Flow other = (Flow) o;
|
||||
return id.equals(other.id);
|
||||
}
|
||||
|
||||
@@ -533,14 +500,11 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
// behavioral code, could be overridden in subclasses
|
||||
|
||||
/**
|
||||
* Start a new session for this flow in its start state. This boils down to
|
||||
* the following:
|
||||
* Start a new session for this flow in its start state. This boils down to the following:
|
||||
* <ol>
|
||||
* <li>Create (setup) all registered flow variables ({@link #addVariable(FlowVariable)})
|
||||
* in flow scope.</li>
|
||||
* <li>Map provided input data into the flow execution control context.
|
||||
* Typically data will be mapped into flow scope using the registered input
|
||||
* mapper ({@link #setInputMapper(AttributeMapper)}).</li>
|
||||
* <li>Create (setup) all registered flow variables ({@link #addVariable(FlowVariable)}) in flow scope.</li>
|
||||
* <li>Map provided input data into the flow execution control context. Typically data will be mapped into flow
|
||||
* scope using the registered input mapper ({@link #setInputMapper(AttributeMapper)}).</li>
|
||||
* <li>Execute all registered start actions ({@link #getStartActionList()}).</li>
|
||||
* <li>Enter the configured start state ({@link #setStartState(State)})</li>
|
||||
* </ol>
|
||||
@@ -558,26 +522,22 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform this flow definition that an event was signaled in the current
|
||||
* state of an active flow execution. The signaled event is the last event
|
||||
* available in given request context ({@link RequestContext#getLastEvent()}).
|
||||
* Inform this flow definition that an event was signaled in the current state of an active flow execution. The
|
||||
* signaled event is the last event available in given request context ({@link RequestContext#getLastEvent()}).
|
||||
* @param context the flow execution control context
|
||||
* @return the selected view
|
||||
* @throws FlowExecutionException when an exception occurs processing the
|
||||
* event
|
||||
* @throws FlowExecutionException when an exception occurs processing the event
|
||||
*/
|
||||
public ViewSelection onEvent(RequestControlContext context) throws FlowExecutionException {
|
||||
TransitionableState currentState = getCurrentTransitionableState(context);
|
||||
try {
|
||||
return currentState.onEvent(context);
|
||||
}
|
||||
catch (NoMatchingTransitionException e) {
|
||||
} catch (NoMatchingTransitionException e) {
|
||||
// try the flow level transition set for a match
|
||||
Transition transition = globalTransitionSet.getTransition(context);
|
||||
if (transition != null) {
|
||||
return transition.execute(currentState, context);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// no matching global transition => let the original exception
|
||||
// propagate
|
||||
throw e;
|
||||
@@ -586,17 +546,15 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform this flow definition that an execution session of itself has
|
||||
* ended. As a result, the flow will do the following:
|
||||
* Inform this flow definition that an execution session of itself has ended. As a result, the flow will do the
|
||||
* following:
|
||||
* <ol>
|
||||
* <li>Execute all registered end actions ({@link #getEndActionList()}).</li>
|
||||
* <li>Map data available in the flow execution control context into
|
||||
* provided output map using a registered output mapper
|
||||
* ({@link #setOutputMapper(AttributeMapper)}).</li>
|
||||
* <li>Map data available in the flow execution control context into provided output map using a registered output
|
||||
* mapper ({@link #setOutputMapper(AttributeMapper)}).</li>
|
||||
* </ol>
|
||||
* @param context the flow execution control context
|
||||
* @param output initial output produced by the session that is eligible for
|
||||
* modification by this method
|
||||
* @param output initial output produced by the session that is eligible for modification by this method
|
||||
* @throws FlowExecutionException when an exception occurs ending this flow
|
||||
*/
|
||||
public void end(RequestControlContext context, MutableAttributeMap output) throws FlowExecutionException {
|
||||
@@ -610,8 +568,8 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
* Handle an exception that occured during an execution of this flow.
|
||||
* @param exception the exception that occured
|
||||
* @param context the flow execution control context
|
||||
* @return the selected error view, or <code>null</code> if no handler
|
||||
* matched or returned a non-null view selection
|
||||
* @return the selected error view, or <code>null</code> if no handler matched or returned a non-null view
|
||||
* selection
|
||||
*/
|
||||
public ViewSelection handleException(FlowExecutionException exception, RequestControlContext context)
|
||||
throws FlowExecutionException {
|
||||
@@ -626,7 +584,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
private void createVariables(RequestContext context) {
|
||||
Iterator it = variables.iterator();
|
||||
while (it.hasNext()) {
|
||||
FlowVariable variable = (FlowVariable)it.next();
|
||||
FlowVariable variable = (FlowVariable) it.next();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Creating " + variable);
|
||||
}
|
||||
@@ -638,12 +596,12 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
* Returns the current state and makes sure it is transitionable.
|
||||
*/
|
||||
private TransitionableState getCurrentTransitionableState(RequestControlContext context) {
|
||||
State currentState = (State)context.getCurrentState();
|
||||
State currentState = (State) context.getCurrentState();
|
||||
if (!(currentState instanceof TransitionableState)) {
|
||||
throw new IllegalStateException("You can only signal events in transitionable states, and state "
|
||||
+ context.getCurrentState() + " is not transitionable - programmer error");
|
||||
}
|
||||
return (TransitionableState)currentState;
|
||||
return (TransitionableState) currentState;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
@@ -20,14 +20,12 @@ import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* A service interface that maps attributes between two flows. Used by the
|
||||
* subflow state to map attributes between a parent flow and its sub flow.
|
||||
* A service interface that maps attributes between two flows. Used by the subflow state to map attributes between a
|
||||
* parent flow and its sub flow.
|
||||
* <p>
|
||||
* An attribute mapper may map attributes of a parent flow down to a child flow
|
||||
* as <i>input</i> when the child is spawned as a subflow. In addition, a
|
||||
* mapper may map output attributes of a subflow into a resuming parent flow as
|
||||
* <i>output</i> when the child session ends and control is returned to the
|
||||
* parent flow.
|
||||
* An attribute mapper may map attributes of a parent flow down to a child flow as <i>input</i> when the child is
|
||||
* spawned as a subflow. In addition, a mapper may map output attributes of a subflow into a resuming parent flow as
|
||||
* <i>output</i> when the child session ends and control is returned to the parent flow.
|
||||
* <p>
|
||||
* For example, say you have the following parent flow session:
|
||||
* <p>
|
||||
@@ -40,13 +38,11 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* For the "Parent Flow Session" above, there are 3 attributes in flow scope
|
||||
* ("attribute1", "attribute2" and "attribute3", respectively). Any of these
|
||||
* three attributes may be mapped as input down to child subflows when those
|
||||
* subflows are spawned. An implementation of this interface performs the actual
|
||||
* mapping, encapsulating knowledge of <i>which</i> attributes should be
|
||||
* mapped, and <i>how</i> they will be mapped (for example, will the same
|
||||
* attribute names be used between flows or not?).
|
||||
* For the "Parent Flow Session" above, there are 3 attributes in flow scope ("attribute1", "attribute2" and
|
||||
* "attribute3", respectively). Any of these three attributes may be mapped as input down to child subflows when those
|
||||
* subflows are spawned. An implementation of this interface performs the actual mapping, encapsulating knowledge of
|
||||
* <i>which</i> attributes should be mapped, and <i>how</i> they will be mapped (for example, will the same attribute
|
||||
* names be used between flows or not?).
|
||||
* <p>
|
||||
* For example:
|
||||
* <p>
|
||||
@@ -59,30 +55,23 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The above example "Flow Attribute Mapper" specifies
|
||||
* <code>inputMappings</code> that define which parent attributes to map as
|
||||
* input to the child. In this case, two attributes in flow scope of the parent
|
||||
* are mapped, "attribute1" and "attribute3". "attribute1" is mapped with the
|
||||
* name "attribute1" (given the same name in both flows), while "attribute3" is
|
||||
* mapped to "attribute4", given a different name that is local to the child
|
||||
* flow.
|
||||
* The above example "Flow Attribute Mapper" specifies <code>inputMappings</code> that define which parent attributes
|
||||
* to map as input to the child. In this case, two attributes in flow scope of the parent are mapped, "attribute1" and
|
||||
* "attribute3". "attribute1" is mapped with the name "attribute1" (given the same name in both flows), while
|
||||
* "attribute3" is mapped to "attribute4", given a different name that is local to the child flow.
|
||||
* <p>
|
||||
* Likewise, when a child flow ends the <code>outputMappings</code> define
|
||||
* which output attributes to map into the parent. In this case the subflow
|
||||
* output attribute "attribute4" will be mapped up to the parent as "attribute3",
|
||||
* updating the value of "attribute3" in the parent's flow scope. Note: only
|
||||
* output attributes exposed by the end state of the ending subflow are eligible
|
||||
* for mapping.
|
||||
* Likewise, when a child flow ends the <code>outputMappings</code> define which output attributes to map into the
|
||||
* parent. In this case the subflow output attribute "attribute4" will be mapped up to the parent as "attribute3",
|
||||
* updating the value of "attribute3" in the parent's flow scope. Note: only output attributes exposed by the end state
|
||||
* of the ending subflow are eligible for mapping.
|
||||
* <p>
|
||||
* A FlowAttributeMapper is typically implemented using 2 distinct
|
||||
* {@link org.springframework.binding.mapping.AttributeMapper} implementations:
|
||||
* one responsible for input mapping and one taking care of output mapping.
|
||||
* {@link org.springframework.binding.mapping.AttributeMapper} implementations: one responsible for input mapping and
|
||||
* one taking care of output mapping.
|
||||
* <p>
|
||||
* Note: because FlowAttributeMappers are singletons, take care not to store
|
||||
* and/or modify caller-specific state in a unsafe manner. The
|
||||
* FlowAttributeMapper methods run in an independently executing thread on each
|
||||
* invocation so make sure you deal only with local data or internal,
|
||||
* thread-safe services.
|
||||
* Note: because FlowAttributeMappers are singletons, take care not to store and/or modify caller-specific state in a
|
||||
* unsafe manner. The FlowAttributeMapper methods run in an independently executing thread on each invocation so make
|
||||
* sure you deal only with local data or internal, thread-safe services.
|
||||
*
|
||||
* @see org.springframework.webflow.engine.SubflowState
|
||||
* @see org.springframework.binding.mapping.AttributeMapper
|
||||
@@ -93,25 +82,21 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
public interface FlowAttributeMapper {
|
||||
|
||||
/**
|
||||
* Create a map of attributes that should be passed as <i>input</i> to a
|
||||
* spawning flow.
|
||||
* Create a map of attributes that should be passed as <i>input</i> to a spawning flow.
|
||||
* <p>
|
||||
* Attributes set in the map returned by this method are availale
|
||||
* as input to the subflow when its session is spawned.
|
||||
* @param context the current request execution context, which gives access
|
||||
* to the parent flow scope, the request scope, any event parameters, etcetera
|
||||
* @return a map of attributes (name=value pairs) to pass as input to the
|
||||
* spawning subflow
|
||||
* Attributes set in the map returned by this method are availale as input to the subflow when its session is
|
||||
* spawned.
|
||||
* @param context the current request execution context, which gives access to the parent flow scope, the request
|
||||
* scope, any event parameters, etcetera
|
||||
* @return a map of attributes (name=value pairs) to pass as input to the spawning subflow
|
||||
*/
|
||||
public MutableAttributeMap createFlowInput(RequestContext context);
|
||||
|
||||
/**
|
||||
* Map output attributes of an ended flow to a resuming parent flow session.
|
||||
* This maps the <i>output</i> of the child as new input to the resuming
|
||||
* parent, typically adding data to flow scope.
|
||||
* Map output attributes of an ended flow to a resuming parent flow session. This maps the <i>output</i> of the
|
||||
* child as new input to the resuming parent, typically adding data to flow scope.
|
||||
* @param flowOutput the output attributes exposed by the ended subflow
|
||||
* @param context the current request execution context, which gives access
|
||||
* to the parent flow scope
|
||||
* @param context the current request execution context, which gives access to the parent flow scope
|
||||
*/
|
||||
public void mapFlowOutput(AttributeMap flowOutput, RequestContext context);
|
||||
}
|
||||
@@ -19,8 +19,7 @@ import org.springframework.webflow.execution.FlowExecutionException;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A strategy for handling an exception that occurs at runtime during the
|
||||
* execution of a flow definition.
|
||||
* A strategy for handling an exception that occurs at runtime during the execution of a flow definition.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -34,13 +33,12 @@ public interface FlowExecutionExceptionHandler {
|
||||
public boolean handles(FlowExecutionException exception);
|
||||
|
||||
/**
|
||||
* Handle the exception in the context of the current request, optionally
|
||||
* making an error view selection that should be rendered.
|
||||
* Handle the exception in the context of the current request, optionally making an error view selection that should
|
||||
* be rendered.
|
||||
* @param exception the exception that occured
|
||||
* @param context the execution control context for this request
|
||||
* @return the selected error view that should be displayed (may be null if
|
||||
* the handler chooses not to select a view, in which case other exception
|
||||
* handlers may be given a chance to handle the exception)
|
||||
* @return the selected error view that should be displayed (may be null if the handler chooses not to select a
|
||||
* view, in which case other exception handlers may be given a chance to handle the exception)
|
||||
*/
|
||||
public ViewSelection handle(FlowExecutionException exception, RequestControlContext context);
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ import org.springframework.webflow.execution.FlowExecutionException;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A typed set of state exception handlers, mainly for use internally by
|
||||
* artifacts that can apply state exception handling logic.
|
||||
* A typed set of state exception handlers, mainly for use internally by artifacts that can apply state exception
|
||||
* handling logic.
|
||||
*
|
||||
* @see FlowExecutionExceptionHandler
|
||||
* @see Flow#getExceptionHandlerSet()
|
||||
@@ -44,8 +44,7 @@ public class FlowExecutionExceptionHandlerSet {
|
||||
/**
|
||||
* Add a state exception handler to this set.
|
||||
* @param exceptionHandler the exception handler to add
|
||||
* @return true if this set's contents changed as a result of the add
|
||||
* operation
|
||||
* @return true if this set's contents changed as a result of the add operation
|
||||
*/
|
||||
public boolean add(FlowExecutionExceptionHandler exceptionHandler) {
|
||||
if (contains(exceptionHandler)) {
|
||||
@@ -57,8 +56,7 @@ public class FlowExecutionExceptionHandlerSet {
|
||||
/**
|
||||
* Add a collection of state exception handler instances to this set.
|
||||
* @param exceptionHandlers the exception handlers to add
|
||||
* @return true if this set's contents changed as a result of the add
|
||||
* operation
|
||||
* @return true if this set's contents changed as a result of the add operation
|
||||
*/
|
||||
public boolean addAll(FlowExecutionExceptionHandler[] exceptionHandlers) {
|
||||
return CollectionUtils.addAllNoDuplicates(this.exceptionHandlers, exceptionHandlers);
|
||||
@@ -67,8 +65,7 @@ public class FlowExecutionExceptionHandlerSet {
|
||||
/**
|
||||
* Tests if this state exception handler is in this set.
|
||||
* @param exceptionHandler the exception handler
|
||||
* @return true if the state exception handler is contained in this set,
|
||||
* false otherwise
|
||||
* @return true if the state exception handler is contained in this set, false otherwise
|
||||
*/
|
||||
public boolean contains(FlowExecutionExceptionHandler exceptionHandler) {
|
||||
return exceptionHandlers.contains(exceptionHandler);
|
||||
@@ -77,8 +74,7 @@ public class FlowExecutionExceptionHandlerSet {
|
||||
/**
|
||||
* Remove the exception handler instance from this set.
|
||||
* @param exceptionHandler the exception handler to add
|
||||
* @return true if this set's contents changed as a result of the remove
|
||||
* operation
|
||||
* @return true if this set's contents changed as a result of the remove operation
|
||||
*/
|
||||
public boolean remove(FlowExecutionExceptionHandler exceptionHandler) {
|
||||
return exceptionHandlers.remove(exceptionHandler);
|
||||
@@ -97,25 +93,24 @@ public class FlowExecutionExceptionHandlerSet {
|
||||
* @return the exception handler list, as a typed array
|
||||
*/
|
||||
public FlowExecutionExceptionHandler[] toArray() {
|
||||
return (FlowExecutionExceptionHandler[])exceptionHandlers.toArray(new FlowExecutionExceptionHandler[exceptionHandlers.size()]);
|
||||
return (FlowExecutionExceptionHandler[]) exceptionHandlers
|
||||
.toArray(new FlowExecutionExceptionHandler[exceptionHandlers.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an exception that occured during the context of the current flow
|
||||
* execution request.
|
||||
* Handle an exception that occured during the context of the current flow execution request.
|
||||
* <p>
|
||||
* This implementation iterates over the ordered set of exception handler
|
||||
* objects, delegating to each handler in the set until one handles the
|
||||
* exception that occured and selects a non-null error view.
|
||||
* This implementation iterates over the ordered set of exception handler objects, delegating to each handler in the
|
||||
* set until one handles the exception that occured and selects a non-null error view.
|
||||
* @param exception the exception that occured
|
||||
* @param context the flow execution control context
|
||||
* @return the selected error view, or <code>null</code> if no handler
|
||||
* matched or returned a non-null view selection
|
||||
* @return the selected error view, or <code>null</code> if no handler matched or returned a non-null view
|
||||
* selection
|
||||
*/
|
||||
public ViewSelection handleException(FlowExecutionException exception, RequestControlContext context) {
|
||||
Iterator it = exceptionHandlers.iterator();
|
||||
while (it.hasNext()) {
|
||||
FlowExecutionExceptionHandler handler = (FlowExecutionExceptionHandler)it.next();
|
||||
FlowExecutionExceptionHandler handler = (FlowExecutionExceptionHandler) it.next();
|
||||
if (handler.handles(exception)) {
|
||||
ViewSelection result = handler.handle(exception, context);
|
||||
if (result != null) {
|
||||
|
||||
@@ -23,9 +23,8 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ScopeType;
|
||||
|
||||
/**
|
||||
* A value object that defines a specification for a flow variable. Encapsulates
|
||||
* information about the variable and the behavior necessary to create a new
|
||||
* variable instance in a flow execution scope.
|
||||
* A value object that defines a specification for a flow variable. Encapsulates information about the variable and the
|
||||
* behavior necessary to create a new variable instance in a flow execution scope.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
@@ -66,14 +65,14 @@ public abstract class FlowVariable extends AnnotatedObject implements Serializab
|
||||
public ScopeType getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
|
||||
// name and scope based equality
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof FlowVariable)) {
|
||||
return false;
|
||||
}
|
||||
FlowVariable other = (FlowVariable)o;
|
||||
FlowVariable other = (FlowVariable) o;
|
||||
return name.equals(other.name) && scope.equals(other.scope);
|
||||
}
|
||||
|
||||
@@ -90,9 +89,8 @@ public abstract class FlowVariable extends AnnotatedObject implements Serializab
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook method that needs to be implemented by subclasses to calculate the
|
||||
* value of this flow variable based on the information available in the
|
||||
* request context.
|
||||
* Hook method that needs to be implemented by subclasses to calculate the value of this flow variable based on the
|
||||
* information available in the request context.
|
||||
* @param context the flow execution request context
|
||||
* @return the flow variable value
|
||||
*/
|
||||
|
||||
@@ -19,11 +19,9 @@ import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.FlowExecutionException;
|
||||
|
||||
/**
|
||||
* Thrown when no transition can be matched given the occurence of an event in
|
||||
* the context of a flow execution request.
|
||||
* Thrown when no transition can be matched given the occurence of an event in the context of a flow execution request.
|
||||
* <p>
|
||||
* Typically this happens because there is no "handler" transition for the last
|
||||
* event that occured.
|
||||
* Typically this happens because there is no "handler" transition for the last event that occured.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
@@ -39,8 +37,7 @@ public class NoMatchingTransitionException extends FlowExecutionException {
|
||||
* Create a new no matching transition exception.
|
||||
* @param flowId the current flow
|
||||
* @param stateId the state that could not be transitioned out of
|
||||
* @param event the event that occured that could not be matched to a
|
||||
* transition
|
||||
* @param event the event that occured that could not be matched to a transition
|
||||
* @param message the message
|
||||
*/
|
||||
public NoMatchingTransitionException(String flowId, String stateId, Event event, String message) {
|
||||
@@ -52,8 +49,7 @@ public class NoMatchingTransitionException extends FlowExecutionException {
|
||||
* Create a new no matching transition exception.
|
||||
* @param flowId the current flow
|
||||
* @param stateId the state that could not be transitioned out of
|
||||
* @param event the event that occured that could not be matched to a
|
||||
* transition
|
||||
* @param event the event that occured that could not be matched to a transition
|
||||
* @param message the message
|
||||
* @param cause the underlying cause
|
||||
*/
|
||||
@@ -63,8 +59,7 @@ public class NoMatchingTransitionException extends FlowExecutionException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event for the current request that did not trigger any
|
||||
* supported transition.
|
||||
* Returns the event for the current request that did not trigger any supported transition.
|
||||
*/
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
|
||||
@@ -31,12 +31,12 @@ import org.springframework.webflow.execution.ViewSelection;
|
||||
public final class NullViewSelector implements ViewSelector, Serializable {
|
||||
|
||||
/*
|
||||
* Implementation note: not located in webflow.execution.support package to
|
||||
* avoid a cyclic dependency between webflow.execution and webflow.execution.support.
|
||||
* Implementation note: not located in webflow.execution.support package to avoid a cyclic dependency between
|
||||
* webflow.execution and webflow.execution.support.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The shared singleton {@link NullViewSelector} instance.
|
||||
* The shared singleton {@link NullViewSelector} instance.
|
||||
*/
|
||||
public static final ViewSelector INSTANCE = new NullViewSelector();
|
||||
|
||||
@@ -62,5 +62,5 @@ public final class NullViewSelector implements ViewSelector, Serializable {
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -24,22 +24,17 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* Mutable control interface used to manipulate an ongoing flow execution in the
|
||||
* context of one client request. Primarily used internally by the various flow
|
||||
* artifacts when they are invoked.
|
||||
* Mutable control interface used to manipulate an ongoing flow execution in the context of one client request.
|
||||
* Primarily used internally by the various flow artifacts when they are invoked.
|
||||
* <p>
|
||||
* This interface acts as a facade for core definition constructs such as the
|
||||
* central <code>Flow</code> and <code>State</code> classes, abstracting
|
||||
* away details about the runtime execution machine defined in the
|
||||
* {@link org.springframework.webflow.engine.impl execution engine implementation}
|
||||
* package.
|
||||
* This interface acts as a facade for core definition constructs such as the central <code>Flow</code> and
|
||||
* <code>State</code> classes, abstracting away details about the runtime execution machine defined in the
|
||||
* {@link org.springframework.webflow.engine.impl execution engine implementation} package.
|
||||
* <p>
|
||||
* Note this type is not the same as the {@link FlowExecutionContext}. Objects
|
||||
* of this type are <i>request specific</i>: they provide a control interface
|
||||
* for manipulating exactly one flow execution locally from exactly one request.
|
||||
* A <code>FlowExecutionContext</code> provides information about a single
|
||||
* flow execution (conversation), and it's scope is not local to a specific
|
||||
* request (or thread).
|
||||
* Note this type is not the same as the {@link FlowExecutionContext}. Objects of this type are <i>request specific</i>:
|
||||
* they provide a control interface for manipulating exactly one flow execution locally from exactly one request. A
|
||||
* <code>FlowExecutionContext</code> provides information about a single flow execution (conversation), and it's scope
|
||||
* is not local to a specific request (or thread).
|
||||
*
|
||||
* @see org.springframework.webflow.engine.Flow
|
||||
* @see org.springframework.webflow.engine.State
|
||||
@@ -52,74 +47,62 @@ import org.springframework.webflow.execution.ViewSelection;
|
||||
public interface RequestControlContext extends RequestContext {
|
||||
|
||||
/**
|
||||
* Record the last event signaled in the executing flow. This method will be
|
||||
* called as part of signaling an event in a flow to indicate the
|
||||
* 'lastEvent' that was signaled.
|
||||
* Record the last event signaled in the executing flow. This method will be called as part of signaling an event in
|
||||
* a flow to indicate the 'lastEvent' that was signaled.
|
||||
* @param lastEvent the last event signaled
|
||||
* @see Flow#onEvent(RequestControlContext)
|
||||
*/
|
||||
public void setLastEvent(Event lastEvent);
|
||||
|
||||
/**
|
||||
* Record the last transition that executed in the executing flow. This
|
||||
* method will be called as part of executing a transition from one state to
|
||||
* another.
|
||||
* Record the last transition that executed in the executing flow. This method will be called as part of executing a
|
||||
* transition from one state to another.
|
||||
* @param lastTransition the last transition that executed
|
||||
* @see Transition#execute(State, RequestControlContext)
|
||||
*/
|
||||
public void setLastTransition(Transition lastTransition);
|
||||
|
||||
/**
|
||||
* Record the current state that has entered in the executing flow. This
|
||||
* method will be called as part of entering a new state by the State type
|
||||
* itself.
|
||||
* Record the current state that has entered in the executing flow. This method will be called as part of entering a
|
||||
* new state by the State type itself.
|
||||
* @param state the current state
|
||||
* @see State#enter(RequestControlContext)
|
||||
*/
|
||||
public void setCurrentState(State state);
|
||||
|
||||
/**
|
||||
* Spawn a new flow session and activate it in the currently executing flow.
|
||||
* Also transitions the spawned flow to its start state. This method should
|
||||
* be called by clients that wish to spawn new flows, such as subflow
|
||||
* states.
|
||||
* Spawn a new flow session and activate it in the currently executing flow. Also transitions the spawned flow to
|
||||
* its start state. This method should be called by clients that wish to spawn new flows, such as subflow states.
|
||||
* <p>
|
||||
* This will start a new flow session in the current flow execution, which
|
||||
* is already active.
|
||||
* @param flow the flow to start, its <code>start()</code> method will be
|
||||
* called
|
||||
* @param input initial contents of the newly created flow session (may be
|
||||
* <code>null</code>, e.g. empty)
|
||||
* @return the selected starting view, which returns control to the client
|
||||
* and requests that a view be rendered with model data
|
||||
* @throws FlowExecutionException if an exception was thrown within a state
|
||||
* of the flow during execution of this start operation
|
||||
* This will start a new flow session in the current flow execution, which is already active.
|
||||
* @param flow the flow to start, its <code>start()</code> method will be called
|
||||
* @param input initial contents of the newly created flow session (may be <code>null</code>, e.g. empty)
|
||||
* @return the selected starting view, which returns control to the client and requests that a view be rendered with
|
||||
* model data
|
||||
* @throws FlowExecutionException if an exception was thrown within a state of the flow during execution of this
|
||||
* start operation
|
||||
* @see Flow#start(RequestControlContext, MutableAttributeMap)
|
||||
*/
|
||||
public ViewSelection start(Flow flow, MutableAttributeMap input) throws FlowExecutionException;
|
||||
|
||||
/**
|
||||
* Signals the occurence of an event in the current state of this flow
|
||||
* execution request context. This method should be called by clients that
|
||||
* report internal event occurences, such as action states. The
|
||||
* <code>onEvent()</code> method of the flow involved in the flow
|
||||
* execution will be called.
|
||||
* Signals the occurence of an event in the current state of this flow execution request context. This method should
|
||||
* be called by clients that report internal event occurences, such as action states. The <code>onEvent()</code>
|
||||
* method of the flow involved in the flow execution will be called.
|
||||
* @param event the event that occured
|
||||
* @return the next selected view, which returns control to the client and
|
||||
* requests that a view be rendered with model data
|
||||
* @throws FlowExecutionException if an exception was thrown within a state
|
||||
* of the flow during execution of this signalEvent operation
|
||||
* @return the next selected view, which returns control to the client and requests that a view be rendered with
|
||||
* model data
|
||||
* @throws FlowExecutionException if an exception was thrown within a state of the flow during execution of this
|
||||
* signalEvent operation
|
||||
* @see Flow#onEvent(RequestControlContext)
|
||||
*/
|
||||
public ViewSelection signalEvent(Event event) throws FlowExecutionException;
|
||||
|
||||
/**
|
||||
* End the active flow session of the current flow execution. This method
|
||||
* should be called by clients that terminate flows, such as end states. The
|
||||
* <code>end()</code> method of the flow involved in the flow execution
|
||||
* will be called.
|
||||
* @param output output produced by the session that is eligible for mapping
|
||||
* by a resuming parent flow
|
||||
* End the active flow session of the current flow execution. This method should be called by clients that terminate
|
||||
* flows, such as end states. The <code>end()</code> method of the flow involved in the flow execution will be
|
||||
* called.
|
||||
* @param output output produced by the session that is eligible for mapping by a resuming parent flow
|
||||
* @return the ended session
|
||||
* @throws IllegalStateException when the flow execution is not active
|
||||
* @see Flow#end(RequestControlContext, MutableAttributeMap)
|
||||
@@ -127,8 +110,8 @@ public interface RequestControlContext extends RequestContext {
|
||||
public FlowSession endActiveFlowSession(MutableAttributeMap output) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Execute this transition out of the current source state. Allows for
|
||||
* privileged execution of an arbitrary transition.
|
||||
* Execute this transition out of the current source state. Allows for privileged execution of an arbitrary
|
||||
* transition.
|
||||
* @param transition the transition
|
||||
* @return a new view selection
|
||||
* @see Transition#execute(State, RequestControlContext)
|
||||
|
||||
@@ -25,18 +25,15 @@ import org.springframework.webflow.execution.FlowExecutionException;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A point in a flow where something happens. What happens is determined by a
|
||||
* state's type. Standard types of states include action states, view states,
|
||||
* subflow states, and end states.
|
||||
* A point in a flow where something happens. What happens is determined by a state's type. Standard types of states
|
||||
* include action states, view states, subflow states, and end states.
|
||||
* <p>
|
||||
* Each state is associated with exactly one owning flow definition.
|
||||
* Specializations of this class capture all the configuration information
|
||||
* needed for a specific kind of state.
|
||||
* Each state is associated with exactly one owning flow definition. Specializations of this class capture all the
|
||||
* configuration information needed for a specific kind of state.
|
||||
* <p>
|
||||
* Subclasses should implement the <code>doEnter</code> method to execute the
|
||||
* processing that should occur when this state is entered, acting on its
|
||||
* configuration information. The ability to plugin custom state types that
|
||||
* execute different behaviour polymorphically is the classic GoF state pattern.
|
||||
* Subclasses should implement the <code>doEnter</code> method to execute the processing that should occur when this
|
||||
* state is entered, acting on its configuration information. The ability to plugin custom state types that execute
|
||||
* different behaviour polymorphically is the classic GoF state pattern.
|
||||
* <p>
|
||||
* Equality: Two states are equal if they have the same id and are part of the same flow.
|
||||
*
|
||||
@@ -78,13 +75,12 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
private FlowExecutionExceptionHandlerSet exceptionHandlerSet = new FlowExecutionExceptionHandlerSet();
|
||||
|
||||
/**
|
||||
* Creates a state for the provided <code>flow</code> identified by the
|
||||
* provided <code>id</code>. The id must be locally unique to the owning
|
||||
* flow. The state will be automatically added to the flow.
|
||||
* Creates a state for the provided <code>flow</code> identified by the provided <code>id</code>. The id must
|
||||
* be locally unique to the owning flow. The state will be automatically added to the flow.
|
||||
* @param flow the owning flow
|
||||
* @param id the state identifier (must be unique to the flow)
|
||||
* @throws IllegalArgumentException if this state cannot be added to the
|
||||
* flow, for instance when the provided id is not unique in the owning flow
|
||||
* @throws IllegalArgumentException if this state cannot be added to the flow, for instance when the provided id is
|
||||
* not unique in the owning flow
|
||||
* @see #getEntryActionList()
|
||||
* @see #getExceptionHandlerSet()
|
||||
*/
|
||||
@@ -98,13 +94,13 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
public FlowDefinition getOwner() {
|
||||
return flow;
|
||||
}
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
// implementation specific
|
||||
|
||||
|
||||
/**
|
||||
* Returns the owning flow.
|
||||
*/
|
||||
@@ -114,8 +110,7 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
|
||||
/**
|
||||
* Set the owning flow.
|
||||
* @throws IllegalArgumentException if this state cannot be added to the
|
||||
* flow
|
||||
* @throws IllegalArgumentException if this state cannot be added to the flow
|
||||
*/
|
||||
private void setFlow(Flow flow) throws IllegalArgumentException {
|
||||
Assert.hasText(getId(), "The id of the state should be set before adding the state to a flow");
|
||||
@@ -134,8 +129,7 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of actions executed by this state when it is entered.
|
||||
* The returned list is mutable.
|
||||
* Returns the list of actions executed by this state when it is entered. The returned list is mutable.
|
||||
* @return the state entry action list
|
||||
*/
|
||||
public ActionList getEntryActionList() {
|
||||
@@ -143,12 +137,11 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable set of exception handlers, allowing manipulation of how
|
||||
* exceptions are handled when thrown within this state.
|
||||
* Returns a mutable set of exception handlers, allowing manipulation of how exceptions are handled when thrown
|
||||
* within this state.
|
||||
* <p>
|
||||
* Exception handlers are invoked when an exception occurs when this state
|
||||
* is entered, and can execute custom exception handling logic as well as
|
||||
* select an error view to display.
|
||||
* Exception handlers are invoked when an exception occurs when this state is entered, and can execute custom
|
||||
* exception handling logic as well as select an error view to display.
|
||||
* @return the state exception handler set
|
||||
*/
|
||||
public FlowExecutionExceptionHandlerSet getExceptionHandlerSet() {
|
||||
@@ -156,39 +149,37 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flag indicating if this state is the start state of its owning
|
||||
* flow.
|
||||
* Returns a flag indicating if this state is the start state of its owning flow.
|
||||
* @return true if the flow is the start state, false otherwise
|
||||
*/
|
||||
public boolean isStartState() {
|
||||
return flow.getStartState() == this;
|
||||
}
|
||||
|
||||
|
||||
// id and flow based equality
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof State)) {
|
||||
return false;
|
||||
}
|
||||
State other = (State)o;
|
||||
State other = (State) o;
|
||||
return id.equals(other.id) && flow.equals(other.flow);
|
||||
}
|
||||
|
||||
|
||||
public int hashCode() {
|
||||
return id.hashCode() + flow.hashCode();
|
||||
}
|
||||
|
||||
|
||||
// behavioral methods
|
||||
|
||||
|
||||
/**
|
||||
* Enter this state in the provided flow control context. This
|
||||
* implementation just calls the
|
||||
* {@link #doEnter(RequestControlContext)} hook method, which should
|
||||
* be implemented by subclasses, after executing the entry actions.
|
||||
* @param context the control context for the currently executing flow, used
|
||||
* by this state to manipulate the flow execution
|
||||
* @return a view selection containing model and view information needed to
|
||||
* render the results of the state processing
|
||||
* Enter this state in the provided flow control context. This implementation just calls the
|
||||
* {@link #doEnter(RequestControlContext)} hook method, which should be implemented by subclasses, after executing
|
||||
* the entry actions.
|
||||
* @param context the control context for the currently executing flow, used by this state to manipulate the flow
|
||||
* execution
|
||||
* @return a view selection containing model and view information needed to render the results of the state
|
||||
* processing
|
||||
* @throws FlowExecutionException if an exception occurs in this state
|
||||
*/
|
||||
public final ViewSelection enter(RequestControlContext context) throws FlowExecutionException {
|
||||
@@ -201,24 +192,22 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook method to execute custom behaviour as a result of entering this
|
||||
* state. By implementing this method subclasses specialize the behaviour of
|
||||
* the state.
|
||||
* @param context the control context for the currently executing flow, used
|
||||
* by this state to manipulate the flow execution
|
||||
* @return a view selection containing model and view information needed to
|
||||
* render the results of the state processing
|
||||
* Hook method to execute custom behaviour as a result of entering this state. By implementing this method
|
||||
* subclasses specialize the behaviour of the state.
|
||||
* @param context the control context for the currently executing flow, used by this state to manipulate the flow
|
||||
* execution
|
||||
* @return a view selection containing model and view information needed to render the results of the state
|
||||
* processing
|
||||
* @throws FlowExecutionException if an exception occurs in this state
|
||||
*/
|
||||
protected abstract ViewSelection doEnter(RequestControlContext context) throws FlowExecutionException;
|
||||
|
||||
/**
|
||||
* Handle an exception that occured in this state during the context of the
|
||||
* current flow execution request.
|
||||
* Handle an exception that occured in this state during the context of the current flow execution request.
|
||||
* @param exception the exception that occured
|
||||
* @param context the flow execution control context
|
||||
* @return the selected error view, or <code>null</code> if no handler
|
||||
* matched or returned a non-null view selection
|
||||
* @return the selected error view, or <code>null</code> if no handler matched or returned a non-null view
|
||||
* selection
|
||||
*/
|
||||
public ViewSelection handleException(FlowExecutionException exception, RequestControlContext context) {
|
||||
return getExceptionHandlerSet().handleException(exception, context);
|
||||
@@ -233,8 +222,8 @@ public abstract class State extends AnnotatedObject implements StateDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this hook method to stringify their internal
|
||||
* state. This default implementation does nothing.
|
||||
* Subclasses may override this hook method to stringify their internal state. This default implementation does
|
||||
* nothing.
|
||||
* @param creator the toString creator, to stringify properties
|
||||
*/
|
||||
protected void appendToString(ToStringCreator creator) {
|
||||
|
||||
@@ -24,17 +24,13 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A transitionable state that spawns a subflow when executed. When the subflow
|
||||
* this state spawns ends, the ending result is used as grounds for a state
|
||||
* transition out of this state.
|
||||
* A transitionable state that spawns a subflow when executed. When the subflow this state spawns ends, the ending
|
||||
* result is used as grounds for a state transition out of this state.
|
||||
* <p>
|
||||
* A subflow state may be configured to map input data from its flow -- acting
|
||||
* as the parent flow -- down to the subflow when the subflow is spawned. In
|
||||
* addition, output data produced by the subflow may be mapped up to the parent
|
||||
* flow when the subflow ends and the parent flow resumes. See the
|
||||
* {@link FlowAttributeMapper} interface definition for more information on how
|
||||
* to do this. The logic for ending a subflow is located in the {@link EndState}
|
||||
* implementation.
|
||||
* A subflow state may be configured to map input data from its flow -- acting as the parent flow -- down to the subflow
|
||||
* when the subflow is spawned. In addition, output data produced by the subflow may be mapped up to the parent flow
|
||||
* when the subflow ends and the parent flow resumes. See the {@link FlowAttributeMapper} interface definition for more
|
||||
* information on how to do this. The logic for ending a subflow is located in the {@link EndState} implementation.
|
||||
*
|
||||
* @see org.springframework.webflow.engine.FlowAttributeMapper
|
||||
* @see org.springframework.webflow.engine.EndState
|
||||
@@ -50,8 +46,7 @@ public class SubflowState extends TransitionableState {
|
||||
private Flow subflow;
|
||||
|
||||
/**
|
||||
* The attribute mapper that should map attributes from the parent flow down
|
||||
* to the spawned subflow and visa versa.
|
||||
* The attribute mapper that should map attributes from the parent flow down to the spawned subflow and visa versa.
|
||||
*/
|
||||
private FlowAttributeMapper attributeMapper;
|
||||
|
||||
@@ -60,8 +55,7 @@ public class SubflowState extends TransitionableState {
|
||||
* @param flow the owning flow
|
||||
* @param id the state identifier (must be unique to the flow)
|
||||
* @param subflow the subflow to spawn
|
||||
* @throws IllegalArgumentException when this state cannot be added to given
|
||||
* flow, e.g. because the id is not unique
|
||||
* @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique
|
||||
* @see #setAttributeMapper(FlowAttributeMapper)
|
||||
*/
|
||||
public SubflowState(Flow flow, String id, Flow subflow) throws IllegalArgumentException {
|
||||
@@ -86,31 +80,29 @@ public class SubflowState extends TransitionableState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attribute mapper used to map data between the parent and child
|
||||
* flow, or null if no mapping is needed.
|
||||
* Returns the attribute mapper used to map data between the parent and child flow, or null if no mapping is needed.
|
||||
*/
|
||||
public FlowAttributeMapper getAttributeMapper() {
|
||||
return attributeMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attribute mapper used to map model data between the parent and
|
||||
* child flow. Can be null if no mapping is needed.
|
||||
* Set the attribute mapper used to map model data between the parent and child flow. Can be null if no mapping is
|
||||
* needed.
|
||||
*/
|
||||
public void setAttributeMapper(FlowAttributeMapper attributeMapper) {
|
||||
this.attributeMapper = attributeMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of State's <code>doEnter</code> template method that
|
||||
* executes behaviour specific to this state type in polymorphic fashion.
|
||||
* Specialization of State's <code>doEnter</code> template method that executes behaviour specific to this state
|
||||
* type in polymorphic fashion.
|
||||
* <p>
|
||||
* Entering this state, creates the subflow input map and spawns the subflow
|
||||
* in the current flow execution.
|
||||
* @param context the control context for the currently executing flow, used
|
||||
* by this state to manipulate the flow execution
|
||||
* @return a view selection containing model and view information needed to
|
||||
* render the results of the state execution
|
||||
* Entering this state, creates the subflow input map and spawns the subflow in the current flow execution.
|
||||
* @param context the control context for the currently executing flow, used by this state to manipulate the flow
|
||||
* execution
|
||||
* @return a view selection containing model and view information needed to render the results of the state
|
||||
* execution
|
||||
* @throws FlowExecutionException if an exception occurs in this state
|
||||
*/
|
||||
protected ViewSelection doEnter(RequestControlContext context) throws FlowExecutionException {
|
||||
@@ -121,8 +113,8 @@ public class SubflowState extends TransitionableState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the input data map for the spawned subflow session. The returned
|
||||
* map will be passed to {@link Flow#start(RequestControlContext, MutableAttributeMap)}.
|
||||
* Create the input data map for the spawned subflow session. The returned map will be passed to
|
||||
* {@link Flow#start(RequestControlContext, MutableAttributeMap)}.
|
||||
*/
|
||||
protected MutableAttributeMap createSubflowInput(RequestContext context) {
|
||||
if (getAttributeMapper() != null) {
|
||||
@@ -131,20 +123,19 @@ public class SubflowState extends TransitionableState {
|
||||
+ "down to the spawned subflow for access within the subflow");
|
||||
}
|
||||
return getAttributeMapper().createFlowInput(context);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No attribute mapper configured for this subflow state '" + getId()
|
||||
+ "' -- As a result, no attributes will be passed to the spawned subflow '"
|
||||
+ subflow.getId() + "'");
|
||||
+ "' -- As a result, no attributes will be passed to the spawned subflow '" + subflow.getId()
|
||||
+ "'");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on completion of the subflow to handle the subflow result event as
|
||||
* determined by the end state reached by the subflow.
|
||||
* Called on completion of the subflow to handle the subflow result event as determined by the end state reached by
|
||||
* the subflow.
|
||||
*/
|
||||
public ViewSelection onEvent(RequestControlContext context) {
|
||||
mapSubflowOutput(context.getLastEvent().getAttributes(), context);
|
||||
@@ -152,21 +143,22 @@ public class SubflowState extends TransitionableState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the output data produced by the subflow back into the request context
|
||||
* (typically flow scope).
|
||||
* Map the output data produced by the subflow back into the request context (typically flow scope).
|
||||
*/
|
||||
private void mapSubflowOutput(AttributeMap subflowOutput, RequestContext context) {
|
||||
if (getAttributeMapper() != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Messaging the configured attribute mapper to map subflow result attributes to the "
|
||||
+ "resuming parent flow -- It will have access to attributes passed up by the completed subflow");
|
||||
logger
|
||||
.debug("Messaging the configured attribute mapper to map subflow result attributes to the "
|
||||
+ "resuming parent flow -- It will have access to attributes passed up by the completed subflow");
|
||||
}
|
||||
attributeMapper.mapFlowOutput(subflowOutput, context);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No attribute mapper is configured for the resuming subflow state '" + getId()
|
||||
+ "' -- As a result, no attributes of the ending flow will be passed to the resuming parent flow");
|
||||
logger
|
||||
.debug("No attribute mapper is configured for the resuming subflow state '"
|
||||
+ getId()
|
||||
+ "' -- As a result, no attributes of the ending flow will be passed to the resuming parent flow");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,16 @@ package org.springframework.webflow.engine;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* A strategy for calculating the target state of a transition. This facilitates
|
||||
* dynamic transition target state resolution that takes into account runtime
|
||||
* contextual information.
|
||||
* A strategy for calculating the target state of a transition. This facilitates dynamic transition target state
|
||||
* resolution that takes into account runtime contextual information.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface TargetStateResolver {
|
||||
|
||||
/**
|
||||
* Resolve the target state of the transition from the source state in the
|
||||
* current request context. Should never return null.
|
||||
* Resolve the target state of the transition from the source state in the current request context. Should never
|
||||
* return null.
|
||||
* @param transition the transition
|
||||
* @param sourceState the source state of the transition, could be null
|
||||
* @param context the current request context
|
||||
|
||||
@@ -26,32 +26,24 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
|
||||
/**
|
||||
* A path from one {@link TransitionableState state} to another
|
||||
* {@link State state}.
|
||||
* A path from one {@link TransitionableState state} to another {@link State state}.
|
||||
* <p>
|
||||
* When executed a transition takes a flow execution from its current state,
|
||||
* called the <i>source state</i>, to another state, called the </i>target
|
||||
* state</i>. A transition may become eligible for execution on the occurence
|
||||
* of an {@link Event} from within a transitionable source state.
|
||||
* When executed a transition takes a flow execution from its current state, called the <i>source state</i>, to another
|
||||
* state, called the </i>target state</i>. A transition may become eligible for execution on the occurence of an
|
||||
* {@link Event} from within a transitionable source state.
|
||||
* <p>
|
||||
* When an event occurs within this transition's source
|
||||
* <code>TransitionableState</code> the determination of the eligibility of
|
||||
* this transition is made by a <code>TransitionCriteria</code> object called
|
||||
* the <i>matching criteria</i>. If the matching criteria returns
|
||||
* <code>true</code> this transition is marked eligible for execution for that
|
||||
* event.
|
||||
* When an event occurs within this transition's source <code>TransitionableState</code> the determination of the
|
||||
* eligibility of this transition is made by a <code>TransitionCriteria</code> object called the <i>matching criteria</i>.
|
||||
* If the matching criteria returns <code>true</code> this transition is marked eligible for execution for that event.
|
||||
* <p>
|
||||
* Determination as to whether an eligible transition should be allowed to
|
||||
* execute is made by a <code>TransitionCriteria</code> object called the
|
||||
* <i>execution criteria</i>. If the execution criteria test fails this
|
||||
* transition will <i>roll back</i> and reenter its source state. If the
|
||||
* execution criteria test succeeds this transition will execute and take the
|
||||
* flow to the transition's target state.
|
||||
* Determination as to whether an eligible transition should be allowed to execute is made by a
|
||||
* <code>TransitionCriteria</code> object called the <i>execution criteria</i>. If the execution criteria test fails
|
||||
* this transition will <i>roll back</i> and reenter its source state. If the execution criteria test succeeds this
|
||||
* transition will execute and take the flow to the transition's target state.
|
||||
* <p>
|
||||
* The target state of this transition is typically specified at configuration
|
||||
* time in a static manner. If the target state of this transition needs to be
|
||||
* calculated in a dynamic fashion at runtime configure a {@link TargetStateResolver}
|
||||
* that supports such calculations.
|
||||
* The target state of this transition is typically specified at configuration time in a static manner. If the target
|
||||
* state of this transition needs to be calculated in a dynamic fashion at runtime configure a
|
||||
* {@link TargetStateResolver} that supports such calculations.
|
||||
*
|
||||
* @see TransitionableState
|
||||
* @see TransitionCriteria
|
||||
@@ -68,29 +60,26 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
protected final Log logger = LogFactory.getLog(Transition.class);
|
||||
|
||||
/**
|
||||
* The criteria that determine whether or not this transition matches as
|
||||
* eligible for execution when an event occurs in the source state.
|
||||
* The criteria that determine whether or not this transition matches as eligible for execution when an event occurs
|
||||
* in the source state.
|
||||
*/
|
||||
private TransitionCriteria matchingCriteria;
|
||||
|
||||
/**
|
||||
* The criteria that determine whether or not this transition, once matched,
|
||||
* should complete execution or should <i>roll back</i>.
|
||||
* The criteria that determine whether or not this transition, once matched, should complete execution or should
|
||||
* <i>roll back</i>.
|
||||
*/
|
||||
private TransitionCriteria executionCriteria = WildcardTransitionCriteria.INSTANCE;
|
||||
|
||||
/**
|
||||
* The resolver responsible for calculating the target state of this
|
||||
* transition.
|
||||
* The resolver responsible for calculating the target state of this transition.
|
||||
*/
|
||||
private TargetStateResolver targetStateResolver;
|
||||
|
||||
/**
|
||||
* Create a new transition that always matches and always executes,
|
||||
* transitioning to the target state calculated by the provided
|
||||
* targetStateResolver.
|
||||
* @param targetStateResolver the resolver of the target state of this
|
||||
* transition
|
||||
* Create a new transition that always matches and always executes, transitioning to the target state calculated by
|
||||
* the provided targetStateResolver.
|
||||
* @param targetStateResolver the resolver of the target state of this transition
|
||||
* @see #setMatchingCriteria(TransitionCriteria)
|
||||
* @see #setExecutionCriteria(TransitionCriteria)
|
||||
*/
|
||||
@@ -99,12 +88,10 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new transition that matches on the specified criteria,
|
||||
* transitioning to the target state calculated by the provided
|
||||
* targetStateResolver.
|
||||
* Create a new transition that matches on the specified criteria, transitioning to the target state calculated by
|
||||
* the provided targetStateResolver.
|
||||
* @param matchingCriteria the criteria for matching this transition
|
||||
* @param targetStateResolver the resolver of the target state of this
|
||||
* transition
|
||||
* @param targetStateResolver the resolver of the target state of this transition
|
||||
* @see #setExecutionCriteria(TransitionCriteria)
|
||||
*/
|
||||
public Transition(TransitionCriteria matchingCriteria, TargetStateResolver targetStateResolver) {
|
||||
@@ -123,8 +110,7 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the criteria that determine whether or not this transition
|
||||
* matches as eligible for execution.
|
||||
* Returns the criteria that determine whether or not this transition matches as eligible for execution.
|
||||
* @return the transition matching criteria
|
||||
*/
|
||||
public TransitionCriteria getMatchingCriteria() {
|
||||
@@ -132,8 +118,7 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the criteria that determine whether or not this transition matches as
|
||||
* eligible for execution.
|
||||
* Set the criteria that determine whether or not this transition matches as eligible for execution.
|
||||
* @param matchingCriteria the transition matching criteria
|
||||
*/
|
||||
public void setMatchingCriteria(TransitionCriteria matchingCriteria) {
|
||||
@@ -142,8 +127,8 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the criteria that determine whether or not this transition, once
|
||||
* matched, should complete execution or should <i>roll back</i>.
|
||||
* Returns the criteria that determine whether or not this transition, once matched, should complete execution or
|
||||
* should <i>roll back</i>.
|
||||
* @return the transition execution criteria
|
||||
*/
|
||||
public TransitionCriteria getExecutionCriteria() {
|
||||
@@ -151,8 +136,8 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the criteria that determine whether or not this transition, once
|
||||
* matched, should complete execution or should <i>roll back</i>.
|
||||
* Set the criteria that determine whether or not this transition, once matched, should complete execution or should
|
||||
* <i>roll back</i>.
|
||||
* @param executionCriteria the transition execution criteria
|
||||
*/
|
||||
public void setExecutionCriteria(TransitionCriteria executionCriteria) {
|
||||
@@ -168,8 +153,8 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this transition's target state resolver, to calculate what state to
|
||||
* transition to when this transition is executed.
|
||||
* Set this transition's target state resolver, to calculate what state to transition to when this transition is
|
||||
* executed.
|
||||
* @param targetStateResolver the target state resolver
|
||||
*/
|
||||
public void setTargetStateResolver(TargetStateResolver targetStateResolver) {
|
||||
@@ -178,8 +163,8 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this transition is elligible for execution given the state of
|
||||
* the provided flow execution request context.
|
||||
* Checks if this transition is elligible for execution given the state of the provided flow execution request
|
||||
* context.
|
||||
* @param context the flow execution request context
|
||||
* @return true if this transition should execute, false otherwise
|
||||
*/
|
||||
@@ -188,22 +173,21 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this transition can complete its execution or should be rolled
|
||||
* back, given the state of the flow execution request context.
|
||||
* Checks if this transition can complete its execution or should be rolled back, given the state of the flow
|
||||
* execution request context.
|
||||
* @param context the flow execution request context
|
||||
* @return true if this transition can complete execution, false if it
|
||||
* should roll back
|
||||
* @return true if this transition can complete execution, false if it should roll back
|
||||
*/
|
||||
public boolean canExecute(RequestContext context) {
|
||||
return executionCriteria.test(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute this state transition. Will only be called if the
|
||||
* {@link #matches(RequestContext)} method returns true for given context.
|
||||
* Execute this state transition. Will only be called if the {@link #matches(RequestContext)} method returns true
|
||||
* for given context.
|
||||
* @param context the flow execution control context
|
||||
* @return a view selection containing model and view information needed to
|
||||
* render the results of the transition execution
|
||||
* @return a view selection containing model and view information needed to render the results of the transition
|
||||
* execution
|
||||
* @throws FlowExecutionException when transition execution fails
|
||||
*/
|
||||
public ViewSelection execute(State sourceState, RequestControlContext context) throws FlowExecutionException {
|
||||
@@ -215,10 +199,9 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
}
|
||||
if (sourceState instanceof TransitionableState) {
|
||||
// make exit call back on transitionable state
|
||||
((TransitionableState)sourceState).exit(context);
|
||||
((TransitionableState) sourceState).exit(context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing " + this);
|
||||
}
|
||||
@@ -227,15 +210,12 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
context.setLastTransition(this);
|
||||
// enter the target state (note: any exceptions are propagated)
|
||||
selectedView = targetState.enter(context);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (sourceState != null && sourceState instanceof TransitionableState) {
|
||||
// 'roll back' and re-enter the transitionable source state
|
||||
selectedView = ((TransitionableState)sourceState).reenter(context);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Execution of '" + this + "' was blocked by '" + getExecutionCriteria()
|
||||
selectedView = ((TransitionableState) sourceState).reenter(context);
|
||||
} else {
|
||||
throw new IllegalStateException("Execution of '" + this + "' was blocked by '" + getExecutionCriteria()
|
||||
+ "', " + "; however, no source state is set at runtime. "
|
||||
+ "This is an illegal situation: check your flow definition.");
|
||||
}
|
||||
@@ -244,8 +224,7 @@ public class Transition extends AnnotatedObject implements TransitionDefinition
|
||||
if (context.getFlowExecutionContext().isActive()) {
|
||||
logger.debug("Completed execution of " + this + ", as a result the new state is '"
|
||||
+ context.getCurrentState().getId() + "' in flow '" + context.getActiveFlow().getId() + "'");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logger.debug("Completed execution of " + this + ", as a result the flow execution has ended");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ package org.springframework.webflow.engine;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Strategy interface encapsulating criteria that determine whether
|
||||
* or not a transition should execute given a flow execution request context.
|
||||
* Strategy interface encapsulating criteria that determine whether or not a transition should execute given a flow
|
||||
* execution request context.
|
||||
*
|
||||
* @see org.springframework.webflow.engine.Transition
|
||||
* @see org.springframework.webflow.execution.RequestContext
|
||||
@@ -30,8 +30,7 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
public interface TransitionCriteria {
|
||||
|
||||
/**
|
||||
* Check if the transition should fire based on the given flow execution
|
||||
* request context.
|
||||
* Check if the transition should fire based on the given flow execution request context.
|
||||
* @param context the flow execution request context
|
||||
* @return true if the transition should fire, false otherwise
|
||||
*/
|
||||
|
||||
@@ -24,8 +24,7 @@ import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* A typed set of transitions for use internally by artifacts that can
|
||||
* apply transition execution logic.
|
||||
* A typed set of transitions for use internally by artifacts that can apply transition execution logic.
|
||||
*
|
||||
* @see TransitionableState#getTransitionSet()
|
||||
* @see Flow#getGlobalTransitionSet()
|
||||
@@ -42,8 +41,7 @@ public class TransitionSet {
|
||||
/**
|
||||
* Add a transition to this set.
|
||||
* @param transition the transition to add
|
||||
* @return true if this set's contents changed as a result of the add
|
||||
* operation
|
||||
* @return true if this set's contents changed as a result of the add operation
|
||||
*/
|
||||
public boolean add(Transition transition) {
|
||||
if (contains(transition)) {
|
||||
@@ -55,8 +53,7 @@ public class TransitionSet {
|
||||
/**
|
||||
* Add a collection of transition instances to this set.
|
||||
* @param transitions the transitions to add
|
||||
* @return true if this set's contents changed as a result of the add
|
||||
* operation
|
||||
* @return true if this set's contents changed as a result of the add operation
|
||||
*/
|
||||
public boolean addAll(Transition[] transitions) {
|
||||
return CollectionUtils.addAllNoDuplicates(this.transitions, transitions);
|
||||
@@ -74,8 +71,7 @@ public class TransitionSet {
|
||||
/**
|
||||
* Remove the transition instance from this set.
|
||||
* @param transition the transition to remove
|
||||
* @return true if this list's contents changed as a result of the remove
|
||||
* operation
|
||||
* @return true if this list's contents changed as a result of the remove operation
|
||||
*/
|
||||
public boolean remove(Transition transition) {
|
||||
return transitions.remove(transition);
|
||||
@@ -94,12 +90,11 @@ public class TransitionSet {
|
||||
* @return the transition set as a typed array
|
||||
*/
|
||||
public Transition[] toArray() {
|
||||
return (Transition[])transitions.toArray(new Transition[transitions.size()]);
|
||||
return (Transition[]) transitions.toArray(new Transition[transitions.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the supported transitional criteria used to match
|
||||
* transitions in this state.
|
||||
* Returns a list of the supported transitional criteria used to match transitions in this state.
|
||||
* @return the list of transitional criteria
|
||||
*/
|
||||
public TransitionCriteria[] getTransitionCriterias() {
|
||||
@@ -107,21 +102,20 @@ public class TransitionSet {
|
||||
int i = 0;
|
||||
Iterator it = transitions.iterator();
|
||||
while (it.hasNext()) {
|
||||
criterias[i++] = ((Transition)it.next()).getMatchingCriteria();
|
||||
criterias[i++] = ((Transition) it.next()).getMatchingCriteria();
|
||||
}
|
||||
return criterias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a transition for given flow execution request context. The first
|
||||
* matching transition will be returned.
|
||||
* Gets a transition for given flow execution request context. The first matching transition will be returned.
|
||||
* @param context a flow execution context
|
||||
* @return the transition, or null if no transition matches
|
||||
*/
|
||||
public Transition getTransition(RequestContext context) {
|
||||
Iterator it = transitions.iterator();
|
||||
while (it.hasNext()) {
|
||||
Transition transition = (Transition)it.next();
|
||||
Transition transition = (Transition) it.next();
|
||||
if (transition.matches(context)) {
|
||||
return transition;
|
||||
}
|
||||
@@ -130,8 +124,7 @@ public class TransitionSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this list has a transition that will fire for
|
||||
* given flow execution request context.
|
||||
* Returns whether or not this list has a transition that will fire for given flow execution request context.
|
||||
* @param context a flow execution context
|
||||
*/
|
||||
public boolean hasMatchingTransition(RequestContext context) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user