You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gr...@apache.org on 2009/06/13 19:45:24 UTC

svn commit: r784442 [4/4] - in /commons/proper/jexl/branches/2.0: ./ src/java/org/apache/commons/jexl/ src/java/org/apache/commons/jexl/logging/ src/java/org/apache/commons/jexl/parser/ src/java/org/apache/commons/jexl/util/ src/java/org/apache/commons...

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/MapGetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/MapGetExecutor.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/MapGetExecutor.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/MapGetExecutor.java Sat Jun 13 17:45:23 2009
@@ -1,81 +1,81 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.jexl.util;
-
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-
-
-/**
- * GetExecutor that is smart about Maps. If it detects one, it does not
- * use Reflection but a cast to access the getter.
- *
- * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
- * @version $Id$
- */
-public class MapGetExecutor extends AbstractExecutor {
-    /** the property to get. */
-    private final String property;
-
-    /**
-     * Create the instance.
-     * @param rlog the logger.
-     * @param clazz the class to execute the get on.
-     * @param aProperty the property or key to get.
-     */
-    public MapGetExecutor(final Log rlog, final Class clazz, final String aProperty) {
-        this.rlog = rlog;
-        this.property = aProperty;
-        discover(clazz);
-    }
-
-    /**
-     * Discover the method to call.
-     * @param clazz the class to find the method on.
-     */
-    protected void discover(final Class clazz) {
-        Class[] interfaces = clazz.getInterfaces();
-        for (int i = 0; i < interfaces.length; i++) {
-            if (interfaces[i].equals(Map.class)) {
-                try {
-                    if (property != null) {
-                        method = Map.class.getMethod("get", new Class[]{Object.class});
-                    }
-                    /**
-                     * pass through application level runtime exceptions
-                     */
-                } catch (RuntimeException e) {
-                    throw e;
-                } catch (Exception e) {
-                    rlog.error("While looking for get('" + property + "') method:", e);
-                }
-                break;
-            }
-        }
-    }
-
-    /** 
-     * Get the property from the map.
-     * @param o the map.
-     * @return o.get(property)
-     */
-    public Object execute(final Object o) {
-        return ((Map) o).get(property);
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.jexl.util;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+
+
+/**
+ * GetExecutor that is smart about Maps. If it detects one, it does not
+ * use Reflection but a cast to access the getter.
+ *
+ * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
+ * @version $Id$
+ */
+public class MapGetExecutor extends AbstractExecutor {
+    /** the property to get. */
+    private final String property;
+
+    /**
+     * Create the instance.
+     * @param rlog the logger.
+     * @param clazz the class to execute the get on.
+     * @param aProperty the property or key to get.
+     */
+    public MapGetExecutor(final Log rlog, final Class clazz, final String aProperty) {
+        this.rlog = rlog;
+        this.property = aProperty;
+        discover(clazz);
+    }
+
+    /**
+     * Discover the method to call.
+     * @param clazz the class to find the method on.
+     */
+    protected void discover(final Class clazz) {
+        Class[] interfaces = clazz.getInterfaces();
+        for (int i = 0; i < interfaces.length; i++) {
+            if (interfaces[i].equals(Map.class)) {
+                try {
+                    if (property != null) {
+                        method = Map.class.getMethod("get", new Class[]{Object.class});
+                    }
+                    /**
+                     * pass through application level runtime exceptions
+                     */
+                } catch (RuntimeException e) {
+                    throw e;
+                } catch (Exception e) {
+                        rlog.error("While looking for get('" + property + "') method:", e);
+                }
+                break;
+            }
+        }
+    }
+
+    /** 
+     * Get the property from the map.
+     * @param o the map.
+     * @return o.get(property)
+     */
+    public Object execute(final Object o) {
+        return ((Map) o).get(property);
+    }
+}

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/PropertyExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/PropertyExecutor.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/PropertyExecutor.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/PropertyExecutor.java Sat Jun 13 17:45:23 2009
@@ -26,7 +26,8 @@
  * @since 1.0
  */
 public class PropertyExecutor extends AbstractExecutor {
-
+    /* Empty param list. */
+    protected static final Object[] EMPTY_PARAMS = {};
     /** index of the first character of the property. */
     private static final int PROPERTY_START_INDEX = 3;
     /** The JEXL introspector used. */
@@ -64,21 +65,17 @@
 
         try {
             char c;
-            StringBuffer sb;
-
-            Object[] params = {};
-
             /*
              *  start with get<property>
              *  this leaves the property name
              *  as is...
              */
-            sb = new StringBuffer("get");
+            StringBuilder sb = new StringBuilder("get");
             sb.append(property);
 
             methodUsed = sb.toString();
 
-            method = introspector.getMethod(clazz, methodUsed, params);
+            method = introspector.getMethod(clazz, methodUsed, EMPTY_PARAMS);
 
             if (method != null) {
                 return;
@@ -97,7 +94,7 @@
             }
 
             methodUsed = sb.toString();
-            method = introspector.getMethod(clazz, methodUsed, params);
+            method = introspector.getMethod(clazz, methodUsed, EMPTY_PARAMS);
 
             if (method != null) {
                 return;
@@ -108,7 +105,7 @@
         } catch (RuntimeException e) {
             throw e;
         } catch (Exception e) {
-            rlog.error("PROGRAMMER ERROR : PropertyExector() : " + e);
+                rlog.error("PROGRAMMER ERROR : PropertyExector() : ", e);
         }
     }
 
@@ -122,7 +119,7 @@
             return null;
         }
 
-        return method.invoke(o, null);
+        return method.invoke(o, (Object[])null);
     }
 }
 

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java Sat Jun 13 17:45:23 2009
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.commons.jexl.util.introspection;
 
 import java.lang.reflect.Method;
@@ -27,12 +26,11 @@
 
 import org.apache.commons.logging.Log;
 
-
 /**
  * Taken from the Velocity tree so we can be self-sufficient
  *
  * A cache of introspection information for a specific class instance. Keys
- * {@link Method} objects by a concatenation of the method name and
+ * {@link MethodKey} objects by an agregation of the method name and
  * the names of classes that make up the parameters.
  *
  * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
@@ -44,6 +42,7 @@
  * @since 1.0
  */
 public class ClassMap {
+
     /**
      * Class passed into the constructor used to as the basis for the Method map.
      */
@@ -106,11 +105,11 @@
         // until Velocity 1.4. As we always reflect all elements of the tree (that's what we have a cache for), we will
         // hit the public elements sooner or later because we reflect all the public elements anyway.
         //
-        List classesToReflect = new ArrayList();
+        List<Class> classesToReflect = new ArrayList<Class>();
 
         // Ah, the miracles of Java for(;;) ...
-        for (Class classToReflect = getCachedClass(); classToReflect != null; 
-        classToReflect = classToReflect.getSuperclass()) {
+        for (Class classToReflect = getCachedClass(); classToReflect != null;
+                classToReflect = classToReflect.getSuperclass()) {
             if (Modifier.isPublic(classToReflect.getModifiers())) {
                 classesToReflect.add(classToReflect);
             }
@@ -122,8 +121,8 @@
             }
         }
 
-        for (Iterator it = classesToReflect.iterator(); it.hasNext();) {
-            Class classToReflect = (Class) it.next();
+        for (Iterator<Class> it = classesToReflect.iterator(); it.hasNext();) {
+            Class classToReflect = it.next();
 
             try {
                 Method[] methods = classToReflect.getMethods();
@@ -143,10 +142,9 @@
                         }
                     }
                 }
-            }
-            catch (SecurityException se) // Everybody feels better with...
+            } catch (SecurityException se) // Everybody feels better with...
             {
-                if (rlog.isDebugEnabled()) {
+                if (rlog != null && rlog.isDebugEnabled()) {
                     rlog.debug("While accessing methods of " + classToReflect + ": ", se);
                 }
             }
@@ -158,34 +156,65 @@
      *
      * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
      * @version $Id$
+     * <p>
+     * It stores the association between:
+     *  a key made of a method name & an array of argument types. (@see MethodCache.MethodKey)
+     *  a method.
+     * </p>
+     * <p>
+     * Since the invocation of the associated method is dynamic, there is no need (nor way) to differentiate between
+     * foo(int,int) & foo(Integer,Integer) since in practise, only the latter form will be used through a call.
+     * This of course, applies to all 8 primitive types.
+     * </p>
+     * @version $Id$
      */
-    private static final class MethodCache {
-        private static final class CacheMiss {
-        }
-
-        private static final CacheMiss CACHE_MISS = new CacheMiss();
-
-        private static final Object OBJECT = new Object();
-
-        private static final Map convertPrimitives = new HashMap();
+    static class MethodCache {
 
+        /**
+         * A method that returns itself used as a marker for cache miss,
+         * allows the underlying cache map to be strongly typed.
+         */
+        public static Method CacheMiss() {
+            try {
+                return MethodCache.class.getMethod("CacheMiss");
+            } // this really cant make an error...
+            catch (Exception xio) {
+            }
+            return null;
+        }
+        private static final Method CACHE_MISS = CacheMiss();
+        private static final Map<Class, Class> convertPrimitives;
         static {
-            convertPrimitives.put(Boolean.TYPE, Boolean.class.getName());
-            convertPrimitives.put(Byte.TYPE, Byte.class.getName());
-            convertPrimitives.put(Character.TYPE, Character.class.getName());
-            convertPrimitives.put(Double.TYPE, Double.class.getName());
-            convertPrimitives.put(Float.TYPE, Float.class.getName());
-            convertPrimitives.put(Integer.TYPE, Integer.class.getName());
-            convertPrimitives.put(Long.TYPE, Long.class.getName());
-            convertPrimitives.put(Short.TYPE, Short.class.getName());
+            convertPrimitives = new HashMap<Class, Class>(13);
+            convertPrimitives.put(Boolean.TYPE, Boolean.class);
+            convertPrimitives.put(Byte.TYPE, Byte.class);
+            convertPrimitives.put(Character.TYPE, Character.class);
+            convertPrimitives.put(Double.TYPE, Double.class);
+            convertPrimitives.put(Float.TYPE, Float.class);
+            convertPrimitives.put(Integer.TYPE, Integer.class);
+            convertPrimitives.put(Long.TYPE, Long.class);
+            convertPrimitives.put(Short.TYPE, Short.class);
         }
 
+        /** Converts a primitive type to its corresponding class.
+         * <p>
+         * If the argument type is primitive then we want to convert our
+         * primitive type signature to the corresponding Object type so
+         * introspection for methods with primitive types will work
+         * correctly.
+         * </p>
+         */
+        static final Class primitiveClass(Class parm) {
+            // it is marginally faster to get from the map than call isPrimitive...
+            //if (!parm.isPrimitive()) return parm;
+            Class prim = convertPrimitives.get(parm);
+            return prim == null ? parm : prim;
+        }
         /**
          * Cache of Methods, or CACHE_MISS, keyed by method
          * name and actual arguments used to find it.
          */
-        private final Map cache = new HashMap();
-
+        private final Map<MethodKey, Method> cache = new HashMap<MethodKey, Method>();
         /**
          * Map of methods that are searchable according to method parameters to find a match
          */
@@ -193,114 +222,165 @@
 
         /**
          * Find a Method using the method name and parameter objects.
-         *
+         *<p>
          * Look in the methodMap for an entry.  If found,
          * it'll either be a CACHE_MISS, in which case we
          * simply give up, or it'll be a Method, in which
          * case, we return it.
-         *
+         *</p>
+         * <p>
          * If nothing is found, then we must actually go
          * and introspect the method from the MethodMap.
-         *
+         *</p>
          * @param name   The method name to look up.
          * @param params An array of parameters for the method.
          * @return A Method object representing the method to invoke or null.
          * @throws MethodMap.AmbiguousException When more than one method is a match for the parameters.
          */
-        public synchronized Method get(final String name, final Object[] params)
+        public Method get(final String name, final Object[] params)
                 throws MethodMap.AmbiguousException {
-            String methodKey = makeMethodKey(name, params);
+            return get(new MethodKey(name, params));
+        }
 
-            Object cacheEntry = cache.get(methodKey);
+        public Method get(final MethodKey methodKey)
+                throws MethodMap.AmbiguousException {
+            synchronized (methodMap) {
+                Method cacheEntry = cache.get(methodKey);
+                // We looked this up before and failed.
+                if (cacheEntry == CACHE_MISS) {
+                    return null;
+                }
+
+                if (cacheEntry == null) {
+                    try {
+                        // That one is expensive...
+                        cacheEntry = methodMap.find(methodKey);
+                        if (cacheEntry != null) {
+                            cache.put(methodKey, cacheEntry);
+                        } else {
+                            cache.put(methodKey, CACHE_MISS);
+                        }
+                    } catch (MethodMap.AmbiguousException ae) {
+                        // that's a miss :-)
+                        cache.put(methodKey, CACHE_MISS);
+                        throw ae;
+                    }
+                }
 
-            // We looked this up before and failed.
-            if (cacheEntry == CACHE_MISS) {
-                return null;
+                // Yes, this might just be null.
+                return cacheEntry;
             }
+        }
 
-            if (cacheEntry == null) {
-                try {
-                    // That one is expensive...
-                    cacheEntry = methodMap.find(name, params);
+        public void put(Method method) {
+            synchronized (methodMap) {
+                MethodKey methodKey = new MethodKey(method);
+                // We don't overwrite methods. Especially not if we fill the
+                // cache from defined class towards java.lang.Object because
+                // abstract methods in superclasses would else overwrite concrete
+                // classes further down the hierarchy.
+                if (cache.get(methodKey) == null) {
+                    cache.put(methodKey, method);
+                    methodMap.add(method);
                 }
-                catch (MethodMap.AmbiguousException ae) {
-                    /*
-                     *  that's a miss :-)
-                     */
-                    cache.put(methodKey, CACHE_MISS);
-                    throw ae;
-                }
-
-                cache.put(methodKey,
-                        (cacheEntry != null) ? cacheEntry : CACHE_MISS);
             }
+        }
+    }
 
-            // Yes, this might just be null.
+    /**
+     * A method key for the introspector cache:
+     * This replaces the original key scheme which used to build the key by concatenating the method name and parameters
+     * class names as one string with the exception that primitive types were converted to their object class equivalents.
+     * The key is still based on the same information, it is just wrapped in an object instead.
+     * Primitive type classes are converted to they object equivalent to make a key; int foo(int) and int foo(Integer) do
+     * generate the same key.
+     * A key can be constructed either from arguments (array of objects) or from parameters (array of class).
+     * Roughly 3x faster than string key to access the map & uses less memory.
+     */
+    static class MethodKey {
+        /** The hash code */
+        final int hash;
+        /** The method name. */
+        final String method;
+        /** The parameters. */
+        final Class[] params;
+        /** A marker for empty parameter list. */
+        static final Class[] NOARGS = new Class[0];
 
-            return (Method) cacheEntry;
+        /** Builds a MethodKey from a method.
+         *  Used to store information in the method map.
+         */
+        MethodKey(Method method) {
+            this(method.getName(), method.getParameterTypes());
         }
 
-        public synchronized void put(Method method) {
-            String methodKey = makeMethodKey(method);
-
-            // We don't overwrite methods. Especially not if we fill the
-            // cache from defined class towards java.lang.Object because
-            // abstract methods in superclasses would else overwrite concrete
-            // classes further down the hierarchy.
-            if (cache.get(methodKey) == null) {
-                cache.put(methodKey, method);
-                methodMap.add(method);
+        /** Builds a MethodKey from a method name and a set of arguments (objects).
+         *  Used to query the method map.
+         */
+        MethodKey(String method, Object[] args) {
+            // !! keep this in sync with the other ctor (hash code) !!
+            this.method = method;
+            int hash = this.method.hashCode();
+            final int size;
+            if (args != null && (size = args.length) > 0) {
+                this.params = new Class[size];
+                for (int p = 0; p < size; ++p) {
+                    // ctor(Object) : {
+                    Object arg = args[p];
+                    // no need to go thru primitive type conversion since these are objects
+                    Class parm = arg == null ? Object.class : arg.getClass();
+                    // }
+                    hash = (37 * hash) + parm.hashCode();
+                    this.params[p] = parm;
+                }
+            } else {
+                this.params = NOARGS;
             }
+            this.hash = hash;
         }
 
-        /**
-         * Make a methodKey for the given method using
-         * the concatenation of the name and the
-         * types of the method parameters.
-         *
-         * @param method to be stored as key
-         * @return key for ClassMap
+        /** Builds a MethodKey from a method name and a set of parameters (classes).
+         *  Used to store information in the method map. ( @see MethodKey#primitiveClass )
          */
-        private String makeMethodKey(final Method method) {
-            Class[] parameterTypes = method.getParameterTypes();
-
-            StringBuffer methodKey = new StringBuffer(method.getName());
-
-            for (int j = 0; j < parameterTypes.length; j++) {
-                /*
-                 * If the argument type is primitive then we want
-                 * to convert our primitive type signature to the
-                 * corresponding Object type so introspection for
-                 * methods with primitive types will work correctly.
-                 *
-                 * The lookup map (convertPrimitives) contains all eight
-                 * primitives (boolean, byte, char, double, float, int, long, short)
-                 * known to Java. So it should never return null for the key passed in.
-                 */
-                if (parameterTypes[j].isPrimitive()) {
-                    methodKey.append((String) convertPrimitives.get(parameterTypes[j]));
-                } else {
-                    methodKey.append(parameterTypes[j].getName());
+        MethodKey(String method, Class[] args) {
+            // !! keep this in sync with the other ctor (hash code) !!
+            this.method = method;
+            int hash = this.method.hashCode();
+            final int size;
+            if (args != null && (size = args.length) > 0) {
+                this.params = new Class[size];
+                for (int p = 0; p < size; ++p) {
+                    // ctor(Class): {
+                    Class parm = MethodCache.primitiveClass(args[p]);
+                    // }
+                    hash = (37 * hash) + parm.hashCode();
+                    this.params[p] = parm;
                 }
+            } else {
+                this.params = NOARGS;
             }
-
-            return methodKey.toString();
+            this.hash = hash;
         }
 
-        private String makeMethodKey(String method, Object[] params) {
-            StringBuffer methodKey = new StringBuffer().append(method);
-
-            for (int j = 0; j < params.length; j++) {
-                Object arg = params[j];
+        @Override
+        public int hashCode() {
+            return hash;
+        }
 
-                if (arg == null) {
-                    arg = OBJECT;
-                }
+        @Override
+        public boolean equals(Object arg) {
+            MethodKey key = (MethodKey) arg;
+            return method.equals(key.method) && java.util.Arrays.equals(params, key.params);
+        }
 
-                methodKey.append(arg.getClass().getName());
+        @Override
+        /** Compatible with original string key. */
+        public String toString() {
+            StringBuilder builder = new StringBuilder(method);
+            for (Class c : params) {
+                builder.append(c.getName());
             }
-
-            return methodKey.toString();
+            return builder.toString();
         }
     }
 }

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java Sat Jun 13 17:45:23 2009
@@ -99,7 +99,7 @@
              *  whoops.  Ambiguous.  Make a nice log message and return null...
              */
 
-            StringBuffer msg = new StringBuffer("Introspection Error : Ambiguous method invocation ")
+            StringBuilder msg = new StringBuilder("Introspection Error : Ambiguous method invocation ")
                 .append(name).append("( ");
 
             for (int i = 0; i < params.length; i++) {
@@ -112,7 +112,7 @@
 
             msg.append(") for class ").append(c.getName());
 
-            rlog.error(msg.toString());
+           if (rlog != null)  rlog.error(msg.toString());
         }
 
         return null;

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java Sat Jun 13 17:45:23 2009
@@ -59,15 +59,16 @@
 
     /**
      * Holds the method maps for the classes we know about, keyed by Class
+     * Made WeakHashMap so we wont prevent a class from being GCed.
      * object.
      */
-    protected final Map classMethodMaps = new HashMap();
+    protected final Map<Class, ClassMap> classMethodMaps = new java.util.WeakHashMap<Class, ClassMap>();
 
     /**
      * Holds the qualified class names for the classes we hold in the
      * classMethodMaps hash.
      */
-    private Set cachedClassNames = new HashSet();
+    private Set<String> cachedClassNames = new HashSet<String>();
 
     /**
      * Create the introspector.
@@ -104,8 +105,7 @@
         ClassMap classMap;
 
         synchronized (classMethodMaps) {
-            classMap = (ClassMap) classMethodMaps.get(c);
-
+            classMap = classMethodMaps.get(c);
             /*
              * if we don't have this, check to see if we have it by name. if so,
              * then we have a classloader change so dump our caches.
@@ -157,6 +157,6 @@
         /*
          * for speed, we can just make a new one and let the old one be GC'd
          */
-        cachedClassNames = new HashSet();
+        cachedClassNames = new HashSet<String>();
     }
 }

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java Sat Jun 13 17:45:23 2009
@@ -19,7 +19,7 @@
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.Hashtable;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -52,7 +52,7 @@
      * Keep track of all methods with the same name.
      */
     // CSOFF: VisibilityModifier
-    Map methodByNameMap = new Hashtable();
+    private Map<String, List<Method>> methodByNameMap = new HashMap<String, List<Method>>();
     // CSON: VisibilityModifier
 
     /**
@@ -61,13 +61,13 @@
      *
      * @param method the method.
      */
-    public void add(Method method) {
+    public synchronized void add(Method method) {
         String methodName = method.getName();
 
-        List l = get(methodName);
+        List<Method> l = methodByNameMap.get(methodName);
 
         if (l == null) {
-            l = new ArrayList();
+            l = new ArrayList<Method>();
             methodByNameMap.put(methodName, l);
         }
 
@@ -80,8 +80,8 @@
      * @param key the name.
      * @return List list of methods.
      */
-    public List get(String key) {
-        return (List) methodByNameMap.get(key);
+    public synchronized List<Method> get(String key) {
+        return methodByNameMap.get(key);
     }
 
     /**
@@ -115,27 +115,15 @@
     // CSOFF: RedundantThrows
     public Method find(String methodName, Object[] args)
             throws AmbiguousException {
-        List methodList = get(methodName);
+        return find(new ClassMap.MethodKey(methodName, args));
+    }
 
+    Method find(ClassMap.MethodKey methodKey) throws AmbiguousException {
+        List<Method> methodList = get(methodKey.method);
         if (methodList == null) {
             return null;
         }
-
-        int l = args.length;
-        Class[] classes = new Class[l];
-
-        for (int i = 0; i < l; ++i) {
-            Object arg = args[i];
-
-            /*
-             * if we are careful down below, a null argument goes in there
-             * so we can know that the null was passed to the method
-             */
-            classes[i] =
-                    arg == null ? null : arg.getClass();
-        }
-
-        return getMostSpecific(methodList, classes);
+        return getMostSpecific(methodList, methodKey.params);
     } // CSON: RedundantThrows
 
 
@@ -160,16 +148,16 @@
      * @return the most specific method.
      * @throws AmbiguousException if there is more than one.
      */
-    private static Method getMostSpecific(List methods, Class[] classes)
+    private static Method getMostSpecific(List<Method> methods, Class[] classes)
             throws AmbiguousException {
-        LinkedList applicables = getApplicables(methods, classes);
+        LinkedList<Method> applicables = getApplicables(methods, classes);
 
         if (applicables.isEmpty()) {
             return null;
         }
 
         if (applicables.size() == 1) {
-            return (Method) applicables.getFirst();
+            return applicables.getFirst();
         }
 
         /*
@@ -178,17 +166,17 @@
          * (the most specific method) otherwise we have ambiguity.
          */
 
-        LinkedList maximals = new LinkedList();
+        LinkedList<Method> maximals = new LinkedList<Method>();
 
-        for (Iterator applicable = applicables.iterator();
+        for (Iterator<Method> applicable = applicables.iterator();
              applicable.hasNext();) {
-            Method app = (Method) applicable.next();
+            Method app = applicable.next();
             Class[] appArgs = app.getParameterTypes();
             boolean lessSpecific = false;
 
-            for (Iterator maximal = maximals.iterator();
+            for (Iterator<Method> maximal = maximals.iterator();
                  !lessSpecific && maximal.hasNext();) {
-                Method max = (Method) maximal.next();
+                Method max = maximal.next();
 
                 // CSOFF: MissingSwitchDefault
                 switch (moreSpecific(appArgs, max.getParameterTypes())) {
@@ -223,7 +211,7 @@
             throw new AmbiguousException();
         }
 
-        return (Method) maximals.getFirst();
+        return maximals.getFirst();
     } // CSON: RedundantThrows
 
 
@@ -295,12 +283,11 @@
      *         formal and actual arguments matches, and argument types are assignable
      *         to formal types through a method invocation conversion).
      */
-    private static LinkedList getApplicables(List methods, Class[] classes) {
-        LinkedList list = new LinkedList();
-
-        for (Iterator imethod = methods.iterator(); imethod.hasNext();) {
-            Method method = (Method) imethod.next();
+    private static LinkedList<Method> getApplicables(List<Method> methods, Class[] classes) {
+        LinkedList<Method> list = new LinkedList<Method>();
 
+        for (Iterator<Method> imethod = methods.iterator(); imethod.hasNext();) {
+            Method method = imethod.next();
             if (isApplicable(method, classes)) {
                 list.add(method);
             }

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java Sat Jun 13 17:45:23 2009
@@ -33,6 +33,9 @@
      */
     void init();
 
+    /** Returns the underlying introspector. */
+    public Introspector getIntrospector();
+    
     /**
      * To support iteratives - #foreach().
      * @param info template info.

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java Sat Jun 13 17:45:23 2009
@@ -20,11 +20,9 @@
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.jexl.util.AbstractExecutor;
@@ -51,7 +49,10 @@
      * index of the first character of the property.
      */
     private static final int PROPERTY_START_INDEX = 3;
-
+    /*
+     * static signature for method(object,object)
+     */
+    static final Class[] OBJECT_OBJECT = { Object.class, Object.class };
     /**
      * Our runtime logger.
      */
@@ -62,6 +63,9 @@
      */
     private Introspector introspector;
 
+    public Introspector getIntrospector() {
+        return introspector;
+    }
     /**
      * init - does nothing - we need to have setRuntimeLogger called before
      * getting our introspector, as the default vel introspector depends upon
@@ -91,13 +95,13 @@
         } else if (obj instanceof Map) {
             return ((Map) obj).values().iterator();
         } else if (obj instanceof Iterator) {
-            rlog.warn("Warning! The iterative " + " is an Iterator in the #foreach() loop at [" + i.getLine() + ","
+                rlog.warn("Warning! The iterative " + " is an Iterator in the #foreach() loop at [" + i.getLine() + ","
                     + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable,"
                     + " if used in more than once, this may lead to" + " unexpected results.");
 
             return ((Iterator) obj);
         } else if (obj instanceof Enumeration) {
-            rlog.warn("Warning! The iterative " + " is an Enumeration in the #foreach() loop at [" + i.getLine() + ","
+                rlog.warn("Warning! The iterative " + " is an Enumeration in the #foreach() loop at [" + i.getLine() + ","
                     + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable,"
                     + " if used in more than once, this may lead to" + " unexpected results.");
 
@@ -108,10 +112,10 @@
             // foreach without implementing the Collection interface
             Class type = obj.getClass();
             try {
-                Method iter = type.getMethod("iterator", null);
+                Method iter = type.getMethod("iterator", (Class[]) null);
                 Class returns = iter.getReturnType();
                 if (Iterator.class.isAssignableFrom(returns)) {
-                    return (Iterator) iter.invoke(obj, null);
+                    return (Iterator) iter.invoke(obj, (Object[])null);
                 } else {
                     rlog.error("iterator() method of reference in #foreach loop at "
                             + i + " does not return a true Iterator.");
@@ -129,7 +133,7 @@
         }
 
         /*  we have no clue what this is  */
-        rlog.warn("Could not determine type of iterator in " + "#foreach loop " + " at [" + i.getLine() + ","
+            rlog.warn("Could not determine type of iterator in " + "#foreach loop " + " at [" + i.getLine() + ","
                 + i.getColumn() + "]" + " in template " + i.getTemplateName());
 
         return null;
@@ -221,7 +225,7 @@
                     throw new NoSuchMethodException();
                 }
             } catch (NoSuchMethodException nsme2) {
-                StringBuffer sb = new StringBuffer("set");
+                StringBuilder sb = new StringBuilder("set");
                 sb.append(identifier);
 
                 if (Character.isLowerCase(sb.charAt(PROPERTY_START_INDEX))) {
@@ -242,10 +246,7 @@
              */
 
             if (Map.class.isAssignableFrom(claz)) {
-                Object[] params = {new Object(), new Object()};
-
-                vm = getMethod(obj, "put", params, i);
-
+                vm = getMethod(obj, "put", OBJECT_OBJECT, i);
                 if (vm != null) {
                     return new VelSetterImpl(vm, identifier);
                 }
@@ -494,16 +495,13 @@
          * {@inheritDoc}
          */
         public Object invoke(Object o, Object value) throws Exception {
-            List al = new ArrayList();
-
             if (putKey == null) {
-                al.add(value);
+                Object[] a0 = { value };
+                return vm.invoke(o, a0);
             } else {
-                al.add(putKey);
-                al.add(value);
+                Object[] a1 = { putKey, value };
+                return vm.invoke(o, a1);
             }
-
-            return vm.invoke(o, al.toArray());
         }
 
         /**

Added: commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/AssignTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/AssignTest.java?rev=784442&view=auto
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/AssignTest.java (added)
+++ commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/AssignTest.java Sat Jun 13 17:45:23 2009
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl;
+
+import junit.framework.TestCase;
+
+/**
+ * Test cases for the if statement.
+ * 
+ * @author Dion Gillard
+ * @since 1.1
+ */
+public class AssignTest extends TestCase {
+    static JexlEngine JEXL = new JexlEngine();
+    static {
+        JEXL.setSilent(false);
+    }
+    
+    public static class Froboz {
+        int value;
+        public Froboz(int v) {
+            value = v;
+        }
+        public void setValue(int v) {
+            value = v;
+        }
+        public int getValue() {
+            return value;
+        }
+    }
+    
+    public static class Quux {
+        String str;
+        Froboz froboz;
+        public Quux(String str, int fro) {
+            this.str = str;
+            froboz = new Froboz(fro);
+        }
+        
+        public Froboz getFroboz() {
+            return froboz;
+        }
+        
+        public void setFroboz(Froboz froboz) {
+            this.froboz = froboz;
+        }
+        
+        public String getStr() {
+            return str;
+        }
+        
+        public void setStr(String str) {
+            this.str = str;
+        }
+    }
+
+    public AssignTest(String testName) {
+        super(testName);
+    }
+
+    /**
+     * Make sure bean assignment works
+     * 
+     * @throws Exception on any error
+     */
+    public void testAntish() throws Exception {
+        Expression assign = JEXL.createExpression("froboz.value = 10");
+        Expression check = JEXL.createExpression("froboz.value");
+        JexlContext jc = JexlHelper.createContext();
+        Object o = assign.evaluate(jc);
+        assertEquals("Result is not 10", new Integer(10), o);
+        o = check.evaluate(jc);
+        assertEquals("Result is not 10", new Integer(10), o);
+    }
+    
+    public void testBeanish() throws Exception {
+        Expression assign = JEXL.createExpression("froboz.value = 10");
+        Expression check = JEXL.createExpression("froboz.value");
+        JexlContext jc = JexlHelper.createContext();
+        Froboz froboz = new Froboz(-169);
+        jc.getVars().put("froboz", froboz);
+        Object o = assign.evaluate(jc);
+        assertEquals("Result is not 10", new Integer(10), o);
+        o = check.evaluate(jc);
+        assertEquals("Result is not 10", new Integer(10), o);
+    }
+    
+    public void testAmbiguous() throws Exception {
+        Expression assign = JEXL.createExpression("froboz.nosuchbean = 10");
+        JexlContext jc = JexlHelper.createContext();
+        Froboz froboz = new Froboz(-169);
+        jc.getVars().put("froboz", froboz);
+        Object o = null;
+        try {
+            o = assign.evaluate(jc);
+        }
+        catch(RuntimeException xrt) {
+            String str = xrt.toString();
+            return;
+        }
+        finally {
+        assertEquals("Should have failed", null, o);
+        }
+    }
+        
+    public void testArray() throws Exception {
+        Expression assign = JEXL.createExpression("froboz[\"value\"] = 10");
+        Expression check = JEXL.createExpression("froboz[\"value\"]");
+        System.out.print(assign.dump());
+        JexlContext jc = JexlHelper.createContext();
+        Froboz froboz = new Froboz(0);
+        jc.getVars().put("froboz", froboz);
+        Object o = assign.evaluate(jc);
+        assertEquals("Result is not 10", new Integer(10), o);
+        o = check.evaluate(jc);
+        assertEquals("Result is not 10", new Integer(10), o);
+    }
+    
+    public void testMore() throws Exception {
+        Expression assign = JEXL.createExpression("quux.froboz.value = 10");
+        Expression check = JEXL.createExpression("quux[\"froboz\"].value");
+        JexlContext jc = JexlHelper.createContext();
+        jc.getVars().put("quux", new Quux("xuuq", 100));
+        Object o = assign.evaluate(jc);
+        assertEquals("Result is not 10", new Integer(10), o);
+        o = check.evaluate(jc);
+        assertEquals("Result is not 10", new Integer(10), o);
+    }
+    
+    
+    public void testTernary() throws Exception {
+        JexlContext jc = JexlHelper.createContext();
+        Expression e = JEXL.createExpression("x.y.z = foo ?'bar':'quux'");
+        String canonical = e.dump();
+        System.out.print(canonical);
+        Object o = e.evaluate(jc);
+        assertEquals("Should be quux", "quux", o);
+        jc.getVars().put("foo",true);
+        o = e.evaluate(jc);
+        assertEquals("Should be bar", "bar", o);
+        o = jc.getVars().get("x.y.z");
+        assertEquals("Should be bar", "bar", o);
+    }
+    
+    public void testNotNull() throws Exception {
+        JexlContext jc = JexlHelper.createContext();
+        Expression e = JEXL.createExpression("x.y.z = foo?:'quux'");
+        Object o = e.evaluate(jc);
+        assertEquals("Should be quux", "quux", o);
+        jc.getVars().put("foo","bar");
+        o = e.evaluate(jc);
+        assertEquals("Should be bar", "bar", o);
+        o = jc.getVars().get("x.y.z");
+        assertEquals("Should be bar", "bar", o);
+    }
+    
+    public static void main(String[] args) throws Exception {
+        new AssignTest("debug").testAmbiguous();
+        //new AssignTest("debug").testArray();
+    }
+}
\ No newline at end of file

Modified: commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/BlockTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/BlockTest.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/BlockTest.java (original)
+++ commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/BlockTest.java Sat Jun 13 17:45:23 2009
@@ -82,5 +82,8 @@
         Object o = e.evaluate(jc);
         assertEquals("Block result is wrong", "world", o);
     }
-
+    public static void main(String[] args) throws Exception {
+        new BlockTest("debug").testBlockExecutesAll();
+        //new AssignTest("debug").testArray();
+    }
 }

Modified: commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/JexlTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/JexlTest.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/JexlTest.java (original)
+++ commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/JexlTest.java Sat Jun 13 17:45:23 2009
@@ -551,14 +551,8 @@
 
         assertExpression(jc, "foo.substring(2,4)", "cd");
         assertExpression(jc, "foo.charAt(2)", new Character('c'));
-
-        try {
             assertExpression(jc, "foo.charAt(-2)", null);
-            fail("this test should have thrown an exception" );
-        }
-        catch (Exception e) {
-            // expected behaviour
-        }
+
     }
 
     public void testEmptyDottedVariableName() throws Exception

Modified: commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ParseFailuresTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ParseFailuresTest.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ParseFailuresTest.java (original)
+++ commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ParseFailuresTest.java Sat Jun 13 17:45:23 2009
@@ -1,102 +1,102 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.jexl;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.jexl.parser.ParseException;
-
-/**
- * Tests for malformed expressions and scripts.
- * ({@link ExpressionFactory} and {@link ScriptFactory} should throw
- * {@link ParseException}s).
- *
- * @since 1.1
- */
-public class ParseFailuresTest extends TestCase {
-
-    /**
-     * Create the test.
-     *
-     * @param testName name of the test
-     */
-    public ParseFailuresTest(String testName) {
-        super(testName);
-    }
-
-    public void testMalformedExpression1() throws Exception {
-        // this will throw a ParseException
-        String badExpression = "eq";
-        try {
-            ExpressionFactory.createExpression(badExpression);
-            fail("Parsing \"" + badExpression
-                + "\" should result in a ParseException");
-        } catch (ParseException pe) {
-            // expected
-        }
-    }
-
-    public void testMalformedExpression2() throws Exception {
-        // this will throw a TokenMgrErr, which we rethrow as a ParseException
-        String badExpression = "?";
-        try {
-            ExpressionFactory.createExpression(badExpression);
-            fail("Parsing \"" + badExpression
-                + "\" should result in a ParseException");
-        } catch (ParseException pe) {
-            // expected
-        }
-    }
-
-    public void testMalformedScript1() throws Exception {
-        // this will throw a TokenMgrErr, which we rethrow as a ParseException
-        String badScript = "eq";
-        try {
-            ScriptFactory.createScript(badScript);
-            fail("Parsing \"" + badScript
-                + "\" should result in a ParseException");
-        } catch (ParseException pe) {
-            // expected
-        }
-    }
-
-
-    public void testMalformedScript2() throws Exception {
-        // this will throw a TokenMgrErr, which we rethrow as a ParseException
-        String badScript = "?";
-        try {
-            ScriptFactory.createScript(badScript);
-            fail("Parsing \"" + badScript
-                + "\" should result in a ParseException");
-        } catch (ParseException pe) {
-            // expected
-        }
-    }
-
-    public void testMalformedScript3() throws Exception {
-        // this will throw a TokenMgrErr, which we rethrow as a ParseException
-        String badScript = "foo=1;bar=2;a?b:c;";
-        try {
-            ScriptFactory.createScript(badScript);
-            fail("Parsing \"" + badScript
-                + "\" should result in a ParseException");
-        } catch (ParseException pe) {
-            // expected
-        }
-    }
-
-}
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.jexl.parser.ParseException;
+
+/**
+ * Tests for malformed expressions and scripts.
+ * ({@link ExpressionFactory} and {@link ScriptFactory} should throw
+ * {@link ParseException}s).
+ *
+ * @since 1.1
+ */
+public class ParseFailuresTest extends TestCase {
+
+    /**
+     * Create the test.
+     *
+     * @param testName name of the test
+     */
+    public ParseFailuresTest(String testName) {
+        super(testName);
+    }
+
+    public void testMalformedExpression1() throws Exception {
+        // this will throw a ParseException
+        String badExpression = "eq";
+        try {
+            ExpressionFactory.createExpression(badExpression);
+            fail("Parsing \"" + badExpression
+                + "\" should result in a ParseException");
+        } catch (ParseException pe) {
+            // expected
+        }
+    }
+
+    public void testMalformedExpression2() throws Exception {
+        // this will throw a TokenMgrErr, which we rethrow as a ParseException
+        String badExpression = "?";
+        try {
+            ExpressionFactory.createExpression(badExpression);
+            fail("Parsing \"" + badExpression
+                + "\" should result in a ParseException");
+        } catch (ParseException pe) {
+            // expected
+        }
+    }
+
+    public void testMalformedScript1() throws Exception {
+        // this will throw a TokenMgrErr, which we rethrow as a ParseException
+        String badScript = "eq";
+        try {
+            ScriptFactory.createScript(badScript);
+            fail("Parsing \"" + badScript
+                + "\" should result in a ParseException");
+        } catch (ParseException pe) {
+            // expected
+        }
+    }
+
+
+    public void testMalformedScript2() throws Exception {
+        // this will throw a TokenMgrErr, which we rethrow as a ParseException
+        String badScript = "?";
+        try {
+            ScriptFactory.createScript(badScript);
+            fail("Parsing \"" + badScript
+                + "\" should result in a ParseException");
+        } catch (ParseException pe) {
+            // expected
+        }
+    }
+
+    public void testMalformedScript3() throws Exception {
+        // this will throw a TokenMgrErr, which we rethrow as a ParseException
+        String badScript = "foo=1;bar=2;a?b:c:d;";
+        try {
+            ScriptFactory.createScript(badScript);
+            fail("Parsing \"" + badScript
+                + "\" should result in a ParseException");
+        } catch (ParseException pe) {
+            // expected
+        }
+    }
+
+}

Modified: commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ScriptFactoryTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ScriptFactoryTest.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ScriptFactoryTest.java (original)
+++ commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ScriptFactoryTest.java Sat Jun 13 17:45:23 2009
@@ -26,7 +26,7 @@
  * @since 1.1
  */
 public class ScriptFactoryTest extends TestCase {
-
+    static final String TEST1 = "src/test-scripts/test1.jexl";
     /**
      * Creates a new test case.
      * @param name the test case name.
@@ -72,7 +72,7 @@
      * @throws Exception on a parse error.
      */
     public void testCreateFromFile() throws Exception {
-        File testScript = new File("src/test-scripts/test1.jexl");
+        File testScript = new File(TEST1);
         assertNotNull("No script created", ScriptFactory.createScript(testScript));
     }
 

Modified: commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ScriptTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ScriptTest.java?rev=784442&r1=784441&r2=784442&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ScriptTest.java (original)
+++ commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/ScriptTest.java Sat Jun 13 17:45:23 2009
@@ -26,6 +26,7 @@
  * @since 1.1
  */
 public class ScriptTest extends TestCase {
+    static final String TEST1 =  "src/test-scripts/test1.jexl";
 
     // test class for testScriptUpdatesContext
     // making this class private static will cause the test to fail.
@@ -64,7 +65,7 @@
     }
     
     public void testScriptFromFile() throws Exception {
-        File testScript = new File("src/test-scripts/test1.jexl");
+        File testScript = new File(TEST1);
         Script s = ScriptFactory.createScript(testScript);
         JexlContext jc = JexlHelper.createContext();
         jc.getVars().put("out", System.out);

Added: commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/util/introspection/MethodKeyTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/util/introspection/MethodKeyTest.java?rev=784442&view=auto
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/util/introspection/MethodKeyTest.java (added)
+++ commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/util/introspection/MethodKeyTest.java Sat Jun 13 17:45:23 2009
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl.util.introspection;
+import junit.framework.TestCase;
+/**
+ * Checks the CacheMap.MethodKey implementation
+ */
+public class MethodKeyTest extends TestCase {
+    // A set of classes (most of them primitives)
+    static Class[] PRIMS = {
+        Boolean.TYPE,
+        Byte.TYPE,
+        Character.TYPE,
+        Double.TYPE,
+        Float.TYPE,
+        Integer.TYPE,
+        Long.TYPE,
+        Short.TYPE,
+        String.class,
+        java.util.Date.class
+    };
+    
+    // A set of instances corresponding to the classes
+    static Object[] ARGS = {
+        new Boolean(true),
+        new Byte((byte) 1),
+        new Character('2'),
+        new Double(4d),
+        new Float(8f),
+        new Integer(16),
+        new Long(32l),
+        new Short((short)64),
+        "foobar",
+        new java.util.Date()
+    };
+    
+    // A set of (pseudo) method names
+    static String[] METHODS = {
+        "plus",
+        "minus",
+        "execute",
+        "activate",
+        "perform",
+        "apply",
+        "invoke",
+        "executeAction",
+        "activateAction",
+        "performAction",
+        "applyAction",
+        "invokeAction",
+        "executeFunctor",
+        "activateFunctor",
+        "performFunctor",
+        "applyFunctor",
+        "invokeFunctor",
+        "executeIt",
+        "activateIt",
+        "performIt",
+        "applyIt",
+        "invokeIt"
+    };
+    
+    /** from key to string */
+    static java.util.Map<ClassMap.MethodKey, String> byKey;
+    /** form string to key */
+    static java.util.Map<String, ClassMap.MethodKey> byString;
+    /** the list of keys we generated & test against */
+    static ClassMap.MethodKey[] keyList;
+    
+    /** Creates & inserts a key into the byKey & byString map */
+    static void setUpKey(String name, Class[] parms) {
+        ClassMap.MethodKey key = new ClassMap.MethodKey(name, parms);
+        String str = key.toString();
+        byKey.put(key, str);
+        byString.put(str, key);
+        
+    }
+
+    /** Generate a list of method*(prims*), method(prims*, prims*), method*(prims*,prims*,prims*) */
+    static {
+        byKey = new java.util.HashMap<ClassMap.MethodKey, String>();
+        byString = new java.util.HashMap<String, ClassMap.MethodKey>();
+        for (int m = 0; m < METHODS.length; ++m) {
+            String method = METHODS[m];
+            for (int p0 = 0; p0 < PRIMS.length; ++p0) {
+                Class[] arg0 = {PRIMS[p0]};
+                setUpKey(method, arg0);
+                for (int p1 = 0; p1 < PRIMS.length; ++p1) {
+                    Class[] arg1 = {PRIMS[p0], PRIMS[p1]};
+                    setUpKey(method, arg1);
+                    for (int p2 = 0; p2 < PRIMS.length; ++p2) {
+                        Class[] arg2 = {PRIMS[p0], PRIMS[p1], PRIMS[p2]};
+                        setUpKey(method, arg2);
+                    }
+                }
+            }
+        }
+        keyList = byKey.keySet().toArray(new ClassMap.MethodKey[byKey.size()]);
+    }
+
+    /** Builds a string key */
+    String makeStringKey(String method, Class... params) {
+            StringBuilder builder = new StringBuilder(method);
+            for(int p = 0; p < params.length; ++p) {
+                builder.append(ClassMap.MethodCache.primitiveClass(params[p]).getName());
+            }
+            return builder.toString();
+    }
+    
+    /** Checks that a string key does exist */
+    void checkStringKey(String method, Class... params) {
+        String key = makeStringKey(method, params);
+        ClassMap.MethodKey out = byString.get(key);
+        assertTrue(out != null);
+    }
+        
+    /** Builds a method key */
+    ClassMap.MethodKey makeKey(String method, Class... params) {
+        return new ClassMap.MethodKey(method, params);
+    }
+    
+    /** Checks that a method key exists */
+    void checkKey(String method, Class... params) {
+        ClassMap.MethodKey key = makeKey(method, params);
+        String out = byKey.get(key);
+        assertTrue(out != null);
+    }
+    
+    public void testObjectKey() throws Exception {
+        for(int k = 0; k < keyList.length; ++k) {
+            ClassMap.MethodKey ctl = keyList[k];
+            ClassMap.MethodKey key = makeKey(ctl.method, ctl.params);
+            String out = byKey.get(key);
+            assertTrue(out != null);
+            assertTrue(ctl.toString() + " != " + out, ctl.toString().equals(out));
+        }
+        
+    }
+    
+    public void testStringKey() throws Exception {
+        for(int k = 0; k < keyList.length; ++k) {
+            ClassMap.MethodKey ctl = keyList[k];
+            String key = makeStringKey(ctl.method, ctl.params);
+            ClassMap.MethodKey out = byString.get(key);
+            assertTrue(out != null);
+            assertTrue(ctl.toString() + " != " + key, ctl.equals(out));
+        }
+        
+    }
+    
+    static final int LOOP = 300;
+    
+    public void testPerfKey() throws Exception {
+        for(int l = 0; l < LOOP; ++l)
+        for(int k = 0; k < keyList.length; ++k) {
+            ClassMap.MethodKey ctl = keyList[k];
+            ClassMap.MethodKey key = makeKey(ctl.method, ctl.params);
+            String out = byKey.get(key);
+            assertTrue(out != null);
+        }
+    }
+    
+    public void testPerfString() throws Exception {
+        for(int l = 0; l < LOOP; ++l)
+        for(int k = 0; k < keyList.length; ++k) {
+            ClassMap.MethodKey ctl = keyList[k];
+            String key = makeStringKey(ctl.method, ctl.params);
+            ClassMap.MethodKey out = byString.get(key);
+            assertTrue(out != null);
+        }
+    }
+    
+    public void testPerfKey2() throws Exception {
+        for(int l = 0; l < LOOP; ++l)
+        for (int m = 0; m < METHODS.length; ++m) {
+            String method = METHODS[m];
+            for (int p0 = 0; p0 < ARGS.length; ++p0) {
+                checkKey(method, ARGS[p0].getClass());
+                for (int p1 = 0; p1 < ARGS.length; ++p1) {
+                    checkKey(method, ARGS[p0].getClass(), ARGS[p1].getClass());
+                    for (int p2 = 0; p2 < ARGS.length; ++p2) {
+                        checkKey(method, ARGS[p0].getClass(), ARGS[p1].getClass(), ARGS[p2].getClass());
+                    }
+                }
+            }
+        }
+    }
+    
+    public void testPerfStringKey2() throws Exception {
+        for(int l = 0; l < LOOP; ++l)
+        for (int m = 0; m < METHODS.length; ++m) {
+            String method = METHODS[m];
+            for (int p0 = 0; p0 < ARGS.length; ++p0) {
+                checkStringKey(method, ARGS[p0].getClass());
+                for (int p1 = 0; p1 < ARGS.length; ++p1) {
+                    checkStringKey(method,  ARGS[p0].getClass(), ARGS[p1].getClass());
+                    for (int p2 = 0; p2 < ARGS.length; ++p2) {
+                        checkStringKey(method, ARGS[p0].getClass(), ARGS[p1].getClass(), ARGS[p2].getClass());
+                    }
+                }
+            }
+        }
+    }
+}