did some reformatting on abstract externalized flow execution tests (javadoc is only real change)
This commit is contained in:
Keith Donald
2007-06-13 03:56:58 +00:00
parent 546757ccb2
commit cde58941f9
6 changed files with 234 additions and 262 deletions

View File

@@ -26,7 +26,9 @@ Package org.springframework.webflow.engine
* Added name(String, Action) method to AbstractFlowBuilder for convenient creation of named actions.
* AnnotatedAction now has a convenience putAttribute(String, Object) method.
* Added annotate(Action) method to AbstractFlowBuilder.
* Added populateLocalContext(Flow, GenericApplicationContext, Resource[]) hook method to XmlFlowBuilder to allow for control over
the registration of beans needed locally by a flow definition. Useful for testing. (SWF-307).
Package org.springframework.webflow.executor
* JSF integration code now manages flow execution locks properly in exceptional situations and when the
RENDER RESPONSE phase is bypassed (SWF-302).
@@ -38,8 +40,10 @@ Package org.springframework.webflow.executor
resources are cleaned up after request processing (SWF-306).
Package org.springframework.webflow.test
* Added the ability to apply multiple listeners to a test case (SWF-334).
* Added the ability to attach multiple flow execution listeners to a test case (SWF-334).
* Relaxed 'final' qualifier on AbstractXmlFlowExecutionTests#createFlowBuilder(FlowServiceLocator). Overriding this method is useful
for customizing the builder's population of the bean factory local to the flow definition (SWF-307).
Changes in version 1.0.3 (19.04.2007)
-------------------------------------

View File

@@ -70,17 +70,9 @@ class LocalFlowServiceLocator implements FlowServiceLocator {
* @param registry the local registry
*/
public void push(LocalFlowServiceRegistry registry) {
registry.init(this, parent);
localRegistries.push(registry);
}
/**
* Pop a registry off the stack.
*/
public LocalFlowServiceRegistry pop() {
return (LocalFlowServiceRegistry)localRegistries.pop();
}
/**
* Pops all registries off the stack until the stack is empty.
*/
@@ -90,6 +82,13 @@ class LocalFlowServiceLocator implements FlowServiceLocator {
}
}
/**
* Pop a registry off the stack.
*/
public LocalFlowServiceRegistry pop() {
return (LocalFlowServiceRegistry)localRegistries.pop();
}
/**
* Returns the top registry on the stack
*/
@@ -183,7 +182,7 @@ class LocalFlowServiceLocator implements FlowServiceLocator {
}
public BeanFactory getBeanFactory() {
return top().getContext();
return top().getBeanFactory();
}
public ResourceLoader getResourceLoader() {
@@ -208,8 +207,7 @@ class LocalFlowServiceLocator implements FlowServiceLocator {
}
/**
* Does this flow local service locator contain a bean defintion
* for given id?
* Does this flow local service locator contain a bean defintion for the given id?
*/
protected boolean containsBean(String id) {
if (localRegistries.isEmpty()) {

View File

@@ -16,21 +16,14 @@
package org.springframework.webflow.engine.builder.xml;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.builder.FlowServiceLocator;
/**
* Simple value object that holds a reference to a local artifact registry
* of a flow definition that is in the process of being constructed.
* Simple value object that holds a reference to a local bean factory housing services neeed by a flow definition
* at execution time.
* <p>
* Internal helper class of the {@link org.springframework.webflow.engine.builder.xml.XmlFlowBuilder}.
* Package private to highlight it's non-public nature.
* Internal helper class of the {@link org.springframework.webflow.engine.builder.xml.XmlFlowBuilder}. Package private
* to highlight it's non-public nature.
*
* @see org.springframework.webflow.engine.builder.xml.XmlFlowBuilder
* @see org.springframework.webflow.engine.builder.xml.LocalFlowServiceLocator
@@ -44,25 +37,19 @@ class LocalFlowServiceRegistry {
*/
private Flow flow;
/**
* The locations of the registry resource definitions.
*/
private Resource[] resources;
/**
* The local registry holding the artifacts local to the flow.
*/
private GenericApplicationContext context;
private BeanFactory beanFactory;
/**
* Create a new registry, loading artifact definitions from
* given resources.
* Create a new local service registry.
* @param flow the flow this registry is for (and scoped by)
* @param resources the registry resource definitions
* @param beanFactory the actual backing registry - a Spring bean factory
*/
public LocalFlowServiceRegistry(Flow flow, Resource[] resources) {
public LocalFlowServiceRegistry(Flow flow, BeanFactory beanFactory) {
this.flow = flow;
this.resources = resources;
this.beanFactory = beanFactory;
}
/**
@@ -73,69 +60,9 @@ class LocalFlowServiceRegistry {
}
/**
* Returns the resources defining registry artifacts.
* Returns the bean factory acting as the physical registry.
*/
public Resource[] getResources() {
return resources;
}
/**
* Retuns the application context holding registry artifacts.
*/
public ApplicationContext getContext() {
return context;
}
/**
* Initialize this registry of the local flow service locator.
* @param localFactory the local flow service locator
* @param rootFactory the root service locator
*/
public void init(LocalFlowServiceLocator localFactory, FlowServiceLocator rootFactory) {
BeanFactory parent = null;
if (localFactory.isEmpty()) {
try {
parent = rootFactory.getBeanFactory();
}
catch (UnsupportedOperationException e) {
// can't link to a parent
}
}
else {
parent = localFactory.top().context;
}
context = createLocalFlowContext(parent, rootFactory);
new XmlBeanDefinitionReader(context).loadBeanDefinitions(resources);
context.refresh();
}
/**
* Create the flow local application context.
* @param parent the parent application context
* @param rootFactory the root service locator, used to obtain a resource
* loader
* @return the flow local application context
*/
private GenericApplicationContext createLocalFlowContext(BeanFactory parent, FlowServiceLocator rootFactory) {
if (parent instanceof WebApplicationContext) {
GenericWebApplicationContext context = new GenericWebApplicationContext();
context.setServletContext(((WebApplicationContext)parent).getServletContext());
context.setParent((WebApplicationContext)parent);
context.setResourceLoader(rootFactory.getResourceLoader());
return context;
}
else {
GenericApplicationContext context = new GenericApplicationContext();
if (parent instanceof ApplicationContext) {
context.setParent((ApplicationContext)parent);
}
else {
if (parent != null) {
context.getBeanFactory().setParentBeanFactory(parent);
}
}
context.setResourceLoader(rootFactory.getResourceLoader());
return context;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
}

View File

@@ -25,6 +25,7 @@ import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.expression.Expression;
@@ -38,11 +39,15 @@ import org.springframework.binding.mapping.RequiredMapping;
import org.springframework.binding.method.MethodSignature;
import org.springframework.binding.method.Parameter;
import org.springframework.binding.method.Parameters;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.webflow.action.ActionResultExposer;
import org.springframework.webflow.action.EvaluateAction;
import org.springframework.webflow.action.SetAction;
@@ -78,8 +83,7 @@ import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Flow builder that builds flows as defined in an XML document. The XML document
* should adhere to the following format:
* Flow builder that builds flows as defined in an XML document. The XML document should adhere to the following format:
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
@@ -94,17 +98,13 @@ import org.xml.sax.SAXException;
* </pre>
*
* <p>
* Consult the <a
* href="http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">webflow
* XML schema</a> for more information on the XML-based flow definition format.
* Consult the <a href="http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">webflow XML schema</a>
* for more information on the XML-based flow definition format.
* <p>
* This builder will setup a flow-local bean factory for the flow being
* constructed. That flow-local bean factory will be populated with XML bean
* definitions contained in files referenced using the "import" element. The
* flow-local bean factory will use the bean factory defing this flow builder as
* a parent. As such, the flow can access artifacts in either its flow-local
* bean factory or in the parent bean factory hierarchy, e.g. the bean factory
* of the dispatcher.
* This builder will setup a flow-local bean factory for the flow being constructed. That flow-local bean factory will
* be populated with XML bean definitions contained in files referenced using the "import" element. The flow-local bean
* factory will use the bean factory defing this flow builder as a parent. As such, the flow can access artifacts in
* either its flow-local bean factory or in the parent bean factory hierarchy, e.g. the bean factory of the dispatcher.
*
* @author Erwin Vervaet
* @author Keith Donald
@@ -238,15 +238,14 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private static final String RESOURCE_ATTRIBUTE = "resource";
/**
* The resource from which the document element being parsed was read. Used
* as a location for relative resource lookup.
* The resource from which the document element being parsed was read. Used as a location for relative resource
* lookup.
*/
protected Resource location;
/**
* A flow service locator local to this builder that first looks in a
* locally-managed Spring application context for services before searching
* the externally managed {@link #getFlowServiceLocator()}.
* A flow service locator local to this builder that first looks in a locally-managed Spring application context for
* services before searching the externally managed {@link #getFlowServiceLocator()}.
*/
private LocalFlowServiceLocator localFlowServiceLocator;
@@ -256,14 +255,12 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private DocumentLoader documentLoader = new DefaultDocumentLoader();
/**
* The in-memory document object model (DOM) of the XML Document read from
* the flow definition resource.
* The in-memory document object model (DOM) of the XML Document read from the flow definition resource.
*/
private Document document;
/**
* Create a new XML flow builder parsing the document at the specified
* location.
* Create a new XML flow builder parsing the document at the specified location.
* @param location the location of the XML-based flow definition resource
*/
public XmlFlowBuilder(Resource location) {
@@ -271,12 +268,10 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
}
/**
* Create a new XML flow builder parsing the document at the specified
* location, using the provided service locator to access externally managed
* flow artifacts.
* Create a new XML flow builder parsing the document at the specified location, using the provided service locator
* to access externally managed flow artifacts.
* @param location the location of the XML-based flow definition resource
* @param flowServiceLocator the locator for services needed by this builder
* to build its Flow
* @param flowServiceLocator the locator for services needed by this builder to build its Flow
*/
public XmlFlowBuilder(Resource location, FlowServiceLocator flowServiceLocator) {
super(flowServiceLocator);
@@ -284,16 +279,16 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
}
/**
* Returns the resource from which the document element was loaded. This is
* used for location relative loading of other resources.
* Returns the resource from which the document element was loaded. This is used for location relative loading of
* other resources.
*/
public Resource getLocation() {
return location;
}
/**
* Sets the resource from which the document element was loaded. This is
* used for location relative loading of other resources.
* Sets the resource from which the document element was loaded. This is used for location relative loading of other
* resources.
*/
public void setLocation(Resource location) {
Assert.notNull(location, "The resource location of the XML-based flow definition is required");
@@ -301,8 +296,8 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
}
/**
* Sets the loader that will load the XML-based flow definition document.
* Optional, defaults to {@link DefaultDocumentLoader}.
* Sets the loader that will load the XML-based flow definition document. Optional, defaults to
* {@link DefaultDocumentLoader}.
* @param documentLoader the document loader
*/
public void setDocumentLoader(DocumentLoader documentLoader) {
@@ -381,7 +376,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
public Resource getResource() {
return location;
}
// helpers
/**
@@ -406,8 +401,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
}
/**
* Returns the artifact factory of the flow service locator local
* to this builder.
* Returns the artifact factory of the flow service locator local to this builder.
*/
protected FlowArtifactFactory getFlowArtifactFactory() {
return getLocalFlowServiceLocator().getFlowArtifactFactory();
@@ -416,28 +410,25 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
// utility (from Spring 2.x DomUtils)
/**
* Utility method that returns the first child element identified by its
* name.
* Utility method that returns the first child element identified by its name.
* @param ele the DOM element to analyze
* @param childEleName the child element name to look for
* @return the <code>org.w3c.dom.Element</code> instance, or
* <code>null</code> if none found
* @return the <code>org.w3c.dom.Element</code> instance, or <code>null</code> if none found
*/
protected Element getChildElementByTagName(Element ele, String childEleName) {
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && nodeNameEquals(node, childEleName)) {
return (Element)node;
return (Element) node;
}
}
return null;
}
/**
* Namespace-aware equals comparison. Returns <code>true</code> if either
* {@link Node#getLocalName} or {@link Node#getNodeName} equals
* <code>desiredName</code>, otherwise returns <code>false</code>.
* Namespace-aware equals comparison. Returns <code>true</code> if either {@link Node#getLocalName} or
* {@link Node#getNodeName} equals <code>desiredName</code>, otherwise returns <code>false</code>.
*/
protected boolean nodeNameEquals(Node node, String desiredName) {
return desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName());
@@ -462,7 +453,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
List importElements = DomUtils.getChildElementsByTagName(flowElement, IMPORT_ELEMENT);
Resource[] resources = new Resource[importElements.size()];
for (int i = 0; i < importElements.size(); i++) {
Element importElement = (Element)importElements.get(i);
Element importElement = (Element) importElements.get(i);
try {
resources[i] = getLocation().createRelative(importElement.getAttribute(RESOURCE_ATTRIBUTE));
}
@@ -471,7 +462,66 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
+ importElement.getAttribute(RESOURCE_ATTRIBUTE) + "'", e);
}
}
localFlowServiceLocator.push(new LocalFlowServiceRegistry(flow, resources));
localFlowServiceLocator.push(new LocalFlowServiceRegistry(flow, createLocalBeanFactory(flow, resources)));
}
/**
* Create the local bean factory from the resources provided. This factory typcially houses services needed locally
* by the flow definition.
* @param flow the current flow definition being built
* @param resources the file resources to assemble the bean factory from; typically xml-based
* @return the bean factory
*/
private BeanFactory createLocalBeanFactory(Flow flow, Resource[] resources) {
// see if this factory has a parent
BeanFactory parent = null;
if (localFlowServiceLocator.isEmpty()) {
try {
parent = getFlowServiceLocator().getBeanFactory();
}
catch (UnsupportedOperationException e) {
// can't link to a parent
}
}
else {
parent = localFlowServiceLocator.top().getBeanFactory();
}
// determine the context implementation based on the current environment
GenericApplicationContext context;
if (parent instanceof WebApplicationContext) {
GenericWebApplicationContext webContext = new GenericWebApplicationContext();
webContext.setServletContext(((WebApplicationContext) parent).getServletContext());
context = webContext;
}
else {
context = new GenericApplicationContext();
}
// set the parent if necessary
if (parent instanceof ApplicationContext) {
context.setParent((ApplicationContext) parent);
}
else {
if (parent != null) {
context.getBeanFactory().setParentBeanFactory(parent);
}
}
context.setResourceLoader(getFlowServiceLocator().getResourceLoader());
// populate and initialize the context
populateLocalContext(flow, context, resources);
context.refresh();
return context;
}
/**
* Hook method subclasses may override to customize the population of the context local to the flow definition being built.
* Such a context typically houses services needed by the flow definition. A subclass might override this method to
* register mock implementations of services for a test environment.
* @param flow the current flow definition being built
* @param context the flow-local context to populate
* @param resources the imported XML resources that typically define the structure of this context
*/
protected void populateLocalContext(Flow flow, GenericApplicationContext context, Resource[] resources) {
new XmlBeanDefinitionReader(context).loadBeanDefinitions(resources);
}
private void destroyLocalServiceRegistry() {
@@ -481,7 +531,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private void parseAndAddFlowVariables(Element flowElement, Flow flow) {
List varElements = DomUtils.getChildElementsByTagName(flowElement, VAR_ELEMENT);
for (Iterator it = varElements.iterator(); it.hasNext();) {
flow.addVariable(parseVariable((Element)it.next()));
flow.addVariable(parseVariable((Element) it.next()));
}
}
@@ -489,12 +539,12 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
ScopeType scope = parseScope(element, ScopeType.FLOW);
if (StringUtils.hasText(element.getAttribute(BEAN_ATTRIBUTE))) {
BeanFactory beanFactory = getLocalFlowServiceLocator().getBeanFactory();
return new BeanFactoryFlowVariable(element.getAttribute(NAME_ATTRIBUTE),
element.getAttribute(BEAN_ATTRIBUTE), beanFactory, scope);
return new BeanFactoryFlowVariable(element.getAttribute(NAME_ATTRIBUTE), element
.getAttribute(BEAN_ATTRIBUTE), beanFactory, scope);
}
else {
if (StringUtils.hasText(element.getAttribute(CLASS_ATTRIBUTE))) {
Class variableClass = (Class)fromStringTo(Class.class).execute(element.getAttribute(CLASS_ATTRIBUTE));
Class variableClass = (Class) fromStringTo(Class.class).execute(element.getAttribute(CLASS_ATTRIBUTE));
return new SimpleFlowVariable(element.getAttribute(NAME_ATTRIBUTE), variableClass, scope);
}
else {
@@ -528,7 +578,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private void parseAndAddInlineFlowDefinitions(Element parentFlowElement, Flow flow) {
List inlineFlowElements = DomUtils.getChildElementsByTagName(parentFlowElement, INLINE_FLOW_ELEMENT);
for (Iterator it = inlineFlowElements.iterator(); it.hasNext();) {
Element inlineFlowElement = (Element)it.next();
Element inlineFlowElement = (Element) it.next();
String inlineFlowId = inlineFlowElement.getAttribute(ID_ATTRIBUTE);
Element flowElement = getChildElementByTagName(inlineFlowElement, FLOW_ATTRIBUTE);
Flow inlineFlow = parseFlow(inlineFlowId, null, flowElement);
@@ -547,7 +597,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
parseAndAddEndActions(flowElement, inlineFlow);
inlineFlow.setOutputMapper(parseOutputMapper(flowElement));
inlineFlow.getExceptionHandlerSet().addAll(parseExceptionHandlers(flowElement));
destroyLocalServiceRegistry();
}
@@ -556,7 +606,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
for (int i = 0; i < childNodeList.getLength(); i++) {
Node childNode = childNodeList.item(i);
if (childNode instanceof Element) {
Element stateElement = (Element)childNode;
Element stateElement = (Element) childNode;
if (nodeNameEquals(stateElement, ACTION_STATE_ELEMENT)) {
parseAndAddActionState(stateElement, flow);
}
@@ -600,9 +650,9 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
}
private void parseAndAddDecisionState(Element element, Flow flow) {
getFlowArtifactFactory().createDecisionState(
parseId(element), flow, parseEntryActions(element), parseIfs(element),
parseExceptionHandlers(element), parseExitActions(element), parseAttributes(element));
getFlowArtifactFactory()
.createDecisionState(parseId(element), flow, parseEntryActions(element), parseIfs(element),
parseExceptionHandlers(element), parseExitActions(element), parseAttributes(element));
}
private void parseAndAddSubflowState(Element element, Flow flow) {
@@ -655,21 +705,21 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
List transitions = new LinkedList();
List transitionElements = DomUtils.getChildElementsByTagName(element, TRANSITION_ELEMENT);
for (Iterator it = transitionElements.iterator(); it.hasNext();) {
Element transitionElement = (Element)it.next();
Element transitionElement = (Element) it.next();
if (!StringUtils.hasText(transitionElement.getAttribute(ON_EXCEPTION_ATTRIBUTE))) {
// the "on-exception transition" is not really a transition but rather
// a FlowExecutionExceptionHandler (see parseTransitionExecutingExceptionHandlers)
transitions.add(parseTransition(transitionElement));
}
}
return (Transition[])transitions.toArray(new Transition[transitions.size()]);
return (Transition[]) transitions.toArray(new Transition[transitions.size()]);
}
private Transition parseTransition(Element element) {
TransitionCriteria matchingCriteria = (TransitionCriteria)fromStringTo(TransitionCriteria.class).execute(
TransitionCriteria matchingCriteria = (TransitionCriteria) fromStringTo(TransitionCriteria.class).execute(
element.getAttribute(ON_ATTRIBUTE));
TargetStateResolver targetStateResolver = (TargetStateResolver)fromStringTo(TargetStateResolver.class).execute(
element.getAttribute(TO_ATTRIBUTE));
TargetStateResolver targetStateResolver = (TargetStateResolver) fromStringTo(TargetStateResolver.class)
.execute(element.getAttribute(TO_ATTRIBUTE));
TransitionCriteria executionCriteria = TransitionCriteriaChain.criteriaChainFor(parseAnnotatedActions(element));
return getFlowArtifactFactory().createTransition(targetStateResolver, matchingCriteria, executionCriteria,
parseAttributes(element));
@@ -677,7 +727,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private ViewSelector parseViewSelector(Element element) {
String viewName = element.getAttribute(VIEW_ATTRIBUTE);
return (ViewSelector)fromStringTo(ViewSelector.class).execute(viewName);
return (ViewSelector) fromStringTo(ViewSelector.class).execute(viewName);
}
private Flow parseSubflow(Element element) {
@@ -687,30 +737,30 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private AnnotatedAction[] parseAnnotatedActions(Element element) {
List actions = new LinkedList();
NodeList childNodeList = element.getChildNodes();
for (int i=0; i < childNodeList.getLength(); i++) {
for (int i = 0; i < childNodeList.getLength(); i++) {
Node childNode = childNodeList.item(i);
if (!(childNode instanceof Element)) {
continue;
}
if (nodeNameEquals(childNode, ACTION_ELEMENT)) {
// parse standard action
actions.add(parseAnnotatedAction((Element)childNode));
actions.add(parseAnnotatedAction((Element) childNode));
}
else if (nodeNameEquals(childNode, BEAN_ACTION_ELEMENT)) {
// parse bean invoking action
actions.add(parseAnnotatedBeanInvokingAction((Element)childNode));
actions.add(parseAnnotatedBeanInvokingAction((Element) childNode));
}
else if (nodeNameEquals(childNode, EVALUATE_ACTION_ELEMENT)) {
// parse evaluate action
actions.add(parseAnnotatedEvaluateAction((Element)childNode));
actions.add(parseAnnotatedEvaluateAction((Element) childNode));
}
else if (nodeNameEquals(childNode, SET_ELEMENT)) {
// parse set action
actions.add(parseAnnotatedSetAction((Element)childNode));
actions.add(parseAnnotatedSetAction((Element) childNode));
}
}
return (AnnotatedAction[])actions.toArray(new AnnotatedAction[actions.size()]);
return (AnnotatedAction[]) actions.toArray(new AnnotatedAction[actions.size()]);
}
private AnnotatedAction parseAnnotatedAction(Element element) {
@@ -759,12 +809,13 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
Parameters parameters = new Parameters();
Iterator it = DomUtils.getChildElementsByTagName(methodArgumentsElement, ARGUMENT_ELEMENT).iterator();
while (it.hasNext()) {
Element argumentElement = (Element)it.next();
Expression name = getLocalFlowServiceLocator().getExpressionParser()
.parseExpression(argumentElement.getAttribute(EXPRESSION_ATTRIBUTE));
Element argumentElement = (Element) it.next();
Expression name = getLocalFlowServiceLocator().getExpressionParser().parseExpression(
argumentElement.getAttribute(EXPRESSION_ATTRIBUTE));
Class type = null;
if (argumentElement.hasAttribute(PARAMETER_TYPE_ATTRIBUTE)) {
type = (Class)fromStringTo(Class.class).execute(argumentElement.getAttribute(PARAMETER_TYPE_ATTRIBUTE));
type = (Class) fromStringTo(Class.class)
.execute(argumentElement.getAttribute(PARAMETER_TYPE_ATTRIBUTE));
}
parameters.add(new Parameter(type, name));
}
@@ -793,8 +844,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private Action parseEvaluateAction(Element element) {
String expressionString = element.getAttribute(EXPRESSION_ATTRIBUTE);
Expression expression = getLocalFlowServiceLocator().getExpressionParser()
.parseExpression(expressionString);
Expression expression = getLocalFlowServiceLocator().getExpressionParser().parseExpression(expressionString);
return new EvaluateAction(expression, parseEvaluationResultExposer(element));
}
@@ -816,15 +866,15 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private Action parseSetAction(Element element) {
String attributeExpressionString = element.getAttribute(ATTRIBUTE_ATTRIBUTE);
SettableExpression attributeExpression = getLocalFlowServiceLocator().getExpressionParser()
.parseSettableExpression(attributeExpressionString);
Expression valueExpression = getLocalFlowServiceLocator().getExpressionParser()
.parseExpression(element.getAttribute(VALUE_ATTRIBUTE));
.parseSettableExpression(attributeExpressionString);
Expression valueExpression = getLocalFlowServiceLocator().getExpressionParser().parseExpression(
element.getAttribute(VALUE_ATTRIBUTE));
return new SetAction(attributeExpression, parseScope(element, ScopeType.REQUEST), valueExpression);
}
private ScopeType parseScope(Element element, ScopeType defaultValue) {
if (element.hasAttribute(SCOPE_ATTRIBUTE) && !element.getAttribute(SCOPE_ATTRIBUTE).equals(DEFAULT_VALUE)) {
return (ScopeType)fromStringTo(ScopeType.class).execute(element.getAttribute(SCOPE_ATTRIBUTE));
return (ScopeType) fromStringTo(ScopeType.class).execute(element.getAttribute(SCOPE_ATTRIBUTE));
}
else {
return defaultValue;
@@ -835,7 +885,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
LocalAttributeMap attributes = new LocalAttributeMap();
List propertyElements = DomUtils.getChildElementsByTagName(element, ATTRIBUTE_ELEMENT);
for (int i = 0; i < propertyElements.size(); i++) {
parseAndSetAttribute((Element)propertyElements.get(i), attributes);
parseAndSetAttribute((Element) propertyElements.get(i), attributes);
}
return attributes;
}
@@ -849,14 +899,14 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
else {
List valueElements = DomUtils.getChildElementsByTagName(element, VALUE_ELEMENT);
Assert.state(valueElements.size() == 1, "A property value should be specified for property '" + name + "'");
value = DomUtils.getTextValue((Element)valueElements.get(0));
value = DomUtils.getTextValue((Element) valueElements.get(0));
}
attributes.put(name, convertPropertyValue(element, value));
}
private Object convertPropertyValue(Element element, String stringValue) {
if (element.hasAttribute(TYPE_ATTRIBUTE)) {
Class targetClass = (Class)fromStringTo(Class.class).execute(element.getAttribute(TYPE_ATTRIBUTE));
Class targetClass = (Class) fromStringTo(Class.class).execute(element.getAttribute(TYPE_ATTRIBUTE));
// convert string value to instance of target class
return fromStringTo(targetClass).execute(stringValue);
}
@@ -869,9 +919,9 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
List transitions = new LinkedList();
List transitionElements = DomUtils.getChildElementsByTagName(element, IF_ELEMENT);
for (Iterator it = transitionElements.iterator(); it.hasNext();) {
transitions.addAll(Arrays.asList(parseIf((Element)it.next())));
transitions.addAll(Arrays.asList(parseIf((Element) it.next())));
}
return (Transition[])transitions.toArray(new Transition[transitions.size()]);
return (Transition[]) transitions.toArray(new Transition[transitions.size()]);
}
private Transition[] parseIf(Element element) {
@@ -886,17 +936,17 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
}
private Transition parseThen(Element element) {
Expression expression = getLocalFlowServiceLocator().getExpressionParser()
.parseExpression(element.getAttribute(TEST_ATTRIBUTE));
Expression expression = getLocalFlowServiceLocator().getExpressionParser().parseExpression(
element.getAttribute(TEST_ATTRIBUTE));
TransitionCriteria matchingCriteria = new BooleanExpressionTransitionCriteria(expression);
TargetStateResolver targetStateResolver = (TargetStateResolver)fromStringTo(TargetStateResolver.class).execute(
element.getAttribute(THEN_ATTRIBUTE));
TargetStateResolver targetStateResolver = (TargetStateResolver) fromStringTo(TargetStateResolver.class)
.execute(element.getAttribute(THEN_ATTRIBUTE));
return getFlowArtifactFactory().createTransition(targetStateResolver, matchingCriteria, null, null);
}
private Transition parseElse(Element element) {
TargetStateResolver targetStateResolver = (TargetStateResolver)fromStringTo(TargetStateResolver.class).execute(
element.getAttribute(ELSE_ATTRIBUTE));
TargetStateResolver targetStateResolver = (TargetStateResolver) fromStringTo(TargetStateResolver.class)
.execute(element.getAttribute(ELSE_ATTRIBUTE));
return getFlowArtifactFactory().createTransition(targetStateResolver, null, null, null);
}
@@ -917,8 +967,8 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
Element mapperElement = getChildElementByTagName(element, INPUT_MAPPER_ELEMENT);
if (mapperElement != null) {
DefaultAttributeMapper mapper = new DefaultAttributeMapper();
parseSimpleAttributeMappings(mapper,
DomUtils.getChildElementsByTagName(mapperElement, INPUT_ATTRIBUTE_ELEMENT));
parseSimpleAttributeMappings(mapper, DomUtils.getChildElementsByTagName(mapperElement,
INPUT_ATTRIBUTE_ELEMENT));
parseMappings(mapper, mapperElement);
return mapper;
}
@@ -931,8 +981,8 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
Element mapperElement = getChildElementByTagName(element, OUTPUT_MAPPER_ELEMENT);
if (mapperElement != null) {
DefaultAttributeMapper mapper = new DefaultAttributeMapper();
parseSimpleAttributeMappings(mapper,
DomUtils.getChildElementsByTagName(mapperElement, OUTPUT_ATTRIBUTE_ELEMENT));
parseSimpleAttributeMappings(mapper, DomUtils.getChildElementsByTagName(mapperElement,
OUTPUT_ATTRIBUTE_ELEMENT));
parseMappings(mapper, mapperElement);
return mapper;
}
@@ -945,15 +995,15 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
ExpressionParser parser = getLocalFlowServiceLocator().getExpressionParser();
List mappingElements = DomUtils.getChildElementsByTagName(element, MAPPING_ELEMENT);
for (Iterator it = mappingElements.iterator(); it.hasNext();) {
Element mappingElement = (Element)it.next();
Element mappingElement = (Element) it.next();
Expression source = parser.parseExpression(mappingElement.getAttribute(SOURCE_ATTRIBUTE));
SettableExpression target = null;
if (StringUtils.hasText(mappingElement.getAttribute(TARGET_ATTRIBUTE))) {
target = parser.parseSettableExpression(mappingElement.getAttribute(TARGET_ATTRIBUTE));
}
else if (StringUtils.hasText(mappingElement.getAttribute(TARGET_COLLECTION_ATTRIBUTE))) {
target = new CollectionAddingExpression(
parser.parseSettableExpression(mappingElement.getAttribute(TARGET_COLLECTION_ATTRIBUTE)));
target = new CollectionAddingExpression(parser.parseSettableExpression(mappingElement
.getAttribute(TARGET_COLLECTION_ATTRIBUTE)));
}
if (getRequired(mappingElement, false)) {
mapper.addMapping(new RequiredMapping(source, target, parseTypeConverter(mappingElement)));
@@ -967,7 +1017,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private void parseSimpleAttributeMappings(DefaultAttributeMapper mapper, List elements) {
ExpressionParser parser = getLocalFlowServiceLocator().getExpressionParser();
for (Iterator it = elements.iterator(); it.hasNext();) {
Element element = (Element)it.next();
Element element = (Element) it.next();
SettableExpression attribute = parser.parseSettableExpression(element.getAttribute(NAME_ATTRIBUTE));
SettableExpression expression = new AttributeExpression(attribute, parseScope(element, ScopeType.FLOW));
if (getRequired(element, false)) {
@@ -981,7 +1031,7 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private boolean getRequired(Element element, boolean defaultValue) {
if (StringUtils.hasText(element.getAttribute(REQUIRED_ATTRIBUTE))) {
return ((Boolean)fromStringTo(Boolean.class).execute(element.getAttribute(REQUIRED_ATTRIBUTE)))
return ((Boolean) fromStringTo(Boolean.class).execute(element.getAttribute(REQUIRED_ATTRIBUTE)))
.booleanValue();
}
else {
@@ -995,8 +1045,8 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
if (StringUtils.hasText(from)) {
if (StringUtils.hasText(to)) {
ConversionService service = getLocalFlowServiceLocator().getConversionService();
Class sourceClass = (Class)fromStringTo(Class.class).execute(from);
Class targetClass = (Class)fromStringTo(Class.class).execute(to);
Class sourceClass = (Class) fromStringTo(Class.class).execute(from);
Class targetClass = (Class) fromStringTo(Class.class).execute(to);
return service.getConversionExecutor(sourceClass, targetClass);
}
else {
@@ -1012,11 +1062,11 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
private FlowExecutionExceptionHandler[] parseExceptionHandlers(Element element) {
FlowExecutionExceptionHandler[] transitionExecutingHandlers = parseTransitionExecutingExceptionHandlers(element);
FlowExecutionExceptionHandler[] customHandlers = parseCustomExceptionHandlers(element);
FlowExecutionExceptionHandler[] exceptionHandlers =
new FlowExecutionExceptionHandler[transitionExecutingHandlers.length + customHandlers.length];
FlowExecutionExceptionHandler[] exceptionHandlers = new FlowExecutionExceptionHandler[transitionExecutingHandlers.length
+ customHandlers.length];
System.arraycopy(transitionExecutingHandlers, 0, exceptionHandlers, 0, transitionExecutingHandlers.length);
System.arraycopy(customHandlers, 0, exceptionHandlers, transitionExecutingHandlers.length,
customHandlers.length);
customHandlers.length);
return exceptionHandlers;
}
@@ -1033,22 +1083,22 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
}
List exceptionHandlers = new LinkedList();
for (Iterator it = transitionElements.iterator(); it.hasNext();) {
Element transitionElement = (Element)it.next();
Element transitionElement = (Element) it.next();
if (StringUtils.hasText(transitionElement.getAttribute(ON_EXCEPTION_ATTRIBUTE))) {
// the "on-exception transitions" are not really transitions but rather
// FlowExecutionExceptionHandlers
exceptionHandlers.add(parseTransitionExecutingExceptionHandler(transitionElement));
}
}
return (FlowExecutionExceptionHandler[])exceptionHandlers
return (FlowExecutionExceptionHandler[]) exceptionHandlers
.toArray(new FlowExecutionExceptionHandler[exceptionHandlers.size()]);
}
private FlowExecutionExceptionHandler parseTransitionExecutingExceptionHandler(Element element) {
TransitionExecutingStateExceptionHandler handler = new TransitionExecutingStateExceptionHandler();
Class exceptionClass = (Class)fromStringTo(Class.class).execute(element.getAttribute(ON_EXCEPTION_ATTRIBUTE));
TargetStateResolver targetStateResolver = (TargetStateResolver)fromStringTo(TargetStateResolver.class).execute(
element.getAttribute(TO_ATTRIBUTE));
Class exceptionClass = (Class) fromStringTo(Class.class).execute(element.getAttribute(ON_EXCEPTION_ATTRIBUTE));
TargetStateResolver targetStateResolver = (TargetStateResolver) fromStringTo(TargetStateResolver.class)
.execute(element.getAttribute(TO_ATTRIBUTE));
handler.add(exceptionClass, targetStateResolver);
handler.getActionList().addAll(parseAnnotatedActions(element));
return handler;
@@ -1058,10 +1108,10 @@ public class XmlFlowBuilder extends BaseFlowBuilder implements ResourceHolder {
List exceptionHandlers = new LinkedList();
List handlerElements = DomUtils.getChildElementsByTagName(element, EXCEPTION_HANDLER_ELEMENT);
for (int i = 0; i < handlerElements.size(); i++) {
Element handlerElement = (Element)handlerElements.get(i);
Element handlerElement = (Element) handlerElements.get(i);
exceptionHandlers.add(parseCustomExceptionHandler(handlerElement));
}
return (FlowExecutionExceptionHandler[])exceptionHandlers
return (FlowExecutionExceptionHandler[]) exceptionHandlers
.toArray(new FlowExecutionExceptionHandler[exceptionHandlers.size()]);
}

View File

@@ -32,9 +32,8 @@ import org.springframework.webflow.execution.factory.StaticFlowExecutionListener
import org.springframework.webflow.test.MockFlowServiceLocator;
/**
* Base class for flow integration tests that verify an externalized flow
* definition executes as expected. Supports caching of the flow definition
* built from an externalized resource to speed up test execution.
* Base class for flow integration tests that verify an externalized flow definition executes as expected. Supports
* caching of the flow definition built from an externalized resource to speed up test execution.
*
* @author Keith Donald
*/
@@ -46,8 +45,8 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
private static FlowDefinition cachedFlowDefinition;
/**
* The flag indicating if the flow definition built from an externalized
* resource as part of this test should be cached.
* The flag indicating if the flow definition built from an externalized resource as part of this test should be
* cached.
*/
private boolean cacheFlowDefinition = false;
@@ -58,7 +57,7 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
public AbstractExternalizedFlowExecutionTests() {
super();
}
/**
* Constructs an externalized flow execution test with given name.
* @param name the name of the test
@@ -69,13 +68,13 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
}
/**
* Internal helper that return the flow execution factory used by the
* test cast to a {@link FlowExecutionImplFactory}.
* Internal helper that return the flow execution factory used by the test cast to a
* {@link FlowExecutionImplFactory}.
*/
private FlowExecutionImplFactory getFlowExecutionImplFactory() {
return (FlowExecutionImplFactory)getFlowExecutionFactory();
return (FlowExecutionImplFactory) getFlowExecutionFactory();
}
/**
* Returns if flow definition caching is turned on.
*/
@@ -84,18 +83,16 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
}
/**
* Sets the flag indicating if the flow definition built from an
* externalized resource as part of this test should be cached.
* Default is false.
* Sets the flag indicating if the flow definition built from an externalized resource as part of this test should
* be cached. Default is false.
*/
protected void setCacheFlowDefinition(boolean cacheFlowDefinition) {
this.cacheFlowDefinition = cacheFlowDefinition;
}
/**
* Sets system attributes to be associated with the flow execution the next
* time one is {@link #startFlow() started} by this test. Useful for
* assigning attributes that influence flow execution behavior.
* Sets system attributes to be associated with the flow execution the next time one is {@link #startFlow() started}
* by this test. Useful for assigning attributes that influence flow execution behavior.
* @param executionAttributes the system attributes to assign
*/
protected void setFlowExecutionAttributes(AttributeMap executionAttributes) {
@@ -103,20 +100,18 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
}
/**
* Set the listener to be attached to the flow execution the next time one
* is {@link #startFlow() started} by this test. Useful for attaching a
* listener that does test assertions during the execution of the flow.
* Set a single listener to be attached to the flow execution the next time one is {@link #startFlow() started} by this
* test. Useful for attaching a listener that does test assertions during the execution of the flow.
* @param executionListener the listener to attach
*/
protected void setFlowExecutionListener(FlowExecutionListener executionListener) {
getFlowExecutionImplFactory().setExecutionListenerLoader(
new StaticFlowExecutionListenerLoader(executionListener));
}
/**
* Set the listeners to be attached to the flow execution the next time one
* is {@link #startFlow() started} by this test. Useful for attaching
* listeners that do test assertions during the execution of the flow.
* Set the listeners to be attached to the flow execution the next time one is {@link #startFlow() started} by this
* test. Useful for attaching listeners that do test assertions during the execution of the flow.
* @param executionListeners the listeners to attach
*/
protected void setFlowExecutionListeners(FlowExecutionListener[] executionListeners) {
@@ -137,12 +132,11 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
}
/**
* Returns the flow artifact factory to use during flow definition
* construction time for accessing externally managed flow artifacts such as
* actions and flows to be used as subflows.
* Returns the flow artifact factory to use during flow definition construction time for accessing externally
* managed flow artifacts such as actions and flows to be used as subflows.
* <p>
* This implementation just creates a {@link MockFlowServiceLocator} and
* populates it with services by calling {@link #registerMockServices(MockFlowServiceLocator)}.
* This implementation just creates a {@link MockFlowServiceLocator} and populates it with services by calling
* {@link #registerMockServices(MockFlowServiceLocator)}.
* @return the flow artifact factory
*/
protected FlowServiceLocator createFlowServiceLocator() {
@@ -152,20 +146,18 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
}
/**
* Template method called by {@link #createFlowServiceLocator()} to allow
* registration of mock implementations of services needed to test the flow
* execution. Useful when testing flow definitions in execution in isolation
* from flows and middle-tier services. Subclasses may override.
* Template method called by {@link #createFlowServiceLocator()} to allow registration of mock implementations of
* services needed to test the flow execution. Useful when testing flow definitions in execution in isolation from
* flows and middle-tier services. Subclasses may override.
* @param serviceRegistry the mock service registry (and locator)
*/
protected void registerMockServices(MockFlowServiceLocator serviceRegistry) {
}
/**
* Factory method to assemble another flow definition from a resource.
* Called by {@link #getFlowDefinition()} to create the "main" flow to test.
* May also be called by subclasses to create subflow definitions whose
* executions should also be exercised by this test.
* Factory method to assemble another flow definition from a resource. Called by {@link #getFlowDefinition()} to
* create the "main" flow to test. May also be called by subclasses to create subflow definitions whose executions
* should also be exercised by this test.
* @param resource the flow definition resource
* @return the built flow definition, ready for execution
* @see #createFlowBuilder(Resource, FlowServiceLocator)
@@ -177,22 +169,26 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
}
/**
* Returns the pointer to the resource that houses the definition of the
* flow to be tested. Subclasses must implement.
* Returns the pointer to the resource that houses the definition of the flow to be tested. Subclasses must
* implement.
* <p>
* Example usage:
* <pre class="code">
* protected FlowDefinitionResource getFlowDefinitionResource() {
* return createFlowDefinitionResource(&quot;/WEB-INF/flows/order-flow.xml&quot;);
* }
* </pre>
* protected FlowDefinitionResource getFlowDefinitionResource() {
* return createFlowDefinitionResource(&quot;/WEB-INF/flows/order-flow.xml&quot;);
* }
* </pre>
* @return the flow definition resource
*/
protected abstract FlowDefinitionResource getFlowDefinitionResource();
/**
* Factory method to create the builder that will build the flow whose
* execution will be tested. Subclasses must override.
* Factory method to create the builder that will build the flow definition whose execution will be tested. Subclasses must
* override.
*
* A subclass may return a builder that sets up mock implementations of services needed locally by the flow
* definition at runtime.
*
* @param resource the externalized flow definition resource location
* @param serviceLocator the flow service locator
* @return the flow builder that will build the flow to be tested
@@ -200,9 +196,8 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
protected abstract FlowBuilder createFlowBuilder(Resource resource, FlowServiceLocator serviceLocator);
/**
* Convenient factory method that creates a {@link FlowDefinitionResource}
* from a file path. Typically called by subclasses overriding
* {@link #getFlowDefinitionResource()}.
* Convenient factory method that creates a {@link FlowDefinitionResource} from a file path. Typically called by
* subclasses overriding {@link #getFlowDefinitionResource()}.
* @param filePath the full path to the externalized flow definition file
* @return the flow definition resource
*/
@@ -211,9 +206,8 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
}
/**
* Convenient factory method that creates a {@link FlowDefinitionResource}
* from a file in a directory. Typically called by subclasses overriding
* {@link #getFlowDefinitionResource()}.
* Convenient factory method that creates a {@link FlowDefinitionResource} from a file in a directory. Typically
* called by subclasses overriding {@link #getFlowDefinitionResource()}.
* @param fileDirectory the directory containing the file
* @param fileName the short file name
* @return the flow definition resource pointing to the file
@@ -223,8 +217,7 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo
}
/**
* Convenient factory method that creates a {@link FlowDefinitionResource}
* from a file.
* Convenient factory method that creates a {@link FlowDefinitionResource} from a file.
* @param file the file
* @return the flow definition resource
*/

View File

@@ -71,7 +71,7 @@ public abstract class AbstractXmlFlowExecutionTests extends AbstractExternalized
super(name);
}
protected final FlowBuilder createFlowBuilder(Resource resource, FlowServiceLocator flowServiceLocator) {
protected FlowBuilder createFlowBuilder(Resource resource, FlowServiceLocator flowServiceLocator) {
return new XmlFlowBuilder(resource, flowServiceLocator);
}
}