diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParser.java index 8bca3c17..27ccb509 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowBuilderServicesBeanDefinitionParser.java @@ -18,39 +18,24 @@ import org.w3c.dom.Element; * * @author Jeremy Grelle */ -public class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { - - private static final String EXPRESSION_PARSER_ATTRIBUTE = "expression-parser"; - - private static final String EXPRESSION_PARSER_PROPERTY = "expressionParser"; - - private static final String VIEW_FACTORY_CREATOR_ATTRIBUTE = "view-factory-creator"; - - private static final String VIEW_FACTORY_CREATOR_PROPERTY = "viewFactoryCreator"; +class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { private static final String CONVERSION_SERVICE_ATTRIBUTE = "conversion-service"; + private static final String EXPRESSION_PARSER_ATTRIBUTE = "expression-parser"; + + private static final String VIEW_FACTORY_CREATOR_ATTRIBUTE = "view-factory-creator"; + private static final String CONVERSION_SERVICE_PROPERTY = "conversionService"; - public static BeanDefinitionHolder registerDefaultBeanDefinition(ParserContext context) { - FlowBuilderServicesBeanDefinitionParser parser = new FlowBuilderServicesBeanDefinitionParser(); - BeanDefinitionBuilder defaultBuilder = BeanDefinitionBuilder.genericBeanDefinition(FlowBuilderServices.class); - defaultBuilder.addPropertyReference(CONVERSION_SERVICE_PROPERTY, parser.createBeanDefinitionForClass( - DefaultConversionService.class, context).getBeanName()); - defaultBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, parser.createBeanDefinitionForClass( - MvcViewFactoryCreator.class, context).getBeanName()); - defaultBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, DefaultExpressionParserFactory - .getExpressionParser()); - BeanDefinitionHolder holder = new BeanDefinitionHolder(defaultBuilder.getBeanDefinition(), - BeanDefinitionReaderUtils.generateBeanName(defaultBuilder.getBeanDefinition(), context.getRegistry())); - parser.registerBeanDefinition(holder, context.getRegistry()); - return holder; - } + private static final String EXPRESSION_PARSER_PROPERTY = "expressionParser"; + + private static final String VIEW_FACTORY_CREATOR_PROPERTY = "viewFactoryCreator"; protected void doParse(Element element, ParserContext context, BeanDefinitionBuilder builder) { + parseConversionService(element, builder, context); parseExpressionParser(element, builder, context); parseViewFactoryCreator(element, builder, context); - parseConversionService(element, builder, context); } private void parseConversionService(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) { @@ -58,18 +43,7 @@ public class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanD if (StringUtils.hasText(conversionService)) { definitionBuilder.addPropertyReference(CONVERSION_SERVICE_PROPERTY, conversionService); } else { - definitionBuilder.addPropertyReference(CONVERSION_SERVICE_PROPERTY, createBeanDefinitionForClass( - DefaultConversionService.class, context).getBeanName()); - } - } - - private void parseViewFactoryCreator(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) { - String viewFactoryCreator = element.getAttribute(VIEW_FACTORY_CREATOR_ATTRIBUTE); - if (StringUtils.hasText(viewFactoryCreator)) { - definitionBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, viewFactoryCreator); - } else { - definitionBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, createBeanDefinitionForClass( - MvcViewFactoryCreator.class, context).getBeanName()); + definitionBuilder.addPropertyValue(CONVERSION_SERVICE_PROPERTY, new DefaultConversionService()); } } @@ -83,6 +57,16 @@ public class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanD } } + private void parseViewFactoryCreator(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) { + String viewFactoryCreator = element.getAttribute(VIEW_FACTORY_CREATOR_ATTRIBUTE); + if (StringUtils.hasText(viewFactoryCreator)) { + definitionBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, viewFactoryCreator); + } else { + definitionBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, createBeanDefinitionForClass( + MvcViewFactoryCreator.class, context).getBeanName()); + } + } + private BeanDefinitionHolder createBeanDefinitionForClass(Class clazz, ParserContext context) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); BeanDefinitionHolder holder = new BeanDefinitionHolder(builder.getBeanDefinition(), BeanDefinitionReaderUtils @@ -95,4 +79,17 @@ public class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanD return FlowBuilderServices.class; } + public static BeanDefinitionHolder registerDefaultFlowBuilderServicesBeanDefinition(ParserContext context) { + FlowBuilderServicesBeanDefinitionParser parser = new FlowBuilderServicesBeanDefinitionParser(); + BeanDefinitionBuilder defaultBuilder = BeanDefinitionBuilder.genericBeanDefinition(FlowBuilderServices.class); + defaultBuilder.addPropertyValue(CONVERSION_SERVICE_PROPERTY, new DefaultConversionService()); + defaultBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, DefaultExpressionParserFactory + .getExpressionParser()); + defaultBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, parser.createBeanDefinitionForClass( + MvcViewFactoryCreator.class, context).getBeanName()); + BeanDefinitionHolder holder = new BeanDefinitionHolder(defaultBuilder.getBeanDefinition(), + BeanDefinitionReaderUtils.generateBeanName(defaultBuilder.getBeanDefinition(), context.getRegistry())); + parser.registerBeanDefinition(holder, context.getRegistry()); + return holder; + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorBeanDefinitionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorBeanDefinitionParser.java index 98f3d9e9..6f3d84b9 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorBeanDefinitionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorBeanDefinitionParser.java @@ -20,9 +20,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.StringUtils; @@ -34,7 +33,7 @@ import org.w3c.dom.Element; * * @author Keith Donald */ -class FlowExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser { +class FlowExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { // elements and attributes @@ -78,15 +77,15 @@ class FlowExecutorBeanDefinitionParser extends AbstractBeanDefinitionParser { private static final String MAX_CONVERSATIONS_PROPERTY = "maxConversations"; - protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { - BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder - .rootBeanDefinition(FlowExecutorFactoryBean.class); - definitionBuilder.setSource(parserContext.extractSource(element)); + protected Class getBeanClass(Element element) { + return FlowExecutorFactoryBean.class; + } + + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder definitionBuilder) { definitionBuilder.addPropertyReference(DEFINITION_LOCATOR_PROPERTY, getRegistryRef(element, parserContext)); definitionBuilder.addPropertyValue(EXECUTION_ATTRIBUTES_PROPERTY, parseAttributes(element)); addExecutionListenerLoader(element, parserContext, definitionBuilder); configureRepository(element, definitionBuilder, parserContext); - return definitionBuilder.getBeanDefinition(); } /** diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParser.java index a92b8752..14b3874a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryBeanDefinitionParser.java @@ -75,7 +75,8 @@ class FlowRegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParse definitionBuilder.addPropertyReference(FLOW_BUILDER_SERVICES_PROPERTY, flowBuilderServices); } else { definitionBuilder.addPropertyReference(FLOW_BUILDER_SERVICES_PROPERTY, - FlowBuilderServicesBeanDefinitionParser.registerDefaultBeanDefinition(parserContext).getBeanName()); + FlowBuilderServicesBeanDefinitionParser.registerDefaultFlowBuilderServicesBeanDefinition( + parserContext).getBeanName()); } definitionBuilder.addPropertyValue(FLOW_LOCATIONS_PROPERTY, parseLocations(element)); definitionBuilder.addPropertyValue(FLOW_BUILDERS_PROPERTY, parseFlowBuilders(element)); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryFactoryBean.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryFactoryBean.java index bbafba2a..b62f1e21 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryFactoryBean.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowRegistryFactoryBean.java @@ -3,15 +3,10 @@ package org.springframework.webflow.config; import java.util.Iterator; import java.util.Set; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.binding.convert.ConversionExecutor; -import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.util.ClassUtils; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.LocalAttributeMap; @@ -37,7 +32,7 @@ import org.springframework.webflow.engine.builder.xml.XmlFlowBuilder; * @author Keith Donald * @author Jeremy Grelle */ -class FlowRegistryFactoryBean implements FactoryBean, ResourceLoaderAware, BeanFactoryAware, InitializingBean { +class FlowRegistryFactoryBean implements FactoryBean, InitializingBean { /** * The definition registry produced by this factory bean. @@ -66,16 +61,6 @@ class FlowRegistryFactoryBean implements FactoryBean, ResourceLoaderAware, BeanF */ private FlowDefinitionResourceFactory flowResourceFactory; - /** - * The container's resource loader. - */ - private ResourceLoader resourceLoader; - - /** - * The containing bean factory this factory bean was deployed in. - */ - private BeanFactory beanFactory; - public void setFlowLocations(FlowLocation[] flowLocations) { this.flowLocations = flowLocations; } @@ -88,16 +73,8 @@ class FlowRegistryFactoryBean implements FactoryBean, ResourceLoaderAware, BeanF this.flowBuilderServices = flowBuilderServices; } - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } - public void afterPropertiesSet() throws Exception { - flowResourceFactory = new FlowDefinitionResourceFactory(resourceLoader); + flowResourceFactory = new FlowDefinitionResourceFactory(flowBuilderServices.getResourceLoader()); flowRegistry = new FlowDefinitionRegistryImpl(); registerFlowLocations(); registerFlowBuilders(); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderContextImpl.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderContextImpl.java index add4358e..471994fb 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderContextImpl.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderContextImpl.java @@ -5,6 +5,7 @@ import org.springframework.binding.convert.ConversionService; import org.springframework.binding.convert.support.GenericConversionService; import org.springframework.binding.expression.ExpressionParser; import org.springframework.core.io.ResourceLoader; +import org.springframework.util.Assert; import org.springframework.webflow.action.BeanInvokingActionFactory; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.definition.registry.FlowDefinitionLocator; @@ -26,7 +27,7 @@ public class FlowBuilderContextImpl implements FlowBuilderContext { private FlowBuilderServices flowBuilderServices; - private GenericConversionService flowConversionService; + private ConversionService conversionService; /** * Creates a new flow builder context. @@ -37,14 +38,14 @@ public class FlowBuilderContextImpl implements FlowBuilderContext { */ public FlowBuilderContextImpl(String flowId, AttributeMap flowAttributes, FlowDefinitionLocator flowDefinitionLocator, FlowBuilderServices flowBuilderServices) { + Assert.hasText(flowId, "The flow id is required"); + Assert.notNull(flowDefinitionLocator, "The flow definition locator is required"); + Assert.notNull(flowBuilderServices, "The flow builder services holder is required"); this.flowId = flowId; this.flowAttributes = flowAttributes; this.flowDefinitionLocator = flowDefinitionLocator; this.flowBuilderServices = flowBuilderServices; - flowConversionService = new GenericConversionService(); - flowConversionService.addConverter(new TextToTransitionCriteria(this)); - flowConversionService.addConverter(new TextToTargetStateResolver(this)); - flowConversionService.setParent(this.flowBuilderServices.getConversionService()); + this.conversionService = createConversionService(); } public FlowBuilderServices getFlowBuilderServices() { @@ -78,7 +79,7 @@ public class FlowBuilderContextImpl implements FlowBuilderContext { } public ConversionService getConversionService() { - return flowConversionService; + return conversionService; } public ResourceLoader getResourceLoader() { @@ -93,4 +94,18 @@ public class FlowBuilderContextImpl implements FlowBuilderContext { return flowDefinitionLocator; } -} + /** + * Factory method that creates the conversion service the flow builder will use. Subclasses may override. The + * default implementation registers Web Flow-specific converters thought to be useful for most builder + * implementations, setting the externally-provided builder services conversion service as its parent. + * @return the flow builder conversion service + */ + protected ConversionService createConversionService() { + GenericConversionService service = new GenericConversionService(); + service.addConverter(new TextToTransitionCriteria(this)); + service.addConverter(new TextToTargetStateResolver(this)); + service.setParent(flowBuilderServices.getConversionService()); + return service; + } + +} \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderServices.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderServices.java index 75eb5537..c5c23faa 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderServices.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/FlowBuilderServices.java @@ -3,6 +3,7 @@ package org.springframework.webflow.engine.builder.support; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.InitializingBean; import org.springframework.binding.convert.ConversionService; import org.springframework.binding.expression.ExpressionParser; import org.springframework.context.ResourceLoaderAware; @@ -17,12 +18,18 @@ import org.springframework.webflow.engine.builder.ViewFactoryCreator; import org.springframework.webflow.execution.Action; /** - * A simple holder for services needed by a flow builder. These services are typically exposed via a Flow Builder's + * A simple holder for configuring the services used by flow builders. These services are exposed to a builder in a * {@link FlowBuilderContext}. * + * Note this class does not attempt to default any service implementations other than the {@link FlowArtifactFactory} + * and {@link BeanInvokingActionFactory}, which are more like builder helper objects than services. It is expected + * clients inject non-null references to concrete service implementations appropriate for their environment. + * + * @see FlowBuilderContextImpl + * * @author Keith Donald */ -public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAware { +public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAware, InitializingBean { /** * The factory encapsulating the creation of central Flow artifacts such as {@link Flow flows} and @@ -46,6 +53,7 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar * The conversion service for converting from one object type to another. */ private ConversionService conversionService; + /** * The parser for parsing expression strings into expression objects. The default is Web Flow's default expression * parser implementation. @@ -67,7 +75,6 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar } public void setFlowArtifactFactory(FlowArtifactFactory flowArtifactFactory) { - Assert.notNull(flowArtifactFactory, "The flow artifact factory is required"); this.flowArtifactFactory = flowArtifactFactory; } @@ -76,7 +83,6 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar } public void setBeanInvokingActionFactory(BeanInvokingActionFactory beanInvokingActionFactory) { - Assert.notNull(beanInvokingActionFactory, "The bean invoking action factory is required"); this.beanInvokingActionFactory = beanInvokingActionFactory; } @@ -85,7 +91,6 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar } public void setViewFactoryCreator(ViewFactoryCreator viewFactoryCreator) { - Assert.notNull("The view factory creator cannot be null"); this.viewFactoryCreator = viewFactoryCreator; } @@ -94,7 +99,6 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar } public void setConversionService(ConversionService conversionService) { - Assert.notNull(conversionService, "The type conversion service cannot be null"); this.conversionService = conversionService; } @@ -103,7 +107,6 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar } public void setExpressionParser(ExpressionParser expressionParser) { - Assert.notNull(expressionParser, "The expression parser cannot be null"); this.expressionParser = expressionParser; } @@ -112,7 +115,6 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar } public void setResourceLoader(ResourceLoader resourceLoader) { - Assert.notNull("The resource loader cannot be null"); this.resourceLoader = resourceLoader; } @@ -121,7 +123,19 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - Assert.notNull("The bean factory cannot be null"); this.beanFactory = beanFactory; } + + // implementing InitializingBean + + public void afterPropertiesSet() throws Exception { + Assert.notNull(flowArtifactFactory, "The flow artifact factory is required"); + Assert.notNull(beanInvokingActionFactory, "The bean invoking action factory is required"); + Assert.notNull(viewFactoryCreator, "The view factory creator is required"); + Assert.notNull(conversionService, "The type conversion service is required"); + Assert.notNull(expressionParser, "The expression parser is required"); + Assert.notNull(resourceLoader, "The resource loader is required"); + Assert.notNull(beanFactory, "The bean factory is required"); + } + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/FlowBuilderSystemDefaults.java b/spring-webflow/src/main/java/org/springframework/webflow/test/FlowBuilderSystemDefaults.java deleted file mode 100644 index 8dfbca0e..00000000 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/FlowBuilderSystemDefaults.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.springframework.webflow.test; - -import org.springframework.beans.factory.support.StaticListableBeanFactory; -import org.springframework.binding.convert.support.DefaultConversionService; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.webflow.action.BeanInvokingActionFactory; -import org.springframework.webflow.engine.builder.FlowArtifactFactory; -import org.springframework.webflow.engine.builder.support.FlowBuilderServices; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; - -class FlowBuilderSystemDefaults { - private FlowBuilderServices defaultServices; - - public FlowBuilderSystemDefaults() { - defaultServices = new FlowBuilderServices(); - defaultServices.setFlowArtifactFactory(new FlowArtifactFactory()); - defaultServices.setBeanInvokingActionFactory(new BeanInvokingActionFactory()); - defaultServices.setViewFactoryCreator(new MockViewFactoryCreator()); - defaultServices.setConversionService(new DefaultConversionService()); - defaultServices.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); - defaultServices.setResourceLoader(new DefaultResourceLoader()); - defaultServices.setBeanFactory(new StaticListableBeanFactory()); - } - - public static FlowBuilderServices get() { - return new FlowBuilderSystemDefaults().createBuilderServices(); - } - - public FlowBuilderServices createBuilderServices() { - FlowBuilderServices builderServices = new FlowBuilderServices(); - applyDefaults(builderServices); - return builderServices; - } - - private void applyDefaults(FlowBuilderServices services) { - services.setFlowArtifactFactory(defaultServices.getFlowArtifactFactory()); - services.setBeanInvokingActionFactory(defaultServices.getBeanInvokingActionFactory()); - services.setViewFactoryCreator(defaultServices.getViewFactoryCreator()); - services.setConversionService(defaultServices.getConversionService()); - services.setExpressionParser(defaultServices.getExpressionParser()); - services.setResourceLoader(defaultServices.getResourceLoader()); - services.setBeanFactory(defaultServices.getBeanFactory()); - } -} \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/MockFlowBuilderContext.java b/spring-webflow/src/main/java/org/springframework/webflow/test/MockFlowBuilderContext.java index a3f1f514..84fcfe4c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/MockFlowBuilderContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/MockFlowBuilderContext.java @@ -49,7 +49,7 @@ public class MockFlowBuilderContext extends FlowBuilderContextImpl { * Creates a new mock flow service locator. */ public MockFlowBuilderContext(String flowId, AttributeMap attributes) { - super(flowId, attributes, new FlowDefinitionRegistryImpl(), FlowBuilderSystemDefaults.get()); + super(flowId, attributes, new FlowDefinitionRegistryImpl(), TestFlowBuilderServicesFactory.getServices()); } /** diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/TestFlowBuilderServicesFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/test/TestFlowBuilderServicesFactory.java new file mode 100644 index 00000000..51145bb8 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/TestFlowBuilderServicesFactory.java @@ -0,0 +1,32 @@ +package org.springframework.webflow.test; + +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.binding.convert.support.DefaultConversionService; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.webflow.engine.builder.support.FlowBuilderServices; +import org.springframework.webflow.expression.DefaultExpressionParserFactory; + +/** + * Factory that encapsulates configuration of default flow builder services for a test environment. + * @author Keith Donald + */ +public class TestFlowBuilderServicesFactory { + private static FlowBuilderServices services; + + private TestFlowBuilderServicesFactory() { + } + + public static FlowBuilderServices getServices() { + if (services != null) { + return services; + } else { + services = new FlowBuilderServices(); + services.setViewFactoryCreator(new MockViewFactoryCreator()); + services.setConversionService(new DefaultConversionService()); + services.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); + services.setResourceLoader(new DefaultResourceLoader()); + services.setBeanFactory(new StaticListableBeanFactory()); + return services; + } + } +} \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractExternalizedFlowExecutionTests.java b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractExternalizedFlowExecutionTests.java index 027e028d..0c602bed 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractExternalizedFlowExecutionTests.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractExternalizedFlowExecutionTests.java @@ -23,7 +23,6 @@ import org.springframework.webflow.definition.FlowDefinition; import org.springframework.webflow.engine.Flow; import org.springframework.webflow.engine.builder.FlowAssembler; import org.springframework.webflow.engine.builder.FlowBuilder; -import org.springframework.webflow.engine.builder.FlowBuilderContext; import org.springframework.webflow.engine.impl.FlowExecutionImplFactory; import org.springframework.webflow.execution.FlowExecutionListener; import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader; @@ -144,34 +143,24 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo */ protected final Flow buildFlow() { FlowDefinitionResource resource = getResource(resourceFactory); - FlowBuilderContext builderContext = createFlowBuilderContext(resource); + MockFlowBuilderContext builderContext = new MockFlowBuilderContext(resource.getId(), resource.getAttributes()); + configureFlowBuilderContext(builderContext); FlowBuilder builder = createFlowBuilder(resource.getPath()); FlowAssembler assembler = new FlowAssembler(builder, builderContext); return assembler.assembleFlow(); } - /** - * Create the flow builder context to build the flow definition at the resource location provided. - * @param resource the flow definition resource - * @return the flow builder context - */ - protected FlowBuilderContext createFlowBuilderContext(FlowDefinitionResource resource) { - MockFlowBuilderContext builderContext = new MockFlowBuilderContext(resource.getId(), resource.getAttributes()); - configure(builderContext); - return builderContext; - } - /** * Subclasses may override this hook to customize the builder context for the flow being tested. Useful for - * registering mock subflows or other builder services. - * @param builderContext the mock flow builder context. + * registering mock subflows or other builder services. By default, this method does nothing. + * @param builderContext the mock flow builder context to configure */ - protected void configure(MockFlowBuilderContext builderContext) { + protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) { } /** - * Get the flow definition to be tested. + * Get the resource defining the flow to be tested. * @param resourceFactory a helper for constructing the resource to be tested * @return the flow definition resource */ diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractXmlFlowExecutionTests.java b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractXmlFlowExecutionTests.java index 2c55af19..576d3f94 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractXmlFlowExecutionTests.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractXmlFlowExecutionTests.java @@ -28,24 +28,20 @@ import org.springframework.webflow.engine.builder.xml.XmlFlowBuilder; *
  * public class SearchFlowExecutionTests extends AbstractXmlFlowExecutionTests {
  * 
- * 	protected FlowDefinitionResource getFlowDefinitionResource() {
- * 		return createFlowDefinitionResource("src/main/webapp/WEB-INF/flows/search-flow.xml");
+ * 	protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) {
+ * 		return resourceFactory.createClassPathResource("search-flow.xml", getClass());
  * 	}
  * 
  * 	public void testStartFlow() {
- * 		startFlow();
- * 		assertCurrentStateEquals("displaySearchCriteria");
+ * 		ExternalContext context = new MockExternalContext();
+ * 		startFlow(context);
+ * 		assertCurrentStateEquals("enterSearchCriteria");
  * 	}
  * 
- * 	public void testDisplayCriteriaSubmitSuccess() {
- * 		startFlow();
- * 		MockParameterMap parameters = new MockParameterMap();
- * 		parameters.put("firstName", "Keith");
- * 		parameters.put("lastName", "Donald");
- * 		ViewSelection view = signalEvent("search", parameters);
- * 		assertCurrentStateEquals("displaySearchResults");
- * 		assertModelAttributeCollectionSize(1, "results", view);
+ * 	protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) {
+ * 		builderContext.registerBean("searchService", new TestSearchService());
  * 	}
+ * 
  * }
  * 
* @@ -80,8 +76,8 @@ public abstract class AbstractXmlFlowExecutionTests extends AbstractExternalized /** * Template method subclasses may override to register mock implementations of services used locally by the flow - * being tested. - * @param flowBeanFactory the local flow service registry; register mock services with it using + * being tested. By default, this method does nothing. + * @param flowBeanFactory the local flow bean factory, you may register mock services with it using * {@link ConfigurableBeanFactory#registerSingleton(String, Object)} */ protected void registerMockFlowBeans(ConfigurableBeanFactory flowBeanFactory) { diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/FlowExecutorBeanDefinitionParserTests.java b/spring-webflow/src/test/java/org/springframework/webflow/config/FlowExecutorBeanDefinitionParserTests.java index 51bf66a2..3005a534 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/config/FlowExecutorBeanDefinitionParserTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/FlowExecutorBeanDefinitionParserTests.java @@ -7,19 +7,16 @@ import org.springframework.webflow.definition.FlowDefinition; import org.springframework.webflow.execution.FlowExecutionListenerAdapter; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.executor.FlowExecutor; -import org.springframework.webflow.test.MockExternalContext; public class FlowExecutorBeanDefinitionParserTests extends TestCase { private ClassPathXmlApplicationContext context; - private FlowExecutor executor; public void setUp() { context = new ClassPathXmlApplicationContext("org/springframework/webflow/config/flow-executor.xml"); - executor = (FlowExecutor) context.getBean("flowExecutor"); } - public void testExecute() { - MockExternalContext context = new MockExternalContext(); + public void testConfigOk() { + context.getBean("flowExecutor", FlowExecutor.class); } public static class ConfigurationListener extends FlowExecutionListenerAdapter { diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/FlowRegistryFactoryBeanTests.java b/spring-webflow/src/test/java/org/springframework/webflow/config/FlowRegistryFactoryBeanTests.java index 6159cb91..abb7a38a 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/config/FlowRegistryFactoryBeanTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/FlowRegistryFactoryBeanTests.java @@ -4,12 +4,9 @@ import java.util.HashSet; import junit.framework.TestCase; -import org.springframework.beans.factory.support.StaticListableBeanFactory; -import org.springframework.binding.convert.support.DefaultConversionService; -import org.springframework.core.io.DefaultResourceLoader; import org.springframework.webflow.definition.FlowDefinition; import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; -import org.springframework.webflow.engine.builder.support.FlowBuilderServices; +import org.springframework.webflow.test.TestFlowBuilderServicesFactory; public class FlowRegistryFactoryBeanTests extends TestCase { private FlowRegistryFactoryBean factoryBean; @@ -25,12 +22,8 @@ public class FlowRegistryFactoryBeanTests extends TestCase { FlowLocation location1 = new FlowLocation("flow1", "org/springframework/webflow/config/flow.xml", attributes); FlowLocation location2 = new FlowLocation("flow2", "org/springframework/webflow/config/flow.xml", attributes); FlowLocation[] flowLocations = new FlowLocation[] { location1, location2 }; - FlowBuilderServices builderServices = new FlowBuilderServices(); - builderServices.setConversionService(new DefaultConversionService()); - factoryBean.setFlowBuilderServices(builderServices); + factoryBean.setFlowBuilderServices(TestFlowBuilderServicesFactory.getServices()); factoryBean.setFlowLocations(flowLocations); - factoryBean.setResourceLoader(new DefaultResourceLoader()); - factoryBean.setBeanFactory(new StaticListableBeanFactory()); factoryBean.afterPropertiesSet(); FlowDefinitionRegistry registry = (FlowDefinitionRegistry) factoryBean.getObject(); FlowDefinition def = registry.getFlowDefinition("flow1"); @@ -46,11 +39,8 @@ public class FlowRegistryFactoryBeanTests extends TestCase { public void testGetFlowRegistryGeneratedFlowId() throws Exception { FlowLocation location1 = new FlowLocation(null, "org/springframework/webflow/config/flow.xml", null); FlowLocation[] flowLocations = new FlowLocation[] { location1 }; - FlowBuilderServices builderServices = new FlowBuilderServices(); - factoryBean.setFlowBuilderServices(builderServices); + factoryBean.setFlowBuilderServices(TestFlowBuilderServicesFactory.getServices()); factoryBean.setFlowLocations(flowLocations); - factoryBean.setResourceLoader(new DefaultResourceLoader()); - factoryBean.setBeanFactory(new StaticListableBeanFactory()); factoryBean.afterPropertiesSet(); FlowDefinitionRegistry registry = (FlowDefinitionRegistry) factoryBean.getObject(); FlowDefinition def = registry.getFlowDefinition("flow"); @@ -63,10 +53,7 @@ public class FlowRegistryFactoryBeanTests extends TestCase { FlowLocation location1 = new FlowLocation(null, "org/springframework/webflow/config/flow.xml", null); FlowLocation[] flowLocations = new FlowLocation[] { location1 }; factoryBean.setFlowLocations(flowLocations); - FlowBuilderServices builderServices = new FlowBuilderServices(); - factoryBean.setFlowBuilderServices(builderServices); - factoryBean.setResourceLoader(new DefaultResourceLoader()); - factoryBean.setBeanFactory(new StaticListableBeanFactory()); + factoryBean.setFlowBuilderServices(TestFlowBuilderServicesFactory.getServices()); factoryBean.afterPropertiesSet(); FlowDefinitionRegistry registry = (FlowDefinitionRegistry) factoryBean.getObject(); FlowDefinition def = registry.getFlowDefinition("flow"); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/flow-executor.xml b/spring-webflow/src/test/java/org/springframework/webflow/config/flow-executor.xml index 384ddbdd..1a30899a 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/config/flow-executor.xml +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/flow-executor.xml @@ -1,31 +1,29 @@ - - - - - - - - - - - + + + + + + + + + + + - - - - - + + + \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java b/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java index 261d3551..8f9c9338 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java @@ -67,7 +67,7 @@ public class SearchFlowExecutionTests extends AbstractXmlFlowExecutionTests { assertCurrentStateEquals("displayResults"); } - protected void configure(MockFlowBuilderContext builderContext) { + protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) { builderContext.getFlowBuilderServices().setExpressionParser(new WebFlowELExpressionParser()); Flow mockDetailFlow = new Flow("detail-flow"); mockDetailFlow.setInputMapper(new AttributeMapper() {