diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/el/ELExpression.java b/spring-binding/src/main/java/org/springframework/binding/expression/el/ELExpression.java index 609e5f1f..ccee6b07 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/el/ELExpression.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/el/ELExpression.java @@ -65,7 +65,8 @@ public class ELExpression implements Expression { } else { EvaluationAttempt attempt = new EvaluationAttempt(this, context); throw new EvaluationException(attempt, attempt - + " failed: the expression path did not resolve--is the base variable incorrect?", null); + + " failed: the expression path did not resolve--is the base variable spelled correctly?", + null); } } return result; diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/WebFlowOgnlExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/WebFlowOgnlExpressionParser.java index a6b86c40..21abb321 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/WebFlowOgnlExpressionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/WebFlowOgnlExpressionParser.java @@ -18,6 +18,7 @@ package org.springframework.webflow.expression; import java.util.Map; import ognl.ObjectPropertyAccessor; +import ognl.Ognl; import ognl.OgnlException; import ognl.PropertyAccessor; @@ -27,7 +28,9 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.support.StaticListableBeanFactory; import org.springframework.binding.collection.MapAdaptable; import org.springframework.binding.expression.ognl.OgnlExpressionParser; -import org.springframework.util.ClassUtils; +import org.springframework.context.MessageSource; +import org.springframework.webflow.context.ExternalContext; +import org.springframework.webflow.context.ExternalContextHolder; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.engine.AnnotatedAction; import org.springframework.webflow.execution.Action; @@ -49,6 +52,7 @@ public class WebFlowOgnlExpressionParser extends OgnlExpressionParser { public WebFlowOgnlExpressionParser() { addPropertyAccessor(MapAdaptable.class, new MapAdaptablePropertyAccessor()); addPropertyAccessor(MutableAttributeMap.class, new MutableAttributeMapPropertyAccessor()); + addPropertyAccessor(MessageSource.class, new MessageSourcePropertyAccessor()); addPropertyAccessor(RequestContext.class, new RequestContextPropertyAccessor(new ObjectPropertyAccessor())); addPropertyAccessor(Action.class, new ActionPropertyAccessor()); addPropertyAccessor(Event.class, new EventPropertyAccessor()); @@ -82,9 +86,6 @@ public class WebFlowOgnlExpressionParser extends OgnlExpressionParser { */ private static class RequestContextPropertyAccessor implements PropertyAccessor { - private static boolean securityPresent = ClassUtils - .isPresent("org.springframework.security.context.SecurityContextHolder"); - private static final BeanFactory EMPTY_BEAN_FACTORY = new StaticListableBeanFactory(); private PropertyAccessor delegate; @@ -108,6 +109,12 @@ public class WebFlowOgnlExpressionParser extends OgnlExpressionParser { } return requestContext.getExternalContext().getCurrentUser(); } + if (property.equals("resourceBundle")) { + if (logger.isDebugEnabled()) { + logger.debug("Successfully resolved implicit flow variable '" + property + "'"); + } + return requestContext.getActiveFlow().getApplicationContext(); + } if (requestContext.getRequestScope().contains(property)) { if (logger.isDebugEnabled()) { logger.debug("Successfully resolved request scoped variable '" + property + "'"); @@ -118,6 +125,11 @@ public class WebFlowOgnlExpressionParser extends OgnlExpressionParser { logger.debug("Successfully resolved flash scoped variable '" + property + "'"); } return requestContext.getFlashScope().get(property); + } else if (requestContext.inViewState() && requestContext.getViewScope().contains(property)) { + if (logger.isDebugEnabled()) { + logger.debug("Successfully resolved view scoped variable '" + property + "'"); + } + return requestContext.getViewScope().get(property); } else if (requestContext.getFlowScope().contains(property)) { if (logger.isDebugEnabled()) { logger.debug("Successfully resolved flow scoped variable '" + property + "'"); @@ -145,9 +157,12 @@ public class WebFlowOgnlExpressionParser extends OgnlExpressionParser { if (property.equals("flowRequestContext")) { throw new OgnlException("The 'flowRequestContext' variable is not writeable"); } - if (securityPresent && property.equals("currentUser")) { + if (property.equals("currentUser")) { throw new OgnlException("The 'currentUser' variable is not writeable"); } + if (property.equals("resourceBundle")) { + throw new OgnlException("The 'resourceBundle' variable is not writeable"); + } if (requestContext.getRequestScope().contains(property)) { if (logger.isDebugEnabled()) { logger.debug("Successfully resolved request scoped variable '" + property + "'"); @@ -158,6 +173,11 @@ public class WebFlowOgnlExpressionParser extends OgnlExpressionParser { logger.debug("Successfully resolved flash scoped variable '" + property + "'"); } requestContext.getFlashScope().put(property, value); + } else if (requestContext.inViewState() && requestContext.getViewScope().contains(property)) { + if (logger.isDebugEnabled()) { + logger.debug("Successfully resolved view scoped variable '" + property + "'"); + } + requestContext.getViewScope().put(property, value); } else if (requestContext.getFlowScope().contains(property)) { if (logger.isDebugEnabled()) { logger.debug("Successfully resolved flow scoped variable '" + property + "'"); @@ -209,4 +229,29 @@ public class WebFlowOgnlExpressionParser extends OgnlExpressionParser { } } + /** + * Resolves messages. + */ + private static class MessageSourcePropertyAccessor implements PropertyAccessor { + public Object getProperty(Map context, Object target, Object name) throws OgnlException { + MessageSource messageSource = (MessageSource) target; + ExternalContext externalContext; + Object root = Ognl.getRoot(context); + if (root instanceof RequestContext) { + externalContext = ((RequestContext) root).getExternalContext(); + } else { + externalContext = ExternalContextHolder.getExternalContext(); + } + if (externalContext != null) { + return messageSource.getMessage(name.toString(), null, null, externalContext.getLocale()); + } else { + return messageSource.getMessage(name.toString(), null, null, null); + } + } + + public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException { + throw new OgnlException("Cannot set properties on a MessageSource instance - operation not allowed"); + } + } + } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/expression/WebFlowOgnlExpressionParserTests.java b/spring-webflow/src/test/java/org/springframework/webflow/expression/WebFlowOgnlExpressionParserTests.java index 7f55bf3d..ba65e356 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/expression/WebFlowOgnlExpressionParserTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/expression/WebFlowOgnlExpressionParserTests.java @@ -1,6 +1,7 @@ package org.springframework.webflow.expression; import java.security.Principal; +import java.util.Locale; import junit.framework.TestCase; @@ -13,9 +14,12 @@ import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.LocalAttributeMap; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.engine.AnnotatedAction; +import org.springframework.webflow.engine.StubViewFactory; +import org.springframework.webflow.engine.ViewState; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.TestAction; import org.springframework.webflow.test.MockRequestContext; +import org.springframework.webflow.test.MockRequestControlContext; public class WebFlowOgnlExpressionParserTests extends TestCase { private WebFlowOgnlExpressionParser parser = new WebFlowOgnlExpressionParser(); @@ -86,6 +90,25 @@ public class WebFlowOgnlExpressionParserTests extends TestCase { assertEquals("baz", exp.getValue(context)); } + public void testResolveViewScope() { + MockRequestControlContext context = new MockRequestControlContext(); + ViewState state = new ViewState(context.getRootFlow(), "view", new StubViewFactory()); + context.setCurrentState(state); + context.getViewScope().put("foo", "bar"); + Expression exp = parser.parseExpression("foo", new FluentParserContext().evaluate(RequestContext.class)); + assertEquals("bar", exp.getValue(context)); + } + + public void testSetViewScope() { + MockRequestControlContext context = new MockRequestControlContext(); + ViewState state = new ViewState(context.getRootFlow(), "view", new StubViewFactory()); + context.setCurrentState(state); + context.getViewScope().put("foo", "bar"); + Expression exp = parser.parseExpression("foo", new FluentParserContext().evaluate(RequestContext.class)); + exp.setValue(context, "baz"); + assertEquals("baz", exp.getValue(context)); + } + public void testResolveFlowScope() { MockRequestContext context = new MockRequestContext(); context.getFlowScope().put("foo", "bar"); @@ -150,4 +173,16 @@ public class WebFlowOgnlExpressionParserTests extends TestCase { assertEquals("setupForm", action.getMethod()); } + public void testResolveMessage() { + MockRequestContext context = new MockRequestContext(); + StaticApplicationContext ac = new StaticApplicationContext(); + ac.getStaticMessageSource().addMessage("foo", Locale.FRANCE, "bar"); + ac.refresh(); + context.getRootFlow().setApplicationContext(ac); + context.getMockExternalContext().setLocale(Locale.FRANCE); + Expression exp = parser.parseExpression("resourceBundle.foo", new FluentParserContext() + .evaluate(RequestContext.class)); + assertEquals("bar", exp.getValue(context)); + } + } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/expression/el/WebFlowELExpressionParserTests.java b/spring-webflow/src/test/java/org/springframework/webflow/expression/el/WebFlowELExpressionParserTests.java index 63675fd1..16c708ae 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/expression/el/WebFlowELExpressionParserTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/expression/el/WebFlowELExpressionParserTests.java @@ -1,6 +1,7 @@ package org.springframework.webflow.expression.el; import java.security.Principal; +import java.util.Locale; import junit.framework.TestCase; @@ -14,10 +15,13 @@ import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.core.collection.LocalAttributeMap; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.engine.AnnotatedAction; +import org.springframework.webflow.engine.StubViewFactory; +import org.springframework.webflow.engine.ViewState; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.TestAction; import org.springframework.webflow.test.MockRequestContext; +import org.springframework.webflow.test.MockRequestControlContext; public class WebFlowELExpressionParserTests extends TestCase { private WebFlowELExpressionParser parser = new WebFlowELExpressionParser(DefaultExpressionFactoryUtils @@ -89,6 +93,25 @@ public class WebFlowELExpressionParserTests extends TestCase { assertEquals("baz", exp.getValue(context)); } + public void testResolveViewScope() { + MockRequestControlContext context = new MockRequestControlContext(); + ViewState state = new ViewState(context.getRootFlow(), "view", new StubViewFactory()); + context.setCurrentState(state); + context.getViewScope().put("foo", "bar"); + Expression exp = parser.parseExpression("foo", new FluentParserContext().evaluate(RequestContext.class)); + assertEquals("bar", exp.getValue(context)); + } + + public void testSetViewScope() { + MockRequestControlContext context = new MockRequestControlContext(); + ViewState state = new ViewState(context.getRootFlow(), "view", new StubViewFactory()); + context.setCurrentState(state); + context.getViewScope().put("foo", "bar"); + Expression exp = parser.parseExpression("foo", new FluentParserContext().evaluate(RequestContext.class)); + exp.setValue(context, "baz"); + assertEquals("baz", exp.getValue(context)); + } + public void testResolveFlowScope() { MockRequestContext context = new MockRequestContext(); context.getFlowScope().put("foo", "bar"); @@ -165,4 +188,15 @@ public class WebFlowELExpressionParserTests extends TestCase { assertEquals(null, exp.getValue(context)); } + public void testResolveMessage() { + MockRequestContext context = new MockRequestContext(); + StaticApplicationContext ac = new StaticApplicationContext(); + ac.getStaticMessageSource().addMessage("foo", Locale.FRANCE, "bar"); + ac.refresh(); + context.getRootFlow().setApplicationContext(ac); + context.getMockExternalContext().setLocale(Locale.FRANCE); + Expression exp = parser.parseExpression("resourceBundle.foo", new FluentParserContext() + .evaluate(RequestContext.class)); + assertEquals("bar", exp.getValue(context)); + } }