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:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
32
spring-webflow/src/etc/test-resources/jsf-flow.xml
Normal file
32
spring-webflow/src/etc/test-resources/jsf-flow.xml
Normal 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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.springframework.webflow.executor.jsf;
|
||||
|
||||
public interface MockService {
|
||||
|
||||
public void doSomething(String arg);
|
||||
}
|
||||
Reference in New Issue
Block a user