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 e3e2cc12..8bca3c17 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 @@ -1,10 +1,15 @@ package org.springframework.webflow.config; +import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.binding.convert.support.DefaultConversionService; import org.springframework.util.StringUtils; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; +import org.springframework.webflow.expression.DefaultExpressionParserFactory; import org.springframework.webflow.mvc.MvcViewFactoryCreator; import org.w3c.dom.Element; @@ -27,37 +32,67 @@ public class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanD private static final String CONVERSION_SERVICE_PROPERTY = "conversionService"; - protected Class getBeanClass(Element element) { - return FlowBuilderServices.class; + 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; } - protected void doParse(Element element, BeanDefinitionBuilder definitionBuilder) { - parseExpressionParser(element, definitionBuilder); - parseViewFactoryCreator(element, definitionBuilder); - parseConversionService(element, definitionBuilder); + protected void doParse(Element element, ParserContext context, BeanDefinitionBuilder builder) { + parseExpressionParser(element, builder, context); + parseViewFactoryCreator(element, builder, context); + parseConversionService(element, builder, context); } - private void parseConversionService(Element element, BeanDefinitionBuilder definitionBuilder) { + private void parseConversionService(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) { String conversionService = element.getAttribute(CONVERSION_SERVICE_ATTRIBUTE); 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) { + 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.addPropertyValue(VIEW_FACTORY_CREATOR_PROPERTY, new MvcViewFactoryCreator()); + definitionBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, createBeanDefinitionForClass( + MvcViewFactoryCreator.class, context).getBeanName()); } } - private void parseExpressionParser(Element element, BeanDefinitionBuilder definitionBuilder) { + private void parseExpressionParser(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) { String expressionParser = element.getAttribute(EXPRESSION_PARSER_ATTRIBUTE); if (StringUtils.hasText(expressionParser)) { definitionBuilder.addPropertyReference(EXPRESSION_PARSER_PROPERTY, expressionParser); + } else { + definitionBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, DefaultExpressionParserFactory + .getExpressionParser()); } } + private BeanDefinitionHolder createBeanDefinitionForClass(Class clazz, ParserContext context) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); + BeanDefinitionHolder holder = new BeanDefinitionHolder(builder.getBeanDefinition(), BeanDefinitionReaderUtils + .generateBeanName(builder.getBeanDefinition(), context.getRegistry())); + registerBeanDefinition(holder, context.getRegistry()); + return holder; + } + + protected Class getBeanClass(Element element) { + return FlowBuilderServices.class; + } + } 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 868ca2d9..a92b8752 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 @@ -25,6 +25,7 @@ import java.util.Set; import org.springframework.beans.factory.support.BeanDefinitionBuilder; 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; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; @@ -68,10 +69,13 @@ class FlowRegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParse return FlowRegistryFactoryBean.class; } - protected void doParse(Element element, BeanDefinitionBuilder definitionBuilder) { + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder definitionBuilder) { String flowBuilderServices = getFlowBuilderServicesAttribute(element); if (StringUtils.hasText(flowBuilderServices)) { definitionBuilder.addPropertyReference(FLOW_BUILDER_SERVICES_PROPERTY, flowBuilderServices); + } else { + definitionBuilder.addPropertyReference(FLOW_BUILDER_SERVICES_PROPERTY, + FlowBuilderServicesBeanDefinitionParser.registerDefaultBeanDefinition(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 4c46c278..bbafba2a 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 @@ -28,7 +28,6 @@ import org.springframework.webflow.engine.builder.RefreshableFlowDefinitionHolde import org.springframework.webflow.engine.builder.support.FlowBuilderContextImpl; import org.springframework.webflow.engine.builder.support.FlowBuilderServices; import org.springframework.webflow.engine.builder.xml.XmlFlowBuilder; -import org.springframework.webflow.mvc.MvcViewFactoryCreator; /** * A factory for a flow definition registry. Is a Spring FactoryBean, for provision by the flow definition registry bean @@ -98,9 +97,6 @@ class FlowRegistryFactoryBean implements FactoryBean, ResourceLoaderAware, BeanF } public void afterPropertiesSet() throws Exception { - if (flowBuilderServices == null) { - initFlowBuilderServices(); - } flowResourceFactory = new FlowDefinitionResourceFactory(resourceLoader); flowRegistry = new FlowDefinitionRegistryImpl(); registerFlowLocations(); @@ -204,10 +200,4 @@ class FlowRegistryFactoryBean implements FactoryBean, ResourceLoaderAware, BeanF } } - private void initFlowBuilderServices() { - flowBuilderServices = new FlowBuilderServices(); - flowBuilderServices.setResourceLoader(resourceLoader); - flowBuilderServices.setBeanFactory(beanFactory); - flowBuilderServices.setViewFactoryCreator(new MvcViewFactoryCreator()); - } } \ 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 6ea6cae2..75eb5537 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 @@ -4,7 +4,6 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.binding.convert.ConversionService; -import org.springframework.binding.convert.support.DefaultConversionService; import org.springframework.binding.expression.ExpressionParser; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.ResourceLoader; @@ -16,7 +15,6 @@ import org.springframework.webflow.engine.builder.FlowArtifactFactory; import org.springframework.webflow.engine.builder.FlowBuilderContext; import org.springframework.webflow.engine.builder.ViewFactoryCreator; import org.springframework.webflow.execution.Action; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; /** * A simple holder for services needed by a flow builder. These services are typically exposed via a Flow Builder's @@ -47,13 +45,12 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar /** * The conversion service for converting from one object type to another. */ - private ConversionService conversionService = new DefaultConversionService(); - + private ConversionService conversionService; /** * The parser for parsing expression strings into expression objects. The default is Web Flow's default expression * parser implementation. */ - private ExpressionParser expressionParser = DefaultExpressionParserFactory.getExpressionParser(); + private ExpressionParser expressionParser; /** * A resource loader that can load resources. diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/SpringBeanWebFlowELResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/SpringBeanWebFlowELResolver.java index bfb19b0e..741d10ef 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/SpringBeanWebFlowELResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/SpringBeanWebFlowELResolver.java @@ -1,7 +1,6 @@ package org.springframework.webflow.expression.el; import javax.el.ELContext; -import javax.el.ELException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.access.el.SpringBeanELResolver; @@ -17,36 +16,6 @@ public class SpringBeanWebFlowELResolver extends SpringBeanELResolver { private static final BeanFactory EMPTY_BEAN_FACTORY = new StaticListableBeanFactory(); - public Class getType(ELContext elContext, Object base, Object property) throws ELException { - if (base != null && base instanceof RequestContext) { - return super.getType(elContext, null, property); - } else { - return null; - } - } - - public Object getValue(ELContext elContext, Object base, Object property) throws ELException { - if (base != null && base instanceof RequestContext) { - return super.getValue(elContext, null, property); - } else { - return null; - } - } - - public boolean isReadOnly(ELContext elContext, Object base, Object property) throws ELException { - if (base != null && base instanceof RequestContext) { - return super.isReadOnly(elContext, null, property); - } else { - return false; - } - } - - public void setValue(ELContext elContext, Object base, Object property, Object value) throws ELException { - if (base != null && base instanceof RequestContext) { - super.setValue(elContext, null, property, value); - } - } - protected BeanFactory getBeanFactory(ELContext elContext) { RequestContext rc = RequestContextHolder.getRequestContext(); if (rc.getActiveFlow().getBeanFactory() != null) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java index dade2a40..920fbf11 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java @@ -44,10 +44,11 @@ public class WebFlowELExpressionParser extends ELExpressionParser { public ELContext getELContext(Object target) { List customResolvers = new ArrayList(); customResolvers.add(new RequestContextELResolver()); + customResolvers.add(new WebFlowImplicitObjectELResolver()); customResolvers.add(new SpringBeanWebFlowELResolver()); customResolvers.add(new ActionMethodELResolver()); customResolvers.add(new ScopeSearchingELResolver()); - ELResolver resolver = new DefaultELResolver(target, customResolvers); + ELResolver resolver = new DefaultELResolver(null, customResolvers); return new WebFlowELContext(resolver); } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowImplicitObjectELResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowImplicitObjectELResolver.java new file mode 100644 index 00000000..824faa45 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowImplicitObjectELResolver.java @@ -0,0 +1,75 @@ +package org.springframework.webflow.expression.el; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.el.BeanELResolver; +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.PropertyNotWritableException; + +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.RequestContextHolder; + +public class WebFlowImplicitObjectELResolver extends ELResolver { + + public Class getCommonPropertyType(ELContext context, Object base) { + return Object.class; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + return null; + } + + public Class getType(ELContext context, Object base, Object property) { + if (base == null && RequestContextHolder.getRequestContext() == null && ImplicitVariable.matches(property)) { + return ImplicitVariable.value(context, RequestContextHolder.getRequestContext(), property).getClass(); + } + return null; + } + + public Object getValue(ELContext context, Object base, Object property) { + if (base == null && RequestContextHolder.getRequestContext() == null && ImplicitVariable.matches(property)) { + return ImplicitVariable.value(context, RequestContextHolder.getRequestContext(), property); + } + return null; + } + + public boolean isReadOnly(ELContext context, Object base, Object property) { + if (base == null && RequestContextHolder.getRequestContext() == null && ImplicitVariable.matches(property)) { + context.setPropertyResolved(true); + return true; + } + return false; + } + + public void setValue(ELContext context, Object base, Object property, Object value) { + if (base == null && RequestContextHolder.getRequestContext() == null && ImplicitVariable.matches(property)) { + context.setPropertyResolved(true); + throw new PropertyNotWritableException("The implicit flow variable " + property + " is not writable."); + } + } + + private static final class ImplicitVariable { + private static final Set vars = new HashSet(); + + static { + vars.add("requestScope"); + vars.add("flashScope"); + vars.add("flowScope"); + vars.add("conversationScope"); + vars.add("requestParameters"); + } + + private static final BeanELResolver internalResolver = new BeanELResolver(); + + public static boolean matches(Object property) { + return vars.contains(property); + } + + public static Object value(ELContext elContext, RequestContext requestContext, Object property) { + return internalResolver.getValue(elContext, requestContext, property); + }; + } +} 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 5699a367..6159cb91 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 @@ -5,6 +5,7 @@ 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; @@ -24,6 +25,9 @@ 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.setFlowLocations(flowLocations); factoryBean.setResourceLoader(new DefaultResourceLoader()); factoryBean.setBeanFactory(new StaticListableBeanFactory()); @@ -42,6 +46,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.setFlowLocations(flowLocations); factoryBean.setResourceLoader(new DefaultResourceLoader()); factoryBean.setBeanFactory(new StaticListableBeanFactory()); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/config/flow-registry.xml b/spring-webflow/src/test/java/org/springframework/webflow/config/flow-registry.xml index 11a0cbac..92f5d8b7 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/config/flow-registry.xml +++ b/spring-webflow/src/test/java/org/springframework/webflow/config/flow-registry.xml @@ -8,7 +8,7 @@ http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd"> - + @@ -26,6 +26,4 @@ - - \ No newline at end of file