Author: tschneider Date: Fri Nov 9 18:47:29 2007 New Revision: 593725 URL: http://svn.apache.org/viewvc?rev=593725&view=rev Log: adding juel plugin as uel plugin
Added: struts/sandbox/trunk/struts2-uel-plugin/ struts/sandbox/trunk/struts2-uel-plugin/pom.xml struts/sandbox/trunk/struts2-uel-plugin/src/ struts/sandbox/trunk/struts2-uel-plugin/src/main/ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/CompoundRootELContext.java struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionContextFactory.java struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionProvider.java struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStack.java struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStackFactory.java struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/contextlistener/ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/contextlistener/UelServletContextListener.java struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/CompoundRootELResolver.java struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/XWorkBeanELResolver.java struts/sandbox/trunk/struts2-uel-plugin/src/main/resources/ struts/sandbox/trunk/struts2-uel-plugin/src/main/resources/struts-plugin.xml struts/sandbox/trunk/struts2-uel-plugin/src/test/ struts/sandbox/trunk/struts2-uel-plugin/src/test/java/ struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/ struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/apache/ struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/apache/struts2/ struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/apache/struts2/uelplugin/ struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/apache/struts2/uelplugin/UelTest.java Added: struts/sandbox/trunk/struts2-uel-plugin/pom.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/pom.xml?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/pom.xml (added) +++ struts/sandbox/trunk/struts2-uel-plugin/pom.xml Fri Nov 9 18:47:29 2007 @@ -0,0 +1,82 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.struts2juel</groupId> + <artifactId>struts2-uel-plugin</artifactId> + <packaging>jar</packaging> + <name>Struts 2 Unified EL Plugin</name> + <version>1.0.0-SNAPSHOT</version> + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.5</source> + <target>1.5</target> + </configuration> + </plugin> + </plugins> + </build> + <scm> + <connection> + scm:svn:https://svn.apache.org/repos/asf/struts/sandbox/trunk/struts2-uel-plugin + </connection> + <developerConnection> + scm:svn:https://svn.apache.org/repos/asf/struts/sandbox/trunk/struts2-uel-plugin + </developerConnection> + <url>http://https://svn.apache.org/repos/asf/struts/sandbox/trunk/struts2-uel-plugin</url> + </scm> + <dependencies> + <dependency> + <groupId>org.apache.struts</groupId> + <artifactId>struts2-core</artifactId> + <version>2.1.1-SNAPSHOT</version> + <exclusions> + <exclusion> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.4</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>de.odysseus.juel</groupId> + <artifactId>juel</artifactId> + <version>2.1.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jsp-2.1</artifactId> + <version>6.1.3</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>commons-beanutils</groupId> + <artifactId>commons-beanutils</artifactId> + <version>20030211.134440</version> + </dependency> + <dependency> + <groupId>commons-collections</groupId> + <artifactId>commons-collections</artifactId> + <version>20040616</version> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1</version> + <exclusions> + <exclusion> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </exclusion> + </exclusions> + </dependency> + </dependencies> +</project> \ No newline at end of file Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/CompoundRootELContext.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/CompoundRootELContext.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/CompoundRootELContext.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/CompoundRootELContext.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,51 @@ +package org.apache.struts2.uelplugin; + +import javax.el.ArrayELResolver; +import javax.el.CompositeELResolver; +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.FunctionMapper; +import javax.el.ListELResolver; +import javax.el.MapELResolver; +import javax.el.ResourceBundleELResolver; +import javax.el.VariableMapper; + +import org.apache.struts2.uelplugin.elresolvers.CompoundRootELResolver; +import org.apache.struts2.uelplugin.elresolvers.XWorkBeanELResolver; + + +/** + * An implementation of SimpleContext that knows about the ValueStack's + * CompoundRoot. + */ +public class CompoundRootELContext extends ELContext { + private ELResolver DEFAULT_RESOLVER_READ_WRITE; + + public CompoundRootELContext() { + DEFAULT_RESOLVER_READ_WRITE = new CompositeELResolver() { + { + add(new CompoundRootELResolver()); + add(new ArrayELResolver(false)); + add(new ListELResolver(false)); + add(new MapELResolver(false)); + add(new ResourceBundleELResolver()); + add(new XWorkBeanELResolver()); + } + }; + } + + @Override + public VariableMapper getVariableMapper() { + return null; + } + + @Override + public ELResolver getELResolver() { + return DEFAULT_RESOLVER_READ_WRITE; + } + + @Override + public FunctionMapper getFunctionMapper() { + return null; + } +} Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionContextFactory.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionContextFactory.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionContextFactory.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionContextFactory.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,15 @@ +package org.apache.struts2.uelplugin; + +import java.util.HashMap; +import java.util.Map; + +import com.opensymphony.xwork2.util.reflection.ReflectionContextFactory; + +/** + * ReflectionContextFactory for Unified EL. + */ +public class UelReflectionContextFactory implements ReflectionContextFactory { + public Map createDefaultContext(Object root) { + return new HashMap(); + } +} Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionProvider.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionProvider.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionProvider.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelReflectionProvider.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,58 @@ +package org.apache.struts2.uelplugin; + +import java.util.Map; + +import javax.el.ELContext; +import javax.el.ExpressionFactory; +import javax.el.ValueExpression; + +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.ognl.OgnlReflectionProvider; +import com.opensymphony.xwork2.util.CompoundRoot; +import com.opensymphony.xwork2.util.reflection.ReflectionException; + +/** + * A OgnlReflectionProvider based on Unified EL. + */ +public class UelReflectionProvider extends OgnlReflectionProvider { + private ExpressionFactory factory; + private XWorkConverter xworkConverter; + + @Inject + public void setXWorkConverter(XWorkConverter conv) { + this.xworkConverter = conv; + } + + public void initExpressionFactory() { + if (factory == null) { + factory = ExpressionFactory.newInstance(); + } + } + + @Override + public Object getValue(String expr, Map context, Object root) throws ReflectionException { + initExpressionFactory(); + CompoundRoot compoundRoot = new CompoundRoot(); + compoundRoot.add(root); + ELContext elContext = new CompoundRootELContext(); + elContext.putContext(XWorkConverter.class, xworkConverter); + // parse our expression + ValueExpression valueExpr = factory.createValueExpression(elContext, + expr, String.class); + return (String) valueExpr.getValue(elContext); + } + + @Override + public void setValue(String expr, Map context, Object root, Object value) throws ReflectionException { + initExpressionFactory(); + CompoundRoot compoundRoot = new CompoundRoot(); + compoundRoot.add(root); + ELContext elContext = new CompoundRootELContext(); + elContext.putContext(XWorkConverter.class, xworkConverter); + // parse our expression + ValueExpression valueExpr = factory.createValueExpression(elContext, + expr, String.class); + valueExpr.setValue(elContext, value); + } +} Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStack.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStack.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStack.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStack.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,168 @@ +package org.apache.struts2.uelplugin; + +import java.util.Map; +import java.util.TreeMap; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ExpressionFactory; +import javax.el.PropertyNotFoundException; +import javax.el.ValueExpression; + +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.util.CompoundRoot; +import com.opensymphony.xwork2.util.ValueStack; + +/** + * A ValueStack that uses Unified EL as the underlying Expression Language. + */ +public class UelValueStack implements ValueStack { + private CompoundRoot root = new CompoundRoot(); + private transient Map context; + private Class defaultType; + private Map overrides; + private XWorkConverter xworkConverter; + + private ExpressionFactory factory; + + private ELContext elContext; + + public UelValueStack(ExpressionFactory factory, + XWorkConverter xworkConverter) { + this(factory, xworkConverter, new CompoundRoot()); + } + + public UelValueStack(ExpressionFactory factory, + XWorkConverter xworkConverter, ValueStack vs) { + this(factory, xworkConverter, new CompoundRoot(vs.getRoot())); + } + + public UelValueStack(ExpressionFactory factory, + XWorkConverter xworkConverter, CompoundRoot root) { + this.xworkConverter = xworkConverter; + this.factory = factory; + setRoot(new CompoundRoot()); + } + + public String findString(String expr) { + return (String) findValue(expr, String.class); + } + + public Object findValue(String expr) { + return findValue(expr, Object.class); + } + + public Object findValue(String expr, Class asType) { + try { + if (expr != null && expr.startsWith("#") && !expr.startsWith("#{")) { + int firstDot = expr.indexOf('.'); + String key = expr.substring(1, firstDot); + String value = expr.substring(firstDot + 1); + Map map = (Map) context.get(key); + return map.get(value); + } + if ((overrides != null) && overrides.containsKey(expr)) { + expr = (String) overrides.get(expr); + } + if (expr != null && expr.startsWith("%{")) { + // replace %{ with ${ + expr = "#" + expr.substring(1); + } + if (expr != null && !expr.startsWith("${") + && !expr.startsWith("#{")) { + expr = "#{" + expr + "}"; + } + elContext.putContext(XWorkConverter.class, xworkConverter); + elContext.putContext(CompoundRoot.class, root); + // parse our expression + ValueExpression valueExpr = factory.createValueExpression( + elContext, expr, Object.class); + Object retVal = valueExpr.getValue(elContext); + if (!Object.class.equals(asType)) { + retVal = xworkConverter.convertValue(null, retVal, asType); + } + return retVal; + } catch (PropertyNotFoundException e) { + // property not found + return null; + } catch (ELException e) { + // fail silently so we don't mess things up + return null; + } + } + + public Map getContext() { + return context; + } + + public Map getExprOverrides() { + return overrides; + } + + public CompoundRoot getRoot() { + return root; + } + + public Object peek() { + return root.peek(); + } + + public Object pop() { + return root.pop(); + } + + public void push(Object o) { + root.push(o); + } + + public void setDefaultType(Class defaultType) { + this.defaultType = defaultType; + } + + public void setExprOverrides(Map overrides) { + if (this.overrides == null) { + this.overrides = overrides; + } else { + this.overrides.putAll(overrides); + } + } + + public void set(String key, Object o) { + overrides.put(key, o); + } + + public void setValue(String expr, Object value) { + setValue(expr, value, false); + } + + public void setValue(String expr, Object value, + boolean throwExceptionOnFailure) { + try { + if (expr != null && !expr.startsWith("${") + && !expr.startsWith("#{")) { + expr = "#{" + expr + "}"; + } + elContext.putContext(XWorkConverter.class, xworkConverter); + elContext.putContext(CompoundRoot.class, root); + // parse our expression + ValueExpression valueExpr = factory.createValueExpression( + elContext, expr, Object.class); + valueExpr.setValue(elContext, value); + } catch (ELException e) { + if (throwExceptionOnFailure) { + throw e; + } + } + } + + public int size() { + return root.size(); + } + + protected void setRoot(CompoundRoot root) { + this.context = new TreeMap(); + context.put(VALUE_STACK, this); + this.root = root; + elContext = new CompoundRootELContext(); + } +} Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStackFactory.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStackFactory.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStackFactory.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/UelValueStackFactory.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,38 @@ +package org.apache.struts2.uelplugin; + +import javax.el.ExpressionFactory; + +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.inject.Inject; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.ValueStackFactory; + +/** + * Creates JuelValueStacks. + */ +public class UelValueStackFactory implements ValueStackFactory { + private ExpressionFactory factory; + + private XWorkConverter xworkConverter; + + @Inject + public void setXWorkConverter(XWorkConverter conv) { + this.xworkConverter = conv; + } + + public void initExpressionFactory() { + if (factory == null) { + factory = ExpressionFactory.newInstance(); + } + } + + public ValueStack createValueStack() { + initExpressionFactory(); + return new UelValueStack(factory, xworkConverter); + } + + public ValueStack createValueStack(ValueStack stack) { + initExpressionFactory(); + return new UelValueStack(factory, xworkConverter, stack); + } +} Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/contextlistener/UelServletContextListener.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/contextlistener/UelServletContextListener.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/contextlistener/UelServletContextListener.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/contextlistener/UelServletContextListener.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,30 @@ +package org.apache.struts2.uelplugin.contextlistener; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.jsp.JspApplicationContext; +import javax.servlet.jsp.JspFactory; + +import org.apache.struts2.uelplugin.elresolvers.CompoundRootELResolver; +import org.apache.struts2.uelplugin.elresolvers.XWorkBeanELResolver; + + +/** + * Responsible for registering the ELResolvers. + */ +public class UelServletContextListener implements ServletContextListener { + + public void contextInitialized(ServletContextEvent contextEvent) { + ServletContext servletContext = contextEvent.getServletContext(); + JspApplicationContext jspApplicationContext = JspFactory + .getDefaultFactory().getJspApplicationContext(servletContext); + jspApplicationContext.addELResolver(new CompoundRootELResolver()); + jspApplicationContext.addELResolver(new XWorkBeanELResolver()); + contextEvent.getServletContext().log( + "CompoundRootELResolver and XWorkBeanELResolver registered"); + } + + public void contextDestroyed(ServletContextEvent contextEvent) { + } +} Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/CompoundRootELResolver.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/CompoundRootELResolver.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/CompoundRootELResolver.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/CompoundRootELResolver.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,203 @@ +package org.apache.struts2.uelplugin.elresolvers; + +import java.beans.BeanInfo; +import java.beans.FeatureDescriptor; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.el.ELContext; +import javax.el.ELResolver; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.beanutils.PropertyUtils; + +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.util.CompoundRoot; + +/** + * An ELResolver that is capable of resolving properties against the + * CompoundRoot if available in the ELContext. + */ +public class CompoundRootELResolver extends ELResolver { + + @Override + public Class<?> getCommonPropertyType(ELContext context, Object base) { + if (base == null) { + return null; + } + + return String.class; + } + + @Override + public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, + Object base) { + // only resolve at the root of the context + if (base != null) { + return null; + } + + CompoundRoot root = (CompoundRoot) context + .getContext(CompoundRoot.class); + if (root == null) { + return null; + } + + ArrayList<FeatureDescriptor> list = new ArrayList<FeatureDescriptor>(); + if (root.size() > 0) { + FeatureDescriptor descriptor = new FeatureDescriptor(); + descriptor.setValue("type", root.get(0).getClass()); + descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); + list.add(descriptor); + } + + for (Object bean : root) { + BeanInfo info = null; + try { + info = Introspector.getBeanInfo(base.getClass()); + } catch (Exception ex) { + } + if (info != null) { + for (PropertyDescriptor pd : info.getPropertyDescriptors()) { + pd.setValue("type", pd.getPropertyType()); + pd.setValue("resolvableAtDesignTime", Boolean.FALSE); + list.add(pd); + } + } + } + return list.iterator(); + } + + @Override + public Class<?> getType(ELContext context, Object base, Object property) { + // only resolve at the root of the context + if (base != null) { + return null; + } + + CompoundRoot root = (CompoundRoot) context + .getContext(CompoundRoot.class); + if (root == null) { + return null; + } + String propertyName = (String) property; + Object bean = findObjectForProperty(root, propertyName); + if (bean == null) { + return null; + } + try { + Class type = determineType(bean, propertyName); + context.setPropertyResolved(true); + return type; + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + @Override + public Object getValue(ELContext context, Object base, Object property) { + if (context == null) { + throw new NullPointerException(); + } + // only resolve at the root of the context + if (base != null) { + return null; + } + + CompoundRoot root = (CompoundRoot) context + .getContext(CompoundRoot.class); + if (root == null) { + return null; + } + String propertyName = (String) property; + if ("top".equals(propertyName) && root.size() > 0) { + return root.get(0); + } + try { + Object bean = findObjectForProperty(root, propertyName); + if (bean != null) { + Object retVal = PropertyUtils.getProperty(bean, propertyName); + context.setPropertyResolved(true); + return retVal; + } + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + return null; + } + + @Override + public boolean isReadOnly(ELContext context, Object base, Object property) { + if (context == null) { + throw new NullPointerException(); + } + + return false; + } + + @Override + public void setValue(ELContext context, Object base, Object property, + Object value) { + if (context == null) { + throw new NullPointerException(); + } + // only resolve at the root of the context + if (base != null) { + return; + } + + CompoundRoot root = (CompoundRoot) context + .getContext(CompoundRoot.class); + String propertyName = (String) property; + try { + if (base == null && property != null && root != null) { + Object bean = findObjectForProperty(root, propertyName); + if (bean != null) { + XWorkConverter converter = (XWorkConverter) context + .getContext(XWorkConverter.class); + if (converter != null && root != null) { + Class propType = determineType(bean, propertyName); + value = converter.convertValue(null, value, propType); + } + BeanUtils.setProperty(bean, propertyName, value); + context.setPropertyResolved(true); + } + } + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + protected Class<?> determineType(Object bean, String property) + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + return PropertyUtils.getPropertyType(bean, property); + } + + protected Object findObjectForProperty(CompoundRoot root, String propertyName) { + if ("top".equals(propertyName) && root.size() > 0) { + return root.get(0); + } + for (int i = 0; i < root.size(); i++) { + if (PropertyUtils.isReadable(root.get(i), propertyName) + || PropertyUtils.isWriteable(root.get(i), propertyName)) { + return root.get(i); + } + } + return null; + } +} Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/XWorkBeanELResolver.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/XWorkBeanELResolver.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/XWorkBeanELResolver.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/java/org/apache/struts2/uelplugin/elresolvers/XWorkBeanELResolver.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,57 @@ +package org.apache.struts2.uelplugin.elresolvers; + +import java.lang.reflect.InvocationTargetException; + +import javax.el.BeanELResolver; +import javax.el.ELContext; + +import org.apache.commons.beanutils.PropertyUtils; + +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; + +public class XWorkBeanELResolver extends BeanELResolver { + + public XWorkBeanELResolver() { + super(false); + } + + /** + * Re-implement this to always return Object. We don't want unified EL to do + * type conversion, we do that in the setter using xwork type conversion + * framework. + */ + @Override + public Class<?> getType(ELContext context, Object base, Object property) { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null || property == null) { + return null; + } + + context.setPropertyResolved(true); + return Object.class; + } + + @Override + public void setValue(ELContext context, Object base, Object property, + Object value) { + XWorkConverter converter = (XWorkConverter) context + .getContext(XWorkConverter.class); + try { + if (converter != null && base != null) { + Class propType = PropertyUtils.getPropertyType(base, property + .toString()); + value = converter.convertValue(null, value, propType); + } + super.setValue(context, base, property, value); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } +} Added: struts/sandbox/trunk/struts2-uel-plugin/src/main/resources/struts-plugin.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/main/resources/struts-plugin.xml?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/main/resources/struts-plugin.xml (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/main/resources/struts-plugin.xml Fri Nov 9 18:47:29 2007 @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<!DOCTYPE struts PUBLIC + "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" + "http://struts.apache.org/dtds/struts-2.0.dtd"> + +<struts> + <bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="uel" class=" org.apache.struts2.uelplugin.UelValueStackFactory" /> + <bean type="com.opensymphony.xwork2.util.reflection.ReflectionProvider" name="uel" class="org.apache.struts2.uelplugin.UelReflectionProvider" /> + <bean type="com.opensymphony.xwork2.util.reflection.ReflectionContextFactory" name="uel" class=" org.apache.struts2.uelplugin.UelReflectionContextFactory" /> + + <constant name="struts.valueStackFactory" value="uel" /> + <constant name="struts.reflectionProvider" value="uel" /> + <constant name="struts.reflectionContextFactory" value="uel" /> +</struts> \ No newline at end of file Added: struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/apache/struts2/uelplugin/UelTest.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/apache/struts2/uelplugin/UelTest.java?rev=593725&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/apache/struts2/uelplugin/UelTest.java (added) +++ struts/sandbox/trunk/struts2-uel-plugin/src/test/java/org/apache/struts2/uelplugin/UelTest.java Fri Nov 9 18:47:29 2007 @@ -0,0 +1,217 @@ +package org.apache.struts2.uelplugin; + +import java.lang.reflect.InvocationTargetException; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.el.ExpressionFactory; + +import org.apache.struts2.uelplugin.UelValueStack; +import org.apache.struts2.util.StrutsTypeConverter; + +import com.opensymphony.xwork2.XWorkTestCase; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.util.CompoundRoot; + +public class UelTest extends XWorkTestCase { + private ExpressionFactory factory = ExpressionFactory.newInstance(); + private XWorkConverter converter; + private DateFormat format = DateFormat.getDateInstance(); + + private class DateConverter extends StrutsTypeConverter { + + @Override + public Object convertFromString(Map context, String[] values, + Class toClass) { + try { + return format.parseObject(values[0]); + } catch (ParseException e) { + return null; + } + } + + @Override + public String convertToString(Map context, Object o) { + return format.format(o); + } + + } + + protected void setUp() throws Exception { + super.setUp(); + + converter = container.getInstance(XWorkConverter.class); + converter.registerConverter("java.util.Date", new DateConverter()); + } + + public void testBasicFind() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + root.add(obj); + UelValueStack stack = new UelValueStack(factory, converter); + stack.setRoot(root); + stack.setValue("${value}", "Hello World"); + String value = stack.findString("${value}"); + assertEquals("Hello World", value); + + stack.setValue("${age}", "56"); + String age = stack.findString("${age}"); + assertEquals("56", age); + } + + public void testSetStringArray() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + root.add(obj); + UelValueStack stack = new UelValueStack(factory, converter); + stack.setRoot(root); + stack.setValue("${value}", new String[] { "Hello World" }); + String value = stack.findString("${value}"); + assertEquals("Hello World", value); + + stack.setValue("${age}", new String[] { "67" }); + assertEquals(new Integer(67), stack.findValue("${age}")); + } + + public void testDeferredFind() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + root.add(obj); + + UelValueStack stack = new UelValueStack(factory, converter); + stack.setRoot(root); + stack.setValue("#{value}", "Hello World"); + String value = stack.findString("#{value}"); + assertEquals("Hello World", value); + + stack.setValue("#{age}", "56"); + String age = stack.findString("#{age}"); + assertEquals("56", age); + + stack.setValue("#{date}", new Date()); + assertEquals(stack.findString("#{date}"), format.format(obj.getDate())); + } + + public void testMap() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + HashMap map = new HashMap(); + map.put("nameValue", "Musachy"); + TestObject obj = new TestObject(); + obj.setParameters(map); + root.add(obj); + + UelValueStack stack = new UelValueStack(factory, converter); + stack.setRoot(root); + String value = (String) stack.findValue("parameters.nameValue", + String.class); + assertEquals("Musachy", value); + } + + public void test2LevelSet() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + TestObject nestedObj = new TestObject(); + obj.setInner(nestedObj); + root.add(obj); + UelValueStack stack = new UelValueStack(factory, converter); + stack.setRoot(root); + stack.setValue("${inner.age}", "66"); + assertEquals(66, obj.getInner().getAge()); + } + + public void testTypeConversion() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + TestObject inner = new TestObject(); + obj.setInner(inner); + root.add(obj); + UelValueStack stack = new UelValueStack(factory, converter); + stack.setRoot(root); + + stack.setValue("${age}", "22"); + assertEquals(stack.findValue("${age}"), obj.getAge()); + + stack.setValue("${inner.value}", "George"); + assertEquals(stack.findValue("${inner.value}"), obj.getInner() + .getValue()); + + stack.setValue("${inner.age}", "44"); + assertEquals(stack.findValue("${inner.age}"), obj.getInner().getAge()); + + stack.setValue("${date}", new Date()); + assertEquals(stack.findString("${date}"), format.format(obj.getDate())); + } + + public void testNotFound() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + CompoundRoot root = new CompoundRoot(); + TestObject obj = new TestObject(); + root.add(obj); + UelValueStack stack = new UelValueStack(factory, converter); + stack.setRoot(root); + stack.setValue("${value}", "Hello World"); + String value = stack.findString("${VALUENOTHERE}"); + assertNull(value); + + value = stack.findString("VALUENOTHERE"); + assertNull(value); + } + + public class TestObject { + private String value; + private int age; + private Date date; + private TestObject inner; + private Map parameters; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public TestObject getInner() { + return inner; + } + + public void setInner(TestObject inner) { + this.inner = inner; + } + + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + } +}