Brought spring-webflow code to formatting conventions

This commit is contained in:
Ben Hale
2007-08-15 12:48:01 +00:00
parent cf9bfdd522
commit 5f6da23f47
379 changed files with 7042 additions and 9013 deletions

View File

@@ -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 {
}

View File

@@ -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-&gt;bean method binding,
* accepting a {@link MethodSignature} and
* The method invoker that performs the action-&gt;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-&gt;event adaption strategy. Defaults to
* {@link SuccessEventFactory}, so all bean method return values will be
* interpreted as "success".
* Set the bean return value-&gt;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

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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");
}
}

View File

@@ -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
*/

View File

@@ -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
*/

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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
*/

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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
*/

View File

@@ -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);
}

View File

@@ -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");
}
}
}

View File

@@ -22,7 +22,7 @@ import org.w3c.dom.Element;
/**
* {@link BeanDefinitionParser} for the <code>&lt;enable-scopes&gt;</code> tag.
*
*
* @author Ben Hale
* @since 1.1
*/

View File

@@ -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) {

View File

@@ -29,21 +29,20 @@ import org.springframework.webflow.execution.factory.ConditionalFlowExecutionLis
import org.w3c.dom.Element;
/**
* {@link BeanDefinitionParser} for the <code>&lt;execution-listeners&gt;</code>
* tag.
* {@link BeanDefinitionParser} for the <code>&lt;execution-listeners&gt;</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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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!
*/

View File

@@ -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>&lt;executor&gt;</code> and <code>&lt;registry&gt;</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>&lt;executor&gt;</code> and
* <code>&lt;registry&gt;</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">
* &lt;flow:executor id=&quot;registry&quot; registry-ref=&quot;registry&quot; repository-type=&quot;continuation&quot; &gt;
@@ -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">
* &lt;flow:registry id=&quot;registry&quot;&gt;

View File

@@ -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
*/

View File

@@ -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();

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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;
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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
*/

View File

@@ -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
*/

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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)
*/

View File

@@ -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(&quot;foo&quot;, &quot;bar&quot;);
* Object foo = conv.getAttribute(&quot;foo&quot;);
* }
* 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

View File

@@ -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();
}

View File

@@ -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
*/

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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();

View File

@@ -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.");

View File

@@ -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
*/

View File

@@ -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
*/

View File

@@ -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);

View File

@@ -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() {

View File

@@ -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}.
*/

View File

@@ -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. "

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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);

View File

@@ -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).
*/

View File

@@ -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());
}

View File

@@ -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));
}
/**

View File

@@ -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();
}
}

View File

@@ -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
*/

View File

@@ -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
*/

View 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();
}

View File

@@ -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();

View File

@@ -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.
*

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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: "

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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>
* &lt;action-state id=&quot;setupForm&quot;&gt;
@@ -72,36 +62,29 @@ import org.springframework.webflow.execution.ViewSelection;
* &lt;/action-state&gt;
* </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

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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() {

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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");
}
}
}

View File

@@ -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

View File

@@ -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");
}
}

View File

@@ -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
*/

View File

@@ -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