EL simplification and config enhancements

This commit is contained in:
Jeremy Grelle
2008-03-04 23:39:38 +00:00
parent 2c8e8a3569
commit b828ada0e7
9 changed files with 136 additions and 61 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,7 +8,7 @@
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
<web:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<web:flow-registry id="flowRegistry">
<web:flow-location id="flow" path="org/springframework/webflow/config/flow.xml">
<web:flow-definition-attributes>
<web:attribute name="foo" value="bar" />
@@ -26,6 +26,4 @@
</web:flow-builder>
</web:flow-registry>
<bean id="flowBuilderServices" class="org.springframework.webflow.engine.builder.support.FlowBuilderServices" />
</beans>