Author: dan.j.allen
Date: 2008-12-01 16:41:20 -0500 (Mon, 01 Dec 2008)
New Revision: 9684
Added:
trunk/src/test/unit/org/jboss/seam/test/unit/ExpressionsTest.java
Modified:
trunk/src/main/org/jboss/seam/faces/FacesExpressions.java
trunk/src/main/org/jboss/seam/init/Initialization.java
trunk/src/main/org/jboss/seam/mock/MockExternalContext.java
trunk/src/main/org/jboss/seam/navigation/Param.java
trunk/src/test/unit/org/jboss/seam/test/unit/PageParamTest.java
Log:
JBSEAM-3674
Modified: trunk/src/main/org/jboss/seam/faces/FacesExpressions.java
===================================================================
--- trunk/src/main/org/jboss/seam/faces/FacesExpressions.java 2008-12-01 21:40:20 UTC (rev
9683)
+++ trunk/src/main/org/jboss/seam/faces/FacesExpressions.java 2008-12-01 21:41:20 UTC (rev
9684)
@@ -33,15 +33,13 @@
@Override
public ELContext getELContext()
{
- FacesContext facesContext = FacesContext.getCurrentInstance();
- return facesContext == null || FacesLifecycle.getPhaseId() == null
- ? super.getELContext() : facesContext.getELContext();
+ return isFacesContextActive() ? FacesContext.getCurrentInstance().getELContext() :
super.getELContext();
}
@Override
protected boolean isFacesContextActive()
{
- return FacesContext.getCurrentInstance()==null;
+ return FacesContext.getCurrentInstance() != null &&
FacesLifecycle.getPhaseId() != null;
}
}
Modified: trunk/src/main/org/jboss/seam/init/Initialization.java
===================================================================
--- trunk/src/main/org/jboss/seam/init/Initialization.java 2008-12-01 21:40:20 UTC (rev
9683)
+++ trunk/src/main/org/jboss/seam/init/Initialization.java 2008-12-01 21:41:20 UTC (rev
9684)
@@ -45,6 +45,7 @@
import org.jboss.seam.bpm.Jbpm;
import org.jboss.seam.contexts.Context;
import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.contexts.ServletLifecycle;
import org.jboss.seam.core.Expressions;
import org.jboss.seam.core.Init;
@@ -758,7 +759,6 @@
boolean changed = new TimestampCheckForwardingDeploymentStrategy()
{
-
@Override
protected DeploymentStrategy delegate()
{
@@ -806,7 +806,6 @@
final WarRootDeploymentStrategy warRootDeploymentStrategy = new
WarRootDeploymentStrategy(Thread.currentThread().getContextClassLoader(), warRoot, new
File[] { warClassesDirectory, warLibDirectory, hotDeployDirectory });
changed = new TimestampCheckForwardingDeploymentStrategy()
{
-
@Override
protected DeploymentStrategy delegate()
{
@@ -822,7 +821,10 @@
log.info("redeploying page descriptors...");
Pages pages = (Pages)
ServletLifecycle.getServletContext().getAttribute(Seam.getComponentName(Pages.class));
if (pages != null) {
-
pages.initialize(warRootDeploymentStrategy.getDotPageDotXmlFileNames());
+ // application context is needed for creating expressions
+ Lifecycle.mockApplication();
+
pages.initialize(warRootDeploymentStrategy.getDotPageDotXmlFileNames());
+ Lifecycle.unmockApplication();
}
ServletLifecycle.getServletContext().removeAttribute(Seam.getComponentName(Exceptions.class));
init.setWarTimestamp(warRootDeploymentStrategy.getTimestamp());
Modified: trunk/src/main/org/jboss/seam/mock/MockExternalContext.java
===================================================================
--- trunk/src/main/org/jboss/seam/mock/MockExternalContext.java 2008-12-01 21:40:20 UTC
(rev 9683)
+++ trunk/src/main/org/jboss/seam/mock/MockExternalContext.java 2008-12-01 21:41:20 UTC
(rev 9684)
@@ -80,6 +80,11 @@
this.request = request;
this.response = response;
}
+
+ public MockExternalContext(HttpServletRequest request)
+ {
+ this.request = request;
+ }
@Override
public void dispatch(String url) throws IOException
Modified: trunk/src/main/org/jboss/seam/navigation/Param.java
===================================================================
--- trunk/src/main/org/jboss/seam/navigation/Param.java 2008-12-01 21:40:20 UTC (rev
9683)
+++ trunk/src/main/org/jboss/seam/navigation/Param.java 2008-12-01 21:41:20 UTC (rev
9684)
@@ -63,6 +63,10 @@
else
{
Class<?> type = valueExpression.getType();
+ if (type==null)
+ {
+ return null;
+ }
return FacesContext.getCurrentInstance().getApplication().createConverter(type);
}
}
Added: trunk/src/test/unit/org/jboss/seam/test/unit/ExpressionsTest.java
===================================================================
--- trunk/src/test/unit/org/jboss/seam/test/unit/ExpressionsTest.java
(rev 0)
+++ trunk/src/test/unit/org/jboss/seam/test/unit/ExpressionsTest.java 2008-12-01 21:41:20
UTC (rev 9684)
@@ -0,0 +1,132 @@
+package org.jboss.seam.test.unit;
+
+import static org.testng.Assert.assertEquals;
+
+import java.beans.FeatureDescriptor;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import javax.el.PropertyNotFoundException;
+import javax.faces.application.Application;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseId;
+
+import org.jboss.seam.contexts.FacesLifecycle;
+import org.jboss.seam.core.Expressions;
+import org.jboss.seam.faces.FacesExpressions;
+import org.jboss.seam.mock.MockApplication;
+import org.jboss.seam.mock.MockExternalContext;
+import org.jboss.seam.mock.MockFacesContext;
+import org.jboss.seam.mock.MockHttpServletRequest;
+import org.jboss.seam.mock.MockHttpSession;
+import org.testng.annotations.Test;
+
+public class ExpressionsTest
+{
+ /**
+ * Validate that FacesExpressions reports that the FacesContext is activate and
+ * returns the Faces-aware EL context so that a Faces-specific expression can
+ * be resolved through Seam's built-in expression resolver.
+ * @jira JBSEAM-3674
+ */
+ @Test
+ public void testExpressionResolvedInFacesELContext()
+ {
+ Map<String, String> params = new HashMap<String, String>();
+ params.put("foo", "bar");
+ FacesContext facesContext = setupFacesContextToAccessRequestParams(params);
+ String expr = "#{param.foo}";
+
+ // the control
+ assertEquals(facesContext.getApplication().evaluateExpressionGet(facesContext,
expr, Object.class), "bar");
+
+ // the test
+ FacesLifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
+ Expressions expressions = new FacesExpressions();
+ assert expressions.getELContext().getContext(FacesContext.class) != null;
+ assertEquals(expressions.createValueExpression(expr).getValue(), "bar");
+ }
+
+ protected FacesContext setupFacesContextToAccessRequestParams(Map<String,
String> params)
+ {
+ MockHttpServletRequest request = new MockHttpServletRequest(new
MockHttpSession());
+ if (params != null)
+ {
+ for (Map.Entry<String, String> param : params.entrySet())
+ {
+ request.getParameterMap().put(param.getKey(), new String[] { param.getValue()
});
+ }
+ }
+ ExternalContext extContext = new MockExternalContext(request);
+ Application application = new MockApplication();
+ application.addELResolver(new ImplicitObjectELResolver());
+ FacesContext facesCtx = new MockFacesContext(extContext,
application).setCurrent();
+ assert FacesContext.getCurrentInstance() != null;
+ return facesCtx;
+ }
+
+ /**
+ * This resolver resolves select implicit objects that are available to the EL during
a Faces request.
+ * It must be implemented here since it is part of the JSF RI, not the API.
+ */
+ class ImplicitObjectELResolver extends ELResolver
+ {
+ private final String PARAM = "param";
+
+ private final String[] IMPLICIT_OBJECT_NAMES = new String[] { PARAM };
+
+ @Override
+ public Class<?> getCommonPropertyType(ELContext ctx, Object base)
+ {
+ return null;
+ }
+
+ @Override
+ public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext ctx,
Object base)
+ {
+ return null;
+ }
+
+ @Override
+ public Class<?> getType(ELContext ctx, Object base, Object prop)
+ {
+ return null;
+ }
+
+ @Override
+ public Object getValue(ELContext elCtx, Object base, Object prop)
+ {
+ if (base != null) return null;
+
+ if (prop == null) throw new PropertyNotFoundException("No such property
" + prop);
+
+ int idx = Arrays.binarySearch(IMPLICIT_OBJECT_NAMES, prop);
+ if (idx < 0) return null;
+
+ FacesContext facesCtx = (FacesContext) elCtx.getContext(FacesContext.class);
+ ExternalContext extCtx = facesCtx.getExternalContext();
+
+ if (prop.equals(PARAM))
+ {
+ elCtx.setPropertyResolved(true);
+ return extCtx.getRequestParameterMap();
+ }
+
+ throw new IllegalStateException("Programming error: list of possible
conditions is incomplete");
+ }
+
+ @Override
+ public boolean isReadOnly(ELContext ctx, Object base, Object prop)
+ {
+ return true;
+ }
+
+ @Override
+ public void setValue(ELContext ctx, Object base, Object prop, Object value) {}
+ }
+}
Modified: trunk/src/test/unit/org/jboss/seam/test/unit/PageParamTest.java
===================================================================
--- trunk/src/test/unit/org/jboss/seam/test/unit/PageParamTest.java 2008-12-01 21:40:20
UTC (rev 9683)
+++ trunk/src/test/unit/org/jboss/seam/test/unit/PageParamTest.java 2008-12-01 21:41:20
UTC (rev 9684)
@@ -1,17 +1,28 @@
package org.jboss.seam.test.unit;
+import java.util.HashMap;
+
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.IntegerConverter;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
+import org.jboss.seam.contexts.Lifecycle;
+import org.jboss.seam.core.Expressions;
+import org.jboss.seam.jsf.SeamApplication;
import org.jboss.seam.mock.MockApplication;
import org.jboss.seam.mock.MockExternalContext;
import org.jboss.seam.mock.MockFacesContext;
import org.jboss.seam.navigation.Param;
import org.testng.annotations.Test;
+/**
+ * Verifies that page parameters are setup properly and report the correct information
+ * about validators and converters.
+ *
+ * @author Dan Allen
+ */
public class PageParamTest
{
@Test
@@ -19,31 +30,51 @@
{
String converterId = "javax.faces.Integer";
String converterClass = "javax.faces.convert.IntegerConverter";
- MockFacesContext facesContext = new MockFacesContext(new MockExternalContext(), new
MockApplication());
- facesContext.setCurrent();
+ setupMockFacesContextWithSeamApplication();
Param param = new Param("param");
param.setConverterId(converterId);
assert param.getConverter() instanceof IntegerConverter : "expecting: " +
converterClass + "; got: " + param.getConverter();
}
+ /**
+ * Verify that converter is null when the parameter value is a value expression and
+ * we are operating outside of a FacesContext.
+ * @jira JBSEAM-3674
+ */
@Test
+ public void testConverterIsNullForNonFacesValueExpression()
+ {
+ setupMockFacesContextWithSeamApplication();
+ Param param = new Param("param");
+
param.setValueExpression(Expressions.instance().createValueExpression("#{variable}"));
+ Lifecycle.beginApplication(new HashMap<String, Object>());
+ Lifecycle.mockApplication();
+ assert param.getConverter() == null;
+ Lifecycle.endApplication();
+ }
+
+ @Test
public void testGetValidatorById() throws ClassNotFoundException
{
String validatorId = "TestValidator";
String validatorClass=
"org.jboss.seam.test.unit.PageParamTest$TestValidator";
- MockFacesContext facesContext = new MockFacesContext(new MockExternalContext(), new
MockApplication());
- facesContext.setCurrent();
+ FacesContext facesContext = setupMockFacesContextWithSeamApplication();
facesContext.getApplication().addValidator(validatorId, validatorClass);
Param param = new Param("param");
param.setValidatorId(validatorId);
assert param.getValidator() instanceof TestValidator : "expecting: " +
validatorClass + "; got: " + param.getValidator();
}
+ protected FacesContext setupMockFacesContextWithSeamApplication()
+ {
+ // MockApplication is wrapped with SeamApplication to validate the behavior Seam
introduces
+ return new MockFacesContext(new MockExternalContext(), new SeamApplication(new
MockApplication())).setCurrent();
+ }
+
public static class TestValidator implements Validator
{
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException
{
}
-
}
}