Polishing EL integration.

This commit is contained in:
Jeremy Grelle
2007-08-01 16:33:08 +00:00
parent 6e4b13f273
commit 1647f0151f
15 changed files with 283 additions and 185 deletions

View File

@@ -0,0 +1,54 @@
package org.springframework.binding.expression.el;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;
/**
* A default {@link ELContextFactory} for facilitating use of EL for expression evaluation.
* @author Jeremy Grelle
*
*/
public class DefaultELContextFactory implements ELContextFactory {
/**
* Configures and returns a simple EL context to use to parse EL expressions.
* @return The configured simple ELContext instance.
*/
public ELContext getParseTimeELContext() {
return new SimpleELContext();
}
/**
* Configures and returns a simple EL context to use to evaluate EL expressions on the given base target object.
* @return The configured simple ELContext instance.
*/
public ELContext getEvalTimeELContext(Object target) {
return new SimpleELContext(target);
}
private static class SimpleELContext extends ELContext {
private DefaultELResolver resolver = new DefaultELResolver();
public SimpleELContext() {
}
public SimpleELContext(Object target) {
this.resolver.setTarget(target);
}
public ELResolver getELResolver() {
return resolver;
}
public FunctionMapper getFunctionMapper() {
return null;
}
public VariableMapper getVariableMapper() {
return null;
}
}
}

View File

@@ -1,6 +1,7 @@
package org.springframework.binding.expression.el;
import javax.el.ELContext;
import javax.el.ELResolver;
/**
* A factory for creating a EL context object that will be used to evaluate a target object of an EL expression.
@@ -10,11 +11,18 @@ import javax.el.ELContext;
public interface ELContextFactory {
/**
* Configures and returns a {@link DelegatingELContext} to be used in evaluating EL expressions on the given base
* target object.
*
* @return DelegatingELContext The configured DelegatingELContext instance.
* Configures and returns an {@link ELContext} to be used in parsing EL expressions.
* @return ELContext The configured ELContext instance for parsing expressions.
*/
public ELContext getELContext(Object target);
public ELContext getParseTimeELContext();
/**
* Configures and returns an {@link ELContext} to be used in evaluating EL expressions on the given base target
* object. In certain environments the target will be null and the base object of the expression is expected to be
* resolved via the ELContext's {@link ELResolver} chain.
* @param target The base object for the expression evaluation.
* @return ELContext The configured ELContext instance for evaluating expressions.
*/
public ELContext getEvalTimeELContext(Object target);
}

View File

@@ -59,7 +59,7 @@ public class ELExpression implements SettableExpression {
* @return {@link ELContext} The thread-bound {@link ELContext} instance.
*/
protected ELContext getELContext(Object target) {
ELContext ctx = factory.getELContext(target);
ELContext ctx = factory.getEvalTimeELContext(target);
return ctx;
}

View File

@@ -2,25 +2,18 @@ package org.springframework.binding.expression.el;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;
import org.jboss.el.ExpressionFactoryImpl;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.SettableExpression;
/**
* An expression parser that parses EL expressions. Beyond standard EL expression parsing, it makes use of the ability
* of the JBoss-EL implementation to parse dynamic method invocations such as foo.bar() (the EL spec currently only
* provides out-of-the-box support for functions).
*
* An expression parser that parses EL expressions.
* @author Jeremy Grelle
*/
public class JBossELExpressionParser implements ExpressionParser {
public class ELExpressionParser implements ExpressionParser {
/**
* The expression prefix for deferred EL expressions.
@@ -50,12 +43,13 @@ public class JBossELExpressionParser implements ExpressionParser {
/**
* The ExpressionFactory for constructing EL expressions
*/
private ExpressionFactory factory = new ExpressionFactoryImpl();
private ExpressionFactory expressionFactory;
/**
* Creates a new EL expression parser for standalone usage.
*/
public JBossELExpressionParser() {
public ELExpressionParser(ExpressionFactory expressionFactory) {
this.expressionFactory = expressionFactory;
this.contextFactory = new DefaultELContextFactory();
}
@@ -64,7 +58,8 @@ public class JBossELExpressionParser implements ExpressionParser {
*
* @param contextFactory the context factory
*/
public JBossELExpressionParser(ELContextFactory contextFactory) {
public ELExpressionParser(ExpressionFactory expressionFactory, ELContextFactory contextFactory) {
this.expressionFactory = expressionFactory;
this.contextFactory = contextFactory;
}
@@ -118,43 +113,12 @@ public class JBossELExpressionParser implements ExpressionParser {
* @throws ParserException
*/
protected SettableExpression doParseSettableExpression(String expressionString) throws ParserException {
ELContext ctx = contextFactory.getELContext(null);
ELContext ctx = contextFactory.getParseTimeELContext();
try {
return new ELExpression(contextFactory, factory.createValueExpression(ctx, expressionString, Object.class));
return new ELExpression(contextFactory, expressionFactory.createValueExpression(ctx, expressionString,
Object.class));
} catch (ELException ex) {
throw new ParserException(expressionString, ex);
}
}
static class DefaultELContextFactory implements ELContextFactory {
/**
* Configures and returns a simple EL context to use to evaluate EL expressions on the given base target object.
* @return The configured simple ELContext instance.
*/
public ELContext getELContext(Object target) {
return new SimpleELContext(target);
}
private static class SimpleELContext extends ELContext {
private DefaultELResolver resolver;
public SimpleELContext(Object target) {
this.resolver = new DefaultELResolver();
this.resolver.setTarget(target);
}
public ELResolver getELResolver() {
return resolver;
}
public FunctionMapper getFunctionMapper() {
return null;
}
public VariableMapper getVariableMapper() {
return null;
}
}
}
}

View File

@@ -5,7 +5,8 @@ import java.util.Map;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.easymock.EasyMock;
import org.jboss.el.ExpressionFactoryImpl;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.support.TestBean;
import org.springframework.binding.expression.support.TestMethods;
@@ -14,22 +15,20 @@ import org.springframework.binding.expression.support.TestMethods;
* Tests to exercise the extended method invoking expression extensions of JBoss-el.
* @author Jeremy Grelle
*/
public class JBossELExpressionParserTests extends TestCase {
public class ELExpressionParserTests extends TestCase {
JBossELExpressionParser parser = new JBossELExpressionParser();
ELExpressionParser parser = new ELExpressionParser(new ExpressionFactoryImpl());
Map context;
Map container;
TestMethods target;
MockControl targetMockControl;
protected void setUp() throws Exception {
context = new HashMap();
container = new HashMap();
targetMockControl = MockControl.createControl(TestMethods.class);
target = (TestMethods) targetMockControl.getMock();
target = (TestMethods) EasyMock.createMock(TestMethods.class);
context.put("container", container);
container.put("myObject", target);
}
@@ -39,10 +38,10 @@ public class JBossELExpressionParserTests extends TestCase {
int param = 5;
container.put("param1", new Integer(param));
target.doSomethingWithInt(param);
targetMockControl.replay();
EasyMock.replay(new Object[] { target });
parser.parseExpression(expression).evaluate(context, null);
targetMockControl.verify();
EasyMock.verify(new Object[] { target });
}
@@ -51,11 +50,11 @@ public class JBossELExpressionParserTests extends TestCase {
String expression = "#{container.myObject.returnStringFromInt(container.param1)}";
int param = 5;
container.put("param1", new Integer(param));
targetMockControl.expectAndReturn(target.returnStringFromInt(param), expected);
targetMockControl.replay();
EasyMock.expect(target.returnStringFromInt(param)).andReturn(expected);
EasyMock.replay(new Object[] { target });
String result = (String) parser.parseExpression(expression).evaluate(context, null);
targetMockControl.verify();
EasyMock.verify(new Object[] { target });
assertEquals(expected, result);
}
@@ -66,11 +65,11 @@ public class JBossELExpressionParserTests extends TestCase {
container.put("param1", new Integer(param1));
TestBean param2 = new TestBean();
container.put("param2", param2);
targetMockControl.expectAndReturn(target.returnStringFromIntAndObject(param1, param2), expected);
targetMockControl.replay();
EasyMock.expect(target.returnStringFromIntAndObject(param1, param2)).andReturn(expected);
EasyMock.replay(new Object[] { target });
String result = (String) parser.parseExpression(expression).evaluate(context, null);
targetMockControl.verify();
EasyMock.verify(new Object[] { target });
assertEquals(expected, result);
}

View File

@@ -18,10 +18,11 @@ package org.springframework.binding.expression.support;
import java.util.ArrayList;
import java.util.List;
import org.jboss.el.ExpressionFactoryImpl;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.el.JBossELExpressionParser;
import org.springframework.binding.expression.el.ELExpressionParser;
import org.springframework.binding.expression.ognl.OgnlExpressionParser;
import junit.framework.TestCase;
@@ -48,9 +49,12 @@ public class SimpleExpressionTests extends TestCase {
suite.addTest(new SimpleExpressionTests("testGetValue", new BeanWrapperExpressionParser(), "$"));
suite.addTest(new SimpleExpressionTests("testSetValue", new BeanWrapperExpressionParser(), "$"));
suite.addTest(new SimpleExpressionTests("testSyntaxError", new BeanWrapperExpressionParser(), "$"));
suite.addTest(new SimpleExpressionTests("testGetValue", new JBossELExpressionParser(), "#"));
suite.addTest(new SimpleExpressionTests("testSetValue", new JBossELExpressionParser(), "#"));
suite.addTest(new SimpleExpressionTests("testSyntaxError", new JBossELExpressionParser(), "#"));
suite.addTest(new SimpleExpressionTests("testGetValue", new ELExpressionParser(new ExpressionFactoryImpl()),
"#"));
suite.addTest(new SimpleExpressionTests("testSetValue", new ELExpressionParser(new ExpressionFactoryImpl()),
"#"));
suite.addTest(new SimpleExpressionTests("testSyntaxError", new ELExpressionParser(new ExpressionFactoryImpl()),
"#"));
return suite;
}

View File

@@ -37,5 +37,6 @@
<classpathentry kind="lib" path="lib/buildtime/persistence-api.jar"/>
<classpathentry kind="lib" path="lib/buildtime/spring-jpa.jar"/>
<classpathentry kind="lib" path="lib/test/shale-test.jar"/>
<classpathentry kind="lib" path="lib/global/jboss-el.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -2,31 +2,33 @@ package org.springframework.webflow.executor.jsf;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;
import javax.faces.context.FacesContext;
import org.springframework.binding.expression.el.DefaultELContextFactory;
import org.springframework.binding.expression.el.ELContextFactory;
import org.springframework.binding.expression.el.JBossELExpressionParser;
import org.springframework.binding.expression.el.ELExpressionParser;
/**
* A JSF-aware ExpressionParser that allows JSF 1.1 managed beans to be referenced in expressions in the FlowDefinition.
* @author Jeremy Grelle
*
*/
public class Jsf11ELExpressionParser extends JBossELExpressionParser {
public class Jsf11ELExpressionParser extends ELExpressionParser {
public Jsf11ELExpressionParser() {
super(new Jsf11ELContextFactory());
public Jsf11ELExpressionParser(ExpressionFactory expressionFactory) {
super(expressionFactory, new Jsf11ELContextFactory());
}
public Jsf11ELExpressionParser(ELContextFactory contextFactory) {
super(contextFactory);
public Jsf11ELExpressionParser(ExpressionFactory expressionFactory, ELContextFactory contextFactory) {
super(expressionFactory, contextFactory);
}
private static class Jsf11ELContextFactory implements ELContextFactory {
private static class Jsf11ELContextFactory extends DefaultELContextFactory {
public ELContext getELContext(Object target) {
public ELContext getEvalTimeELContext(Object target) {
FacesContext context = FacesContext.getCurrentInstance();
return new Jsf11ELContext(context);
@@ -37,7 +39,7 @@ public class Jsf11ELExpressionParser extends JBossELExpressionParser {
ELResolver baseResolver;
public Jsf11ELContext(FacesContext context) {
baseResolver = new ELResolverAdapter(context);
baseResolver = new Jsf11ELResolverAdapter(context);
}
public ELResolver getELResolver() {

View File

@@ -19,11 +19,11 @@ import javax.faces.el.VariableResolver;
* @author Jeremy Grelle
*
*/
public class ELResolverAdapter extends ELResolver {
public class Jsf11ELResolverAdapter extends ELResolver {
private FacesContext facesContext;
public ELResolverAdapter(FacesContext facesContext) {
public Jsf11ELResolverAdapter(FacesContext facesContext) {
this.facesContext = facesContext;
}

View File

@@ -1,35 +1,33 @@
package org.springframework.webflow.executor.jsf;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.faces.context.FacesContext;
import org.springframework.binding.expression.el.DefaultELContextFactory;
import org.springframework.binding.expression.el.ELContextFactory;
import org.springframework.binding.expression.el.JBossELExpressionParser;
import org.springframework.binding.expression.el.ELExpressionParser;
/**
* A JSF-aware ExpressionParser that allows JSF 1.2 managed beans to be referenced in expressions in the FlowDefinition.
* @author Jeremy Grelle
*
*/
public class Jsf12ELExpressionParser extends JBossELExpressionParser {
public class Jsf12ELExpressionParser extends ELExpressionParser {
public Jsf12ELExpressionParser() {
super(new Jsf11ELContextFactory());
public Jsf12ELExpressionParser(ExpressionFactory expressionFactory) {
super(expressionFactory, new Jsf12ELContextFactory());
}
public Jsf12ELExpressionParser(ELContextFactory contextFactory) {
super(contextFactory);
public Jsf12ELExpressionParser(ExpressionFactory expressionFactory, ELContextFactory contextFactory) {
super(expressionFactory, contextFactory);
}
private static class Jsf11ELContextFactory implements ELContextFactory {
public ELContext getELContext(Object target) {
private static class Jsf12ELContextFactory extends DefaultELContextFactory {
public ELContext getEvalTimeELContext(Object target) {
FacesContext context = FacesContext.getCurrentInstance();
if (context != null) {
return context.getELContext();
}
return null;
return context.getELContext();
}
}

View File

@@ -1,80 +0,0 @@
package org.springframework.webflow.executor.jsf;
import org.apache.shale.test.base.AbstractJsfTestCase;
import org.apache.shale.test.mock.MockApplication;
import org.apache.shale.test.mock.MockExternalContext;
import org.apache.shale.test.mock.MockFacesContextFactory;
import org.apache.shale.test.mock.MockHttpServletRequest;
import org.apache.shale.test.mock.MockHttpServletResponse;
import org.apache.shale.test.mock.MockHttpSession;
import org.apache.shale.test.mock.MockLifecycle;
import org.apache.shale.test.mock.MockLifecycleFactory;
import org.apache.shale.test.mock.MockRenderKit;
import org.apache.shale.test.mock.MockServletConfig;
import org.apache.shale.test.mock.MockFacesContext;
import org.apache.shale.test.mock.MockServletContext;
public class JSF extends AbstractJsfTestCase {
public JSF(String name) {
super(name);
}
public void setUp() throws Exception {
super.setUp();
}
public void tearDown() throws Exception {
super.tearDown();
}
public MockApplication application() {
return application;
}
public MockServletConfig config() {
return config;
}
public MockExternalContext externalContext() {
return externalContext;
}
public MockFacesContext facesContext() {
return facesContext;
}
public MockFacesContextFactory facesContextFactory() {
return facesContextFactory;
}
public MockLifecycle lifecycle() {
return lifecycle;
}
public MockLifecycleFactory lifecycleFactory() {
return lifecycleFactory;
}
public MockRenderKit renderKit() {
return renderKit;
}
public MockHttpServletRequest request() {
return request;
}
public MockHttpServletResponse response() {
return response;
}
public MockServletContext servletContext() {
return servletContext;
}
public MockHttpSession session() {
return session;
}
}

View File

@@ -4,7 +4,8 @@ import java.io.FileNotFoundException;
import javax.faces.el.ValueBinding;
import org.easymock.MockControl;
import org.easymock.EasyMock;
import org.jboss.el.ExpressionFactoryImpl;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StaticWebApplicationContext;
@@ -16,19 +17,17 @@ import org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests;
public class JSF11ManagedBeanAccessTests extends AbstractXmlFlowExecutionTests {
JSF jsf;
JSFMockHelper jsf;
JSFManagedBean jsfBean;
JSFModel jsfModel;
FlowPhaseListener flowPhaseListener;
FlowNavigationHandler flowNavigationHandler;
MockService service;
MockControl serviceControl;
protected void setUp() throws Exception {
super.setUp();
serviceControl = MockControl.createControl(MockService.class);
service = (MockService) serviceControl.getMock();
jsf = new JSF("JSFManagedBeanAccessTests");
service = (MockService) EasyMock.createMock(MockService.class);
jsf = new JSFMockHelper();
jsf.setUp();
configureJSFForSWF();
}
@@ -77,11 +76,11 @@ public class JSF11ManagedBeanAccessTests extends AbstractXmlFlowExecutionTests {
testManagedBeanExpression();
jsfBean.setProp1("arg");
service.doSomething(jsfBean.getProp1());
serviceControl.replay();
EasyMock.replay(new Object[] { service });
startFlow();
signalEvent("event1");
serviceControl.verify();
EasyMock.verify(new Object[] { service });
assertCurrentStateEquals("viewState2");
}
@@ -122,7 +121,8 @@ public class JSF11ManagedBeanAccessTests extends AbstractXmlFlowExecutionTests {
protected FlowDefinitionResource getFlowDefinitionResource() {
try {
return createFlowDefinitionResource(ResourceUtils.getFile("classpath:jsf-flow.xml").getPath());
return createFlowDefinitionResource(ResourceUtils.getFile(
"classpath:org/springframework/webflow/executor/jsf/jsf-flow.xml").getPath());
} catch (FileNotFoundException e) {
fail(e.getMessage());
return null;
@@ -130,7 +130,7 @@ public class JSF11ManagedBeanAccessTests extends AbstractXmlFlowExecutionTests {
}
protected void registerMockServices(MockFlowServiceLocator serviceRegistry) {
serviceRegistry.setExpressionParser(new Jsf11ELExpressionParser());
serviceRegistry.setExpressionParser(new Jsf11ELExpressionParser(new ExpressionFactoryImpl()));
serviceRegistry.registerBean("serviceBean", service);
StaticWebApplicationContext ctx = new StaticWebApplicationContext();
ctx.registerPrototype("jsfModel", JSFModel.class);

View File

@@ -1,5 +1,6 @@
package org.springframework.webflow.executor.jsf;
import org.jboss.el.ExpressionFactoryImpl;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.webflow.test.MockFlowServiceLocator;
@@ -7,7 +8,7 @@ import org.springframework.webflow.test.MockFlowServiceLocator;
public class JSF12ManagedBeanAccessTests extends JSF11ManagedBeanAccessTests {
protected void registerMockServices(MockFlowServiceLocator serviceRegistry) {
serviceRegistry.setExpressionParser(new Jsf12ELExpressionParser());
serviceRegistry.setExpressionParser(new Jsf12ELExpressionParser(new ExpressionFactoryImpl()));
serviceRegistry.registerBean("serviceBean", service);
StaticWebApplicationContext ctx = new StaticWebApplicationContext();
ctx.registerPrototype("jsfModel", JSFModel.class);

View File

@@ -0,0 +1,147 @@
package org.springframework.webflow.executor.jsf;
import org.apache.shale.test.base.AbstractJsfTestCase;
import org.apache.shale.test.mock.MockApplication;
import org.apache.shale.test.mock.MockExternalContext;
import org.apache.shale.test.mock.MockFacesContextFactory;
import org.apache.shale.test.mock.MockHttpServletRequest;
import org.apache.shale.test.mock.MockHttpServletResponse;
import org.apache.shale.test.mock.MockHttpSession;
import org.apache.shale.test.mock.MockLifecycle;
import org.apache.shale.test.mock.MockLifecycleFactory;
import org.apache.shale.test.mock.MockRenderKit;
import org.apache.shale.test.mock.MockServletConfig;
import org.apache.shale.test.mock.MockFacesContext;
import org.apache.shale.test.mock.MockServletContext;
/**
* Helper for using the mock JSF environment provided by shale-test inside unit tests that do not extend
* {@link AbstractJsfTestCase}
* @author Jeremy Grelle
*
*/
public class JSFMockHelper {
private JSFMock mock = new JSFMock();
public MockApplication application() {
return mock.application();
}
public MockServletConfig config() {
return mock.config();
}
public MockExternalContext externalContext() {
return mock.externalContext();
}
public MockFacesContext facesContext() {
return mock.facesContext();
}
public MockFacesContextFactory facesContextFactory() {
return mock.facesContextFactory();
}
public MockLifecycle lifecycle() {
return mock.lifecycle();
}
public MockLifecycleFactory lifecycleFactory() {
return mock.lifecycleFactory();
}
public MockRenderKit renderKit() {
return mock.renderKit();
}
public MockHttpServletRequest request() {
return mock.request();
}
public MockHttpServletResponse response() {
return mock.response();
}
public MockServletContext servletContext() {
return mock.servletContext();
}
public MockHttpSession session() {
return mock.session();
}
public void setUp() throws Exception {
mock.setUp();
}
public void tearDown() throws Exception {
mock.tearDown();
}
private static class JSFMock extends AbstractJsfTestCase {
public JSFMock() {
super("JSFMock");
}
public void setUp() throws Exception {
super.setUp();
}
public void tearDown() throws Exception {
super.tearDown();
}
public MockApplication application() {
return application;
}
public MockServletConfig config() {
return config;
}
public MockExternalContext externalContext() {
return externalContext;
}
public MockFacesContext facesContext() {
return facesContext;
}
public MockFacesContextFactory facesContextFactory() {
return facesContextFactory;
}
public MockLifecycle lifecycle() {
return lifecycle;
}
public MockLifecycleFactory lifecycleFactory() {
return lifecycleFactory;
}
public MockRenderKit renderKit() {
return renderKit;
}
public MockHttpServletRequest request() {
return request;
}
public MockHttpServletResponse response() {
return response;
}
public MockServletContext servletContext() {
return servletContext;
}
public MockHttpSession session() {
return session;
}
}
}