diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/expression/WebFlowOgnlExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/core/expression/WebFlowOgnlExpressionParser.java index 6cae838d..4244dad4 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/expression/WebFlowOgnlExpressionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/expression/WebFlowOgnlExpressionParser.java @@ -17,12 +17,14 @@ package org.springframework.webflow.core.expression; import java.util.Map; +import ognl.ObjectPropertyAccessor; import ognl.OgnlException; import ognl.PropertyAccessor; import org.springframework.binding.collection.MapAdaptable; import org.springframework.binding.expression.ognl.OgnlExpressionParser; import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.execution.RequestContext; /** * An extension of {@link OgnlExpressionParser} that registers web flow specific property accessors. @@ -35,6 +37,7 @@ class WebFlowOgnlExpressionParser extends OgnlExpressionParser { * Creates a webflow-specific ognl expression parser. */ public WebFlowOgnlExpressionParser() { + addPropertyAccessor(RequestContext.class, new RequestContextPropertyAccessor(new ObjectPropertyAccessor())); addPropertyAccessor(MapAdaptable.class, new MapAdaptablePropertyAccessor()); addPropertyAccessor(MutableAttributeMap.class, new MutableAttributeMapPropertyAccessor()); } @@ -65,4 +68,33 @@ class WebFlowOgnlExpressionParser extends OgnlExpressionParser { ((MutableAttributeMap) target).put((String) name, value); } } + + private static class RequestContextPropertyAccessor implements PropertyAccessor { + private PropertyAccessor delegate; + + public RequestContextPropertyAccessor(PropertyAccessor delegate) { + this.delegate = delegate; + } + + public Object getProperty(Map context, Object target, Object name) throws OgnlException { + String property = name.toString(); + RequestContext requestContext = (RequestContext) target; + if (requestContext.getRequestScope().contains(property)) { + return requestContext.getRequestScope().get(property); + } else if (requestContext.getFlashScope().contains(property)) { + return requestContext.getFlashScope().get(property); + } else if (requestContext.getFlowScope().contains(property)) { + return requestContext.getFlowScope().get(property); + } else if (requestContext.getConversationScope().contains(property)) { + return requestContext.getConversationScope().get(property); + } else { + return delegate.getProperty(context, target, name); + } + } + + public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException { + delegate.setProperty(context, target, name, value); + } + + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolver.java index 0ca991fc..a2f504f2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolver.java @@ -71,13 +71,11 @@ class TextToTargetStateResolver extends AbstractConverter { protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception { String targetStateId = (String) source; ExpressionParser parser = flowBuilderContext.getExpressionParser(); - if (parser.isEvalExpressionString(targetStateId)) { - Expression expression = parser.parseExpression(targetStateId, RequestContext.class, String.class, null); - return new DefaultTargetStateResolver(expression); - } else if (targetStateId.startsWith(BEAN_PREFIX)) { + if (targetStateId.startsWith(BEAN_PREFIX)) { return flowBuilderContext.getBeanFactory().getBean(targetStateId.substring(BEAN_PREFIX.length())); } else { - return new DefaultTargetStateResolver(targetStateId); + Expression expression = parser.parseExpression(targetStateId, RequestContext.class, String.class, null); + return new DefaultTargetStateResolver(expression); } } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteria.java index d6c198c9..406b4c5e 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteria.java @@ -78,6 +78,7 @@ class TextToTransitionCriteria extends AbstractConverter { } protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception { + // TODO - add separate transition 'event' and 'condition' attributes String encodedCriteria = (String) source; ExpressionParser parser = flowBuilderContext.getExpressionParser(); if (!StringUtils.hasText(encodedCriteria) diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java index 4e5219ef..4ed8e13a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java @@ -51,7 +51,6 @@ 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.web.context.support.ServletContextResource; import org.springframework.webflow.action.ActionResultExposer; import org.springframework.webflow.action.EvaluateAction; import org.springframework.webflow.action.ExternalRedirectAction; @@ -603,8 +602,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde String encodedViewName = encodedView.substring(REDIRECT_PREFIX.length()); Expression viewName = getExpressionParser().parseExpression(encodedViewName, RequestContext.class, String.class, null); - Expression viewResource = new ViewResourceExpression(viewName, getLocalContext().getResourceLoader()); - ViewFactory viewFactory = getLocalContext().getViewFactoryCreator().createViewFactory(viewResource, + ViewFactory viewFactory = getLocalContext().getViewFactoryCreator().createViewFactory(viewName, getLocalContext().getResourceLoader()); return new ViewInfo(viewFactory, Boolean.TRUE); } else if (encodedView.startsWith(EXTERNAL_REDIRECT_PREFIX)) { @@ -624,8 +622,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } else { Expression viewName = getExpressionParser().parseExpression(encodedView, RequestContext.class, String.class, null); - Expression viewResource = new ViewResourceExpression(viewName, getLocalContext().getResourceLoader()); - ViewFactory viewFactory = getLocalContext().getViewFactoryCreator().createViewFactory(viewResource, + ViewFactory viewFactory = getLocalContext().getViewFactoryCreator().createViewFactory(viewName, getLocalContext().getResourceLoader()); return new ViewInfo(viewFactory, null); } @@ -650,8 +647,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } else { Expression viewName = getExpressionParser().parseExpression(encodedView, RequestContext.class, String.class, null); - Expression viewResource = new ViewResourceExpression(viewName, getLocalContext().getResourceLoader()); - return getLocalContext().getViewFactoryCreator().createFinalResponseAction(viewResource, + return getLocalContext().getViewFactoryCreator().createFinalResponseAction(viewName, getLocalContext().getResourceLoader()); } } @@ -774,9 +770,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde ExpressionParser parser = getLocalContext().getExpressionParser(); while (it.hasNext()) { Element argumentElement = (Element) it.next(); - String expressionString = parser.parseEvalExpressionString(argumentElement - .getAttribute(EXPRESSION_ATTRIBUTE)); - Expression name = parser.parseExpression(expressionString, RequestContext.class, Object.class, null); + Expression name = parser.parseExpression(argumentElement.getAttribute(EXPRESSION_ATTRIBUTE), + RequestContext.class, Object.class, null); Class type = null; if (argumentElement.hasAttribute(PARAMETER_TYPE_ATTRIBUTE)) { type = (Class) fromStringTo(Class.class) @@ -807,10 +802,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } private Action parseEvaluateAction(Element element) { - String expressionString = getExpressionParser().parseEvalExpressionString( - element.getAttribute(EXPRESSION_ATTRIBUTE)); - Expression expression = getExpressionParser().parseExpression(expressionString, RequestContext.class, - Object.class, null); + Expression expression = getExpressionParser().parseExpression(element.getAttribute(EXPRESSION_ATTRIBUTE), + RequestContext.class, Object.class, null); return new EvaluateAction(expression, parseEvaluationResultExposer(element)); } @@ -900,9 +893,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } private Transition parseThen(Element element) { - String expressionString = getExpressionParser().parseEvalExpressionString(element.getAttribute(TEST_ATTRIBUTE)); - Expression expression = getExpressionParser().parseExpression(expressionString, RequestContext.class, - Boolean.class, null); + Expression expression = getExpressionParser().parseExpression(element.getAttribute(TEST_ATTRIBUTE), + RequestContext.class, Boolean.class, null); TransitionCriteria matchingCriteria = new BooleanExpressionTransitionCriteria(expression); TargetStateResolver targetStateResolver = (TargetStateResolver) fromStringTo(TargetStateResolver.class) .execute(element.getAttribute(THEN_ATTRIBUTE)); @@ -959,16 +951,15 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde List mappingElements = DomUtils.getChildElementsByTagName(element, MAPPING_ELEMENT); for (Iterator it = mappingElements.iterator(); it.hasNext();) { Element mappingElement = (Element) it.next(); - Expression source = parser.parseExpression(parser.parseEvalExpressionString(mappingElement - .getAttribute(SOURCE_ATTRIBUTE)), sourceClass, Object.class, null); + Expression source = parser.parseExpression(mappingElement.getAttribute(SOURCE_ATTRIBUTE), sourceClass, + Object.class, null); Expression target = null; if (StringUtils.hasText(mappingElement.getAttribute(TARGET_ATTRIBUTE))) { - target = parser.parseExpression(parser.parseEvalExpressionString(mappingElement - .getAttribute(TARGET_ATTRIBUTE)), targetClass, Object.class, null); + target = parser.parseExpression(mappingElement.getAttribute(TARGET_ATTRIBUTE), targetClass, + Object.class, null); } else if (StringUtils.hasText(mappingElement.getAttribute(TARGET_COLLECTION_ATTRIBUTE))) { - target = new CollectionAddingExpression(parser.parseExpression(parser - .parseEvalExpressionString(mappingElement.getAttribute(TARGET_COLLECTION_ATTRIBUTE)), - targetClass, Object.class, null)); + target = new CollectionAddingExpression(parser.parseExpression(mappingElement + .getAttribute(TARGET_COLLECTION_ATTRIBUTE), targetClass, Object.class, null)); } if (getRequired(mappingElement, false)) { mapper.addMapping(new RequiredMapping(source, target, parseTypeConverter(mappingElement))); @@ -982,9 +973,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde ExpressionParser parser = getLocalContext().getExpressionParser(); for (Iterator it = elements.iterator(); it.hasNext();) { Element element = (Element) it.next(); - String expressionString = parser.parseEvalExpressionString(element.getAttribute(NAME_ATTRIBUTE)); - Expression attributeExpression = parser.parseExpression(expressionString, MutableAttributeMap.class, - Object.class, null); + Expression attributeExpression = parser.parseExpression(element.getAttribute(NAME_ATTRIBUTE), + MutableAttributeMap.class, Object.class, null); Expression scopedAttributeExpression = new ScopedAttributeExpression(attributeExpression, parseScope( element, ScopeType.FLOW)); if (getRequired(element, false)) { @@ -999,9 +989,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde ExpressionParser parser = getLocalContext().getExpressionParser(); for (Iterator it = elements.iterator(); it.hasNext();) { Element element = (Element) it.next(); - String expressionString = parser.parseEvalExpressionString(element.getAttribute(NAME_ATTRIBUTE)); - Expression attributeExpression = parser.parseExpression(expressionString, MutableAttributeMap.class, - Object.class, null); + Expression attributeExpression = parser.parseExpression(element.getAttribute(NAME_ATTRIBUTE), + MutableAttributeMap.class, Object.class, null); Expression scopedAttributeExpression = new ScopedAttributeExpression(attributeExpression, parseScope( element, ScopeType.FLOW)); if (getRequired(element, false)) { @@ -1135,30 +1124,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde } } - private static class ViewResourceExpression implements Expression { - private Expression viewLocation; - private ResourceLoader viewResourceLoader; - - public ViewResourceExpression(Expression viewLocation, ResourceLoader viewResourceLoader) { - this.viewLocation = viewLocation; - this.viewResourceLoader = viewResourceLoader; - } - - public Object getValue(Object target) throws EvaluationException { - String location = (String) viewLocation.getValue(target); - Resource resource = viewResourceLoader.getResource(location); - if (resource instanceof ServletContextResource) { - return ((ServletContextResource) resource).getPath(); - } else { - throw new IllegalArgumentException("Unsupported resource " + resource); - } - } - - public void setValue(Object target, Object value) throws EvaluationException { - throw new UnsupportedOperationException("Set value not supported"); - } - } - private static class FlowRelativeResourceLoader implements ResourceLoader { private Resource resource; diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/EndStateTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/EndStateTests.java index 8330a9e3..99f7e43b 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/EndStateTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/EndStateTests.java @@ -65,7 +65,7 @@ public class EndStateTests extends TestCase { EndState state = new EndState(flow, "end"); DefaultAttributeMapper mapper = new DefaultAttributeMapper(); MappingBuilder builder = new MappingBuilder(DefaultExpressionParserFactory.getExpressionParser()); - Mapping mapping = builder.source("flowScope.x").target("y").value(); + Mapping mapping = builder.source("${flowScope.x}").target("${y}").value(); mapper.addMapping(mapping); state.setOutputMapper(mapper); MockRequestControlContext context = new MockRequestControlContext(flow); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java index 352fa60f..aa548c48 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java @@ -196,7 +196,7 @@ public class FlowTests extends TestCase { public void testStartWithMapper() { DefaultAttributeMapper attributeMapper = new DefaultAttributeMapper(); MappingBuilder mapping = new MappingBuilder(DefaultExpressionParserFactory.getExpressionParser()); - attributeMapper.addMapping(mapping.source("attr").target("flowScope.attr").value()); + attributeMapper.addMapping(mapping.source("${attr}").target("${flowScope.attr}").value()); flow.setInputMapper(attributeMapper); MockRequestControlContext context = new MockRequestControlContext(flow); LocalAttributeMap sessionInput = new LocalAttributeMap(); @@ -208,7 +208,7 @@ public class FlowTests extends TestCase { public void testStartWithMapperButNoInput() { DefaultAttributeMapper attributeMapper = new DefaultAttributeMapper(); MappingBuilder mapping = new MappingBuilder(DefaultExpressionParserFactory.getExpressionParser()); - attributeMapper.addMapping(mapping.source("attr").target("flowScope.attr").value()); + attributeMapper.addMapping(mapping.source("${attr}").target("${flowScope.attr}").value()); flow.setInputMapper(attributeMapper); MockRequestControlContext context = new MockRequestControlContext(flow); LocalAttributeMap sessionInput = new LocalAttributeMap(); @@ -294,7 +294,7 @@ public class FlowTests extends TestCase { public void testEndWithOutputMapper() { DefaultAttributeMapper attributeMapper = new DefaultAttributeMapper(); MappingBuilder mapping = new MappingBuilder(DefaultExpressionParserFactory.getExpressionParser()); - attributeMapper.addMapping(mapping.source("flowScope.attr").target("attr").value()); + attributeMapper.addMapping(mapping.source("${flowScope.attr}").target("${attr}").value()); flow.setOutputMapper(attributeMapper); MockRequestControlContext context = new MockRequestControlContext(flow); context.getFlowScope().put("attr", "foo");