diff --git a/spring-webflow/.classpath b/spring-webflow/.classpath index 3cb0bef3..3650210c 100644 --- a/spring-webflow/.classpath +++ b/spring-webflow/.classpath @@ -36,5 +36,6 @@ + diff --git a/spring-webflow/ivy.xml b/spring-webflow/ivy.xml index 69b546ea..db726492 100644 --- a/spring-webflow/ivy.xml +++ b/spring-webflow/ivy.xml @@ -72,6 +72,7 @@ + \ No newline at end of file diff --git a/spring-webflow/src/etc/test-resources/jsf-flow.xml b/spring-webflow/src/etc/test-resources/jsf-flow.xml new file mode 100644 index 00000000..8cf2899d --- /dev/null +++ b/spring-webflow/src/etc/test-resources/jsf-flow.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FacesAPI.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FacesAPI.java deleted file mode 100644 index 6482e7f2..00000000 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FacesAPI.java +++ /dev/null @@ -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; - } -} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfELExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/Jsf11ELExpressionParser.java similarity index 62% rename from spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfELExpressionParser.java rename to spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/Jsf11ELExpressionParser.java index cfe7e824..90bde56c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfELExpressionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/Jsf11ELExpressionParser.java @@ -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 { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/Jsf12ELExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/Jsf12ELExpressionParser.java new file mode 100644 index 00000000..61283850 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/Jsf12ELExpressionParser.java @@ -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; + } + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF.java b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF.java new file mode 100644 index 00000000..5ac41b76 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF.java @@ -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; + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF11ManagedBeanAccessTests.java b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF11ManagedBeanAccessTests.java new file mode 100644 index 00000000..43c1c5bb --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF11ManagedBeanAccessTests.java @@ -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); + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF12ManagedBeanAccessTests.java b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF12ManagedBeanAccessTests.java new file mode 100644 index 00000000..948a2a0e --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSF12ManagedBeanAccessTests.java @@ -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); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSFManagedBean.java b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSFManagedBean.java new file mode 100644 index 00000000..a987891b --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSFManagedBean.java @@ -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; + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSFModel.java b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSFModel.java new file mode 100644 index 00000000..2a7e41a7 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/JSFModel.java @@ -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; + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/MockService.java b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/MockService.java new file mode 100644 index 00000000..5e629066 --- /dev/null +++ b/spring-webflow/src/test/java/org/springframework/webflow/executor/jsf/MockService.java @@ -0,0 +1,6 @@ +package org.springframework.webflow.executor.jsf; + +public interface MockService { + + public void doSomething(String arg); +}