Refactored JsfELExpressionParser into Jsf11ELExpressionParser and Jsf12ELExpressionParser and eliminated the nasty FacesAPI class for checking the version. Added unit tests for both parsers using shale-test for a mock JSF environment.

This commit is contained in:
Jeremy Grelle
2007-08-01 13:59:17 +00:00
parent 99416e44ba
commit f89e81033a
12 changed files with 371 additions and 38 deletions

View File

@@ -36,5 +36,6 @@
<classpathentry kind="lib" path="lib/global/el-api.jar"/>
<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="output" path="target/classes"/>
</classpath>

View File

@@ -72,6 +72,7 @@
<dependency org="com.cenqua.clover" name="clover" rev="1.3.12" conf="test->default" />
<dependency org="org.springframework" name="spring-jdbc" rev="2.0.6" conf="test->default" />
<dependency org="org.springframework" name="spring-mock" rev="2.0.6" conf="test->default" />
<dependency org="org.apache.shale" name="shale-test" rev="1.0.4" conf="test->default" />
</dependencies>
</ivy-module>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">
<start-state idref="viewState1" />
<view-state id="viewState1" view="view1">
<transition on="event1" to="doSomething"/>
<transition on="event2" to="evalSomething"/>
</view-state>
<action-state id="doSomething">
<bean-action bean="serviceBean" method="doSomething">
<method-arguments>
<argument expression="#{JsfBean.prop1}"/>
</method-arguments>
</bean-action>
<transition to="viewState2"/>
</action-state>
<action-state id="evalSomething">
<evaluate-action expression="#{JsfBean.addValue(jsfModel.value)}"/>
<transition to="viewState2"/>
</action-state>
<view-state id="viewState2" view="view2">
<transition on="event1" to="endState1"/>
</view-state>
<end-state id="endState1" view="endView1"/>
</flow>

View File

@@ -1,25 +0,0 @@
package org.springframework.webflow.executor.jsf;
import javax.faces.application.Application;
public class FacesAPI {
private static final int version = specifyVersion();
private FacesAPI() {
}
private final static int specifyVersion() {
try {
Application.class.getMethod("getExpressionFactory", null);
} catch (NoSuchMethodException e) {
return 11;
}
return 12;
}
public final static int getVersion() {
return version;
}
}

View File

@@ -10,32 +10,26 @@ import org.springframework.binding.expression.el.ELContextFactory;
import org.springframework.binding.expression.el.JBossELExpressionParser;
/**
* A JSF-aware ExpressionParser that allows JSF managed beans to be referenced in expressions in the FlowDefinition.
* A JSF-aware ExpressionParser that allows JSF 1.1 managed beans to be referenced in expressions in the FlowDefinition.
* @author Jeremy Grelle
*
*/
public class JsfELExpressionParser extends JBossELExpressionParser {
public class Jsf11ELExpressionParser extends JBossELExpressionParser {
public JsfELExpressionParser() {
super(new JsfELContextFactory());
public Jsf11ELExpressionParser() {
super(new Jsf11ELContextFactory());
}
public JsfELExpressionParser(ELContextFactory contextFactory) {
public Jsf11ELExpressionParser(ELContextFactory contextFactory) {
super(contextFactory);
}
private static class JsfELContextFactory implements ELContextFactory {
private static class Jsf11ELContextFactory implements ELContextFactory {
public ELContext getELContext(Object target) {
FacesContext context = FacesContext.getCurrentInstance();
if (FacesAPI.getVersion() < 12) {
return new Jsf11ELContext(context);
}
if (context != null) {
return context.getELContext();
}
return null;
return new Jsf11ELContext(context);
}
private static class Jsf11ELContext extends ELContext {

View File

@@ -0,0 +1,36 @@
package org.springframework.webflow.executor.jsf;
import javax.el.ELContext;
import javax.faces.context.FacesContext;
import org.springframework.binding.expression.el.ELContextFactory;
import org.springframework.binding.expression.el.JBossELExpressionParser;
/**
* 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 Jsf12ELExpressionParser() {
super(new Jsf11ELContextFactory());
}
public Jsf12ELExpressionParser(ELContextFactory contextFactory) {
super(contextFactory);
}
private static class Jsf11ELContextFactory implements ELContextFactory {
public ELContext getELContext(Object target) {
FacesContext context = FacesContext.getCurrentInstance();
if (context != null) {
return context.getELContext();
}
return null;
}
}
}

View File

@@ -0,0 +1,80 @@
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

@@ -0,0 +1,140 @@
package org.springframework.webflow.executor.jsf;
import java.io.FileNotFoundException;
import javax.faces.el.ValueBinding;
import org.easymock.MockControl;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.webflow.definition.registry.FlowDefinitionResource;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.ViewSelection;
import org.springframework.webflow.test.MockFlowServiceLocator;
import org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests;
public class JSF11ManagedBeanAccessTests extends AbstractXmlFlowExecutionTests {
JSF 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");
jsf.setUp();
configureJSFForSWF();
}
private void configureJSFForSWF() {
DelegatingFlowVariableResolver dfvr = new DelegatingFlowVariableResolver(jsf.application()
.getVariableResolver());
FlowVariableResolver fvr = new FlowVariableResolver(dfvr);
jsf.application().setVariableResolver(fvr);
FlowPropertyResolver fpr = new FlowPropertyResolver(jsf.application().getPropertyResolver());
jsf.application().setPropertyResolver(fpr);
// flowPhaseListener = new FlowPhaseListener();
// jsf.lifecycle().addPhaseListener(flowPhaseListener);
flowNavigationHandler = new FlowNavigationHandler(jsf.application().getNavigationHandler());
jsf.application().setNavigationHandler(flowNavigationHandler);
jsf.externalContext().getRequestMap().put("JsfBean", new JSFManagedBean());
// flowPhaseListener.setupELContext(jsf.facesContext());
}
protected void tearDown() throws Exception {
super.tearDown();
jsf.tearDown();
// flowPhaseListener.teardownELContext();
}
public void testManagedBeanExpression() {
ValueBinding vb = jsf.application().createValueBinding("#{JsfBean}");
jsfBean = (JSFManagedBean) vb.getValue(jsf.facesContext());
assertNotNull(jsfBean);
}
public void testSWFExplicitlyScopedPropertyInjection() {
testManagedBeanExpression();
startFlow();
ValueBinding propBinding = jsf.application().createValueBinding("#{flowScope.jsfModel}");
jsfModel = (JSFModel) propBinding.getValue(jsf.facesContext());
assertNotNull(jsfModel);
jsfBean.setModel(jsfModel);
}
public void testManagedBeanProperyAsArgument() {
testManagedBeanExpression();
jsfBean.setProp1("arg");
service.doSomething(jsfBean.getProp1());
serviceControl.replay();
startFlow();
signalEvent("event1");
serviceControl.verify();
assertCurrentStateEquals("viewState2");
}
public void testEvalManagedBeanMethod() {
testManagedBeanExpression();
startFlow();
ValueBinding propBinding = jsf.application().createValueBinding("#{flowScope.jsfModel}");
jsfModel = (JSFModel) propBinding.getValue(jsf.facesContext());
assertNotNull(jsfModel);
jsfModel.setValue("foo");
signalEvent("event2");
assertFalse(jsfBean.getValues().isEmpty());
String addedValue = jsfBean.getValues().get(0).toString();
assertEquals(jsfModel.getValue(), addedValue);
assertCurrentStateEquals("viewState2");
}
public void testSWFScopedPropertyInjection() {
// testManagedBeanExpression();
// startFlow();
// TODO - Add a flow scoped bean definition to the test application context
// ValueBinding propBinding = jsf.application().createValueBinding("#{flowScopedModel}");
// jsfModel = (JSFModel) propBinding.getValue(jsf.facesContext());
// assertNotNull("This test won't pass until custom scopes are implemented.", jsfModel);
// jsfBean.setModel(jsfModel);
}
protected ViewSelection startFlow() throws FlowExecutionException {
ViewSelection view = super.startFlow();
FlowExecutionHolder holder = new FlowExecutionHolder(getFlowExecution());
FlowExecutionHolderUtils.setFlowExecutionHolder(holder, jsf.facesContext());
holder.setViewSelection(view);
return view;
}
protected FlowDefinitionResource getFlowDefinitionResource() {
try {
return createFlowDefinitionResource(ResourceUtils.getFile("classpath:jsf-flow.xml").getPath());
} catch (FileNotFoundException e) {
fail(e.getMessage());
return null;
}
}
protected void registerMockServices(MockFlowServiceLocator serviceRegistry) {
serviceRegistry.setExpressionParser(new Jsf11ELExpressionParser());
serviceRegistry.registerBean("serviceBean", service);
StaticWebApplicationContext ctx = new StaticWebApplicationContext();
ctx.registerPrototype("jsfModel", JSFModel.class);
jsf.externalContext().getApplicationMap()
.put(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
}
}

View File

@@ -0,0 +1,18 @@
package org.springframework.webflow.executor.jsf;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.webflow.test.MockFlowServiceLocator;
public class JSF12ManagedBeanAccessTests extends JSF11ManagedBeanAccessTests {
protected void registerMockServices(MockFlowServiceLocator serviceRegistry) {
serviceRegistry.setExpressionParser(new Jsf12ELExpressionParser());
serviceRegistry.registerBean("serviceBean", service);
StaticWebApplicationContext ctx = new StaticWebApplicationContext();
ctx.registerPrototype("jsfModel", JSFModel.class);
jsf.externalContext().getApplicationMap()
.put(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
}
}

View File

@@ -0,0 +1,37 @@
package org.springframework.webflow.executor.jsf;
import java.util.ArrayList;
import java.util.List;
public class JSFManagedBean {
String prop1;
JSFModel model;
List values = new ArrayList();
public JSFModel getModel() {
return model;
}
public void setModel(JSFModel model) {
this.model = model;
}
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public void addValue(String value)
{
values.add(value);
}
public List getValues()
{
return values;
}
}

View File

@@ -0,0 +1,13 @@
package org.springframework.webflow.executor.jsf;
public class JSFModel {
String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,6 @@
package org.springframework.webflow.executor.jsf;
public interface MockService {
public void doSomething(String arg);
}