You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ge...@apache.org on 2002/08/05 07:04:53 UTC

cvs commit: jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection ClassMap.java Info.java Introspector.java IntrospectorBase.java MethodMap.java Uberspect.java UberspectImpl.java UberspectLoggable.java VelMethod.java VelPropertyGet.java VelPropertySet.java

geirm       2002/08/04 22:04:53

  Added:       jexl/src/java/org/apache/commons/jexl/util/introspection
                        ClassMap.java Info.java Introspector.java
                        IntrospectorBase.java MethodMap.java Uberspect.java
                        UberspectImpl.java UberspectLoggable.java
                        VelMethod.java VelPropertyGet.java
                        VelPropertySet.java
  Log:
  Copied introspection core from Velocity into Jexl so Jexl introspection is
  decoupled (free to do what it wants) and ensures that jexl is lighter (has
  no dependencies other than commons logging and that goes next :)
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java
  
  Index: ClassMap.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Jexl", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  import java.util.Map;
  import java.util.List;
  import java.util.Hashtable;
  
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  
  /**
   *  Taken from the Velocity tree so we can be self-sufficient
   *
   * A cache of introspection information for a specific class instance.
   * Keys {@link java.lang.Method} objects by a concatenation 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>
   * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
   * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @version $Id: ClassMap.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public class ClassMap
  {
      private static final class CacheMiss { }
      private static final CacheMiss CACHE_MISS = new CacheMiss();
      private static final Object OBJECT = new Object();
  
      /** 
       * Class passed into the constructor used to as
       * the basis for the Method map.
       */
  
      private Class clazz;
  
      /**
       * Cache of Methods, or CACHE_MISS, keyed by method
       * name and actual arguments used to find it.
       */
      private Map methodCache = new Hashtable();
  
      private MethodMap methodMap = new MethodMap();
  
      /**
       * Standard constructor
       */
      public ClassMap( Class clazz)
      {
          this.clazz = clazz;
          populateMethodCache();
      }
  
      private ClassMap()
      {
      }
  
      /**
       * @return the class object whose methods are cached by this map.
       */
       Class getCachedClass()
       {
           return clazz;
       }
      
      /**
       * Find a Method using the methodKey
       * provided.
       *
       * 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.
       *
       * If nothing is found, then we must actually go
       * and introspect the method from the MethodMap.
       */
      public Method findMethod(String name, Object[] params)
          throws MethodMap.AmbiguousException
      {
          String methodKey = makeMethodKey(name, params);
          Object cacheEntry = methodCache.get( methodKey );
  
          if (cacheEntry == CACHE_MISS)
          {
              return null;
          }
  
          if (cacheEntry == null)
          {
              try
              {
                  cacheEntry = methodMap.find( name,
                                               params );
              }
              catch( MethodMap.AmbiguousException ae )
              {
                  /*
                   *  that's a miss :)
                   */
  
                  methodCache.put( methodKey,
                                   CACHE_MISS );
  
                  throw ae;
              }
  
              if ( cacheEntry == null )
              {
                  methodCache.put( methodKey,
                                   CACHE_MISS );
              }
              else
              {
                  methodCache.put( methodKey,
                                   cacheEntry );
              }
          }
  
          // Yes, this might just be null.
          
          return (Method) cacheEntry;
      }
      
      /**
       * Populate the Map of direct hits. These
       * are taken from all the public methods
       * that our class provides.
       */
      private void populateMethodCache()
      {
          StringBuffer methodKey;
  
          /*
           *  get all publicly accessible methods
           */
  
          Method[] methods = getAccessibleMethods(clazz);
  
          /*
           * map and cache them
           */
  
          for (int i = 0; i < methods.length; i++)
          {
              Method method = methods[i];
  
              /*
               *  now get the 'public method', the method declared by a 
               *  public interface or class. (because the actual implementing
               *  class may be a facade...
               */
  
              Method publicMethod = getPublicMethod( method );
  
              /*
               *  it is entirely possible that there is no public method for
               *  the methods of this class (i.e. in the facade, a method
               *  that isn't on any of the interfaces or superclass
               *  in which case, ignore it.  Otherwise, map and cache
               */
  
              if ( publicMethod != null)
              {
                  methodMap.add( publicMethod );
                  methodCache.put(  makeMethodKey( publicMethod), publicMethod);
              }
          }            
      }
  
      /**
       * Make a methodKey for the given method using
       * the concatenation of the name and the
       * types of the method parameters.
       */
      private String makeMethodKey(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.
               */
              if (parameterTypes[j].isPrimitive())
              {
                  if (parameterTypes[j].equals(Boolean.TYPE))
                      methodKey.append("java.lang.Boolean");
                  else if (parameterTypes[j].equals(Byte.TYPE))
                      methodKey.append("java.lang.Byte");
                  else if (parameterTypes[j].equals(Character.TYPE))
                      methodKey.append("java.lang.Character");
                  else if (parameterTypes[j].equals(Double.TYPE))
                      methodKey.append("java.lang.Double");
                  else if (parameterTypes[j].equals(Float.TYPE))
                      methodKey.append("java.lang.Float");
                  else if (parameterTypes[j].equals(Integer.TYPE))
                      methodKey.append("java.lang.Integer");
                  else if (parameterTypes[j].equals(Long.TYPE))
                      methodKey.append("java.lang.Long");
                  else if (parameterTypes[j].equals(Short.TYPE))
                      methodKey.append("java.lang.Short");
              }                
              else
              {
                  methodKey.append(parameterTypes[j].getName());
              }
          }            
          
          return methodKey.toString();
      }
  
      private static String makeMethodKey(String method, Object[] params)
      {
          StringBuffer methodKey = new StringBuffer().append(method);
  
          for (int j = 0; j < params.length; j++)
          {
              Object arg = params[j];
  
              if (arg == null)
              {
                  arg = OBJECT;
              }
  
              methodKey.append(arg.getClass().getName());
          }
          
          return methodKey.toString();
      }
  
      /**
       * Retrieves public methods for a class. In case the class is not
       * public, retrieves methods with same signature as its public methods
       * from public superclasses and interfaces (if they exist). Basically
       * upcasts every method to the nearest acccessible method.
       */
      private static Method[] getAccessibleMethods(Class clazz)
      {
          Method[] methods = clazz.getMethods();
          
          /*
           *  Short circuit for the (hopefully) majority of cases where the
           *  clazz is public
           */
          
          if (Modifier.isPublic(clazz.getModifiers()))
          {
              return methods;
          }
  
          /*
           *  No luck - the class is not public, so we're going the longer way.
           */
  
          MethodInfo[] methodInfos = new MethodInfo[methods.length];
  
          for(int i = methods.length; i-- > 0; )
          {
              methodInfos[i] = new MethodInfo(methods[i]);
          }
  
          int upcastCount = getAccessibleMethods(clazz, methodInfos, 0);
  
          /*
           *  Reallocate array in case some method had no accessible counterpart.
           */
  
          if(upcastCount < methods.length)
          {
              methods = new Method[upcastCount];
          }
  
          int j = 0;
          for(int i = 0; i < methodInfos.length; ++i)
          {
              MethodInfo methodInfo = methodInfos[i];
              if(methodInfo.upcast)
              {
                  methods[j++] = methodInfo.method;
              }
          }
          return methods;
      }
  
      /**
       *  Recursively finds a match for each method, starting with the class, and then
       *  searching the superclass and interfaces.
       *
       *  @param clazz Class to check
       *  @param methodInfos array of methods we are searching to match
       *  @param upcastCount current number of methods we have matched
       *  @return count of matched methods
       */
      private static int getAccessibleMethods( Class clazz, MethodInfo[] methodInfos, int upcastCount)
      {
          int l = methodInfos.length;
          
          /*
           *  if this class is public, then check each of the currently
           *  'non-upcasted' methods to see if we have a match
           */
  
          if( Modifier.isPublic(clazz.getModifiers()) )
          {
              for(int i = 0; i < l && upcastCount < l; ++i)
              {
                  try
                  {
                      MethodInfo methodInfo = methodInfos[i];
  
                      if(!methodInfo.upcast)
                      {
                          methodInfo.tryUpcasting(clazz);
                          upcastCount++;
                      }
                  }
                  catch(NoSuchMethodException e)
                  {
                      /*
                       *  Intentionally ignored - it means
                       *  it wasn't found in the current class
                       */
                  }
              }
  
              /*
               *  Short circuit if all methods were upcast
               */
  
              if(upcastCount == l)
              {
                  return upcastCount;
              }
          }
  
          /*
           *   Examine superclass
           */
  
          Class superclazz = clazz.getSuperclass();
  
          if(superclazz != null)
          {
              upcastCount = getAccessibleMethods(superclazz , methodInfos, upcastCount);
  
              /*
               *  Short circuit if all methods were upcast
               */
  
              if(upcastCount == l)
              {
                  return upcastCount;
              }
          }
  
          /*
           *  Examine interfaces. Note we do it even if superclazz == null.
           *  This is redundant as currently java.lang.Object does not implement
           *  any interfaces, however nothing guarantees it will not in future.
           */
  
          Class[] interfaces = clazz.getInterfaces();
  
          for(int i = interfaces.length; i-- > 0; )
          {
              upcastCount = getAccessibleMethods(interfaces[i], methodInfos, upcastCount);
  
              /*
               *  Short circuit if all methods were upcast
               */
  
              if(upcastCount == l)
              {
                  return upcastCount;
              }
          }
  
          return upcastCount;
      }
      
      /**
       *  For a given method, retrieves its publicly accessible counterpart. 
       *  This method will look for a method with same name
       *  and signature declared in a public superclass or implemented interface of this 
       *  method's declaring class. This counterpart method is publicly callable.
       *
       *  @param method a method whose publicly callable counterpart is requested.
       *  @return the publicly callable counterpart method. Note that if the parameter
       *  method is itself declared by a public class, this method is an identity
       *  function.
       */
      public static Method getPublicMethod(Method method)
      {
          Class clazz = method.getDeclaringClass();
          
          /*
           *   Short circuit for (hopefully the majority of) cases where the declaring
           *   class is public.
           */
  
          if((clazz.getModifiers() & Modifier.PUBLIC) != 0)
          {
              return method;
          }
  
          return getPublicMethod(clazz, method.getName(), method.getParameterTypes());
      }
  
      /**
       *  Looks up the method with specified name and signature in the first public
       *  superclass or implemented interface of the class. 
       * 
       *  @param class the class whose method is sought
       *  @param name the name of the method
       *  @param paramTypes the classes of method parameters
       */
      private static Method getPublicMethod(Class clazz, String name, Class[] paramTypes)
      {
          /*
           *  if this class is public, then try to get it
           */
  
          if((clazz.getModifiers() & Modifier.PUBLIC) != 0)
          {
              try
              {
                  return clazz.getMethod(name, paramTypes);
              }
              catch(NoSuchMethodException e)
              {
                  /*
                   *  If the class does not have the method, then neither its
                   *  superclass nor any of its interfaces has it so quickly return
                   *  null.
                   */
                   return null;
              }
          }
  
          /*
           *  try the superclass
           */
  
   
          Class superclazz = clazz.getSuperclass();
  
          if ( superclazz != null )
          {
              Method superclazzMethod = getPublicMethod(superclazz, name, paramTypes);
              
              if(superclazzMethod != null)
              {
                  return superclazzMethod;
              }
          }
  
          /*
           *  and interfaces
           */
  
          Class[] interfaces = clazz.getInterfaces();
  
          for(int i = 0; i < interfaces.length; ++i)
          {
              Method interfaceMethod = getPublicMethod(interfaces[i], name, paramTypes);
              
              if(interfaceMethod != null)
              {
                  return interfaceMethod;
              }
          }
  
          return null;
      }
  
      /**
       *  Used for the iterative discovery process for public methods.
       */
      private static final class MethodInfo
      {
          Method method;
          String name;
          Class[] parameterTypes;
          boolean upcast;
          
          MethodInfo(Method method)
          {
              this.method = null;
              name = method.getName();
              parameterTypes = method.getParameterTypes();
              upcast = false;
          }
          
          void tryUpcasting(Class clazz)
              throws NoSuchMethodException
          {
              method = clazz.getMethod(name, parameterTypes);
              name = null;
              parameterTypes = null;
              upcast = true;
          }
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/Info.java
  
  Index: Info.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Jexl", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.jexl.util.introspection;
  
  /**
   *  Little class to carry in info such as template name, line and column
   *  for information error reporting from the uberspector implementations
   *
   *  Taken from velocity for self-sufficiency.
   *
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @version $Id: Info.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public class Info
  {
      private int line;
      private int column;
      private String templateName;
  
      public Info(String tn, int l, int c)
      {
          templateName = tn;
          line = l;
          column = c;
      }
  
      private Info()
      {
      }
  
      public String getTemplateName()
      {
          return templateName;
      }
  
      public int getLine()
      {
          return line;
      }
  
      public int getColumn()
      {
          return column;
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/Introspector.java
  
  Index: Introspector.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  import org.apache.commons.logging.Log;
  
  import java.util.Map;
  import java.util.Set;
  import java.util.HashMap;
  import java.util.HashSet;
  
  import java.lang.reflect.Method;
  
  
  /**
   * This basic function of this class is to return a Method
   * object for a particular class given the name of a method
   * and the parameters to the method in the form of an Object[]
   *
   * The first time the Introspector sees a 
   * class it creates a class method map for the
   * class in question. Basically the class method map
   * is a Hastable where Method objects are keyed by a
   * concatenation of the method name and the names of
   * classes that make up the parameters.
   *
   * For example, a method with the following signature:
   *
   * public void method(String a, StringBuffer b)
   *
   * would be mapped by the key:
   *
   * "method" + "java.lang.String" + "java.lang.StringBuffer"
   *
   * This mapping is performed for all the methods in a class
   * and stored for 
   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
   * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
   * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
   * @author <a href="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
   * @version $Id: Introspector.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public class Introspector extends IntrospectorBase
  {
      /**
       *  define a public string so that it can be looked for
       *  if interested
       */
       
      public final static String CACHEDUMP_MSG = 
          "Introspector : detected classloader change. Dumping cache.";
  
      /**
       *  our engine runtime services
       */
      private  Log rlog = null;
  
      /**
       *  Recieves our RuntimeServices object
       */
      public Introspector(Log logger)
      {
          this.rlog = logger;
      }
     
      /**
       * Gets the method defined by <code>name</code> and
       * <code>params</code> for the Class <code>c</code>.
       *
       * @param c Class in which the method search is taking place
       * @param name Name of the method being searched for
       * @param params An array of Objects (not Classes) that describe the
       *               the parameters
       *
       * @return The desired Method object.
       */
      public Method getMethod(Class c, String name, Object[] params)
          throws Exception
      {
          /*
           *  just delegate to the base class
           */
  
          try
          {
              return super.getMethod( c, name, params );
          }
          catch( MethodMap.AmbiguousException ae )
          {
              /*
               *  whoops.  Ambiguous.  Make a nice log message and return null...
               */
  
              String msg = "Introspection Error : Ambiguous method invocation "
                  + name + "( ";
  
              for (int i = 0; i < params.length; i++)
              {
                  if ( i > 0)
                      msg = msg + ", ";
                  
                  msg = msg + params[i].getClass().getName();
              }
              
              msg = msg + ") for class " + c;
              
              rlog.error( msg );
          }
  
          return null;
      }
  
      /**
       * Clears the classmap and classname
       * caches, and logs that we did so
       */
      protected void clearCache()
      {
          super.clearCache();
          rlog.info( CACHEDUMP_MSG );
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java
  
  Index: IntrospectorBase.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  
  import java.util.Map;
  import java.util.Set;
  import java.util.HashMap;
  import java.util.HashSet;
  
  import java.lang.reflect.Method;
  
  /**
   * This basic function of this class is to return a Method
   * object for a particular class given the name of a method
   * and the parameters to the method in the form of an Object[]
   *
   * The first time the Introspector sees a 
   * class it creates a class method map for the
   * class in question. Basically the class method map
   * is a Hastable where Method objects are keyed by a
   * concatenation of the method name and the names of
   * classes that make up the parameters.
   *
   * For example, a method with the following signature:
   *
   * public void method(String a, StringBuffer b)
   *
   * would be mapped by the key:
   *
   * "method" + "java.lang.String" + "java.lang.StringBuffer"
   *
   * This mapping is performed for all the methods in a class
   * and stored for 
   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
   * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
   * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
   * @author <a href="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
   * @version $Id: IntrospectorBase.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public class IntrospectorBase
  {   
      /**
       * Holds the method maps for the classes we know about, keyed by
       * Class object.
       */ 
      protected  Map classMethodMaps = new HashMap();
      
      /**
       * Holds the qualified class names for the classes
       * we hold in the classMethodMaps hash
       */
      protected Set cachedClassNames = new HashSet();
     
      /**
       * Gets the method defined by <code>name</code> and
       * <code>params</code> for the Class <code>c</code>.
       *
       * @param c Class in which the method search is taking place
       * @param name Name of the method being searched for
       * @param params An array of Objects (not Classes) that describe the
       *               the parameters
       *
       * @return The desired Method object.
       */
      public Method getMethod(Class c, String name, Object[] params)
          throws Exception
      {
          if (c == null)
          {
              throw new Exception ( 
                  "Introspector.getMethod(): Class method key was null: " + name );
          }                
  
          ClassMap classMap = null;
          
          synchronized(classMethodMaps)
          {
              classMap = (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.
               */
               
              if (classMap == null)
              {                
                  if ( cachedClassNames.contains( c.getName() ))
                  {
                      /*
                       * we have a map for a class with same name, but not
                       * this class we are looking at.  This implies a 
                       * classloader change, so dump
                       */
                      clearCache();                    
                  }
                   
                  classMap = createClassMap(c);
              }
          }
          
          return classMap.findMethod(name, params);
      }
  
      /**
       * Creates a class map for specific class and registers it in the
       * cache.  Also adds the qualified name to the name->class map
       * for later Classloader change detection.
       */
      protected ClassMap createClassMap(Class c)
      {        
          ClassMap classMap = new ClassMap( c );        
          classMethodMaps.put(c, classMap);
          cachedClassNames.add( c.getName() );
  
          return classMap;
      }
  
      /**
       * Clears the classmap and classname
       * caches
       */
      protected void clearCache()
      {
          /*
           *  since we are synchronizing on this
           *  object, we have to clear it rather than
           *  just dump it.
           */            
          classMethodMaps.clear();
          
          /*
           * for speed, we can just make a new one
           * and let the old one be GC'd
           */
          cachedClassNames = new HashSet();
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java
  
  Index: MethodMap.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  import java.util.Iterator;
  import java.util.List;
  import java.util.ArrayList;
  import java.util.LinkedList;
  import java.util.Set;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Hashtable;
  
  import java.lang.reflect.Method;
  
  /**
   *
   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
   * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
   * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph Reck</a>
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
   * @version $Id: MethodMap.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public class MethodMap
  {
      private static final int MORE_SPECIFIC = 0;
      private static final int LESS_SPECIFIC = 1;
      private static final int INCOMPARABLE = 2;
  
      /**
       * Keep track of all methods with the same name.
       */
      Map methodByNameMap = new Hashtable();
  
      /**
       * Add a method to a list of methods by name.
       * For a particular class we are keeping track
       * of all the methods with the same name.
       */
      public void add(Method method)
      {
          String methodName = method.getName();
  
          List l = get( methodName );
  
          if ( l == null)
          {
              l = new ArrayList();
              methodByNameMap.put(methodName, l);
          }
  
          l.add(method);
  
          return;
      }
  
      /**
       * Return a list of methods with the same name.
       *
       * @param String key
       * @return List list of methods
       */
      public List get(String key)
      {
          return (List) methodByNameMap.get(key);
      }
  
      /**
       *  <p>
       *  Find a method.  Attempts to find the
       *  most specific applicable method using the
       *  algorithm described in the JLS section
       *  15.12.2 (with the exception that it can't
       *  distinguish a primitive type argument from
       *  an object type argument, since in reflection
       *  primitive type arguments are represented by
       *  their object counterparts, so for an argument of
       *  type (say) java.lang.Integer, it will not be able
       *  to decide between a method that takes int and a
       *  method that takes java.lang.Integer as a parameter.
       *  </p>
       *
       *  <p>
       *  This turns out to be a relatively rare case
       *  where this is needed - however, functionality
       *  like this is needed.
       *  </p>
       *
       *  @param methodName name of method
       *  @param args the actual arguments with which the method is called
       *  @return the most specific applicable method, or null if no
       *  method is applicable.
       *  @throws AmbiguousException if there is more than one maximally
       *  specific applicable method
       */
      public Method find(String methodName, Object[] args)
          throws AmbiguousException
      {
          List methodList = get(methodName);
  
          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);
      }
  
      /**
       *  simple distinguishable exception, used when
       *  we run across ambiguous overloading
       */
      public static class AmbiguousException extends Exception
      {
      }
  
  
      private static Method getMostSpecific(List methods, Class[] classes)
          throws AmbiguousException
      {
          LinkedList applicables = getApplicables(methods, classes);
  
          if(applicables.isEmpty())
          {
              return null;
          }
  
          if(applicables.size() == 1)
          {
              return (Method)applicables.getFirst();
          }
  
          /*
           * This list will contain the maximally specific methods. Hopefully at
           * the end of the below loop, the list will contain exactly one method,
           * (the most specific method) otherwise we have ambiguity.
           */
  
          LinkedList maximals = new LinkedList();
  
          for (Iterator applicable = applicables.iterator();
               applicable.hasNext();)
          {
              Method app = (Method) applicable.next();
              Class[] appArgs = app.getParameterTypes();
              boolean lessSpecific = false;
  
              for (Iterator maximal = maximals.iterator();
                   !lessSpecific && maximal.hasNext();)
              {
                  Method max = (Method) maximal.next();
  
                  switch(moreSpecific(appArgs, max.getParameterTypes()))
                  {
                      case MORE_SPECIFIC:
                      {
                          /*
                           * This method is more specific than the previously
                           * known maximally specific, so remove the old maximum.
                           */
  
                          maximal.remove();
                          break;
                      }
  
                      case LESS_SPECIFIC:
                      {
                          /*
                           * This method is less specific than some of the
                           * currently known maximally specific methods, so we
                           * won't add it into the set of maximally specific
                           * methods
                           */
  
                          lessSpecific = true;
                          break;
                      }
                  }
              }
  
              if(!lessSpecific)
              {
                  maximals.addLast(app);
              }
          }
  
          if(maximals.size() > 1)
          {
              // We have more than one maximally specific method
              throw new AmbiguousException();
          }
  
          return (Method)maximals.getFirst();
      }
  
      /**
       * Determines which method signature (represented by a class array) is more
       * specific. This defines a partial ordering on the method signatures.
       * @param c1 first signature to compare
       * @param c2 second signature to compare
       * @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if
       * c1 is less specific than c2, INCOMPARABLE if they are incomparable.
       */
      private static int moreSpecific(Class[] c1, Class[] c2)
      {
          boolean c1MoreSpecific = false;
          boolean c2MoreSpecific = false;
  
          for(int i = 0; i < c1.length; ++i)
          {
              if(c1[i] != c2[i])
              {
                  c1MoreSpecific =
                      c1MoreSpecific ||
                      isStrictMethodInvocationConvertible(c2[i], c1[i]);
                  c2MoreSpecific =
                      c2MoreSpecific ||
                      isStrictMethodInvocationConvertible(c1[i], c2[i]);
              }
          }
  
          if(c1MoreSpecific)
          {
              if(c2MoreSpecific)
              {
                  /*
                   *  Incomparable due to cross-assignable arguments (i.e.
                   * foo(String, Object) vs. foo(Object, String))
                   */
  
                  return INCOMPARABLE;
              }
  
              return MORE_SPECIFIC;
          }
  
          if(c2MoreSpecific)
          {
              return LESS_SPECIFIC;
          }
  
          /*
           * Incomparable due to non-related arguments (i.e.
           * foo(Runnable) vs. foo(Serializable))
           */
  
          return INCOMPARABLE;
      }
  
      /**
       * Returns all methods that are applicable to actual argument types.
       * @param methods list of all candidate methods
       * @param classes the actual types of the arguments
       * @return a list that contains only applicable methods (number of
       * 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();
  
              if(isApplicable(method, classes))
              {
                  list.add(method);
              }
  
          }
          return list;
      }
  
      /**
       * Returns true if the supplied method is applicable to actual
       * argument types.
       */
      private static boolean isApplicable(Method method, Class[] classes)
      {
          Class[] methodArgs = method.getParameterTypes();
  
          if(methodArgs.length != classes.length)
          {
              return false;
          }
  
          for(int i = 0; i < classes.length; ++i)
          {
              if(!isMethodInvocationConvertible(methodArgs[i], classes[i]))
              {
                  return false;
              }
          }
  
          return true;
      }
  
      /**
       * Determines whether a type represented by a class object is
       * convertible to another type represented by a class object using a
       * method invocation conversion, treating object types of primitive
       * types as if they were primitive types (that is, a Boolean actual
       * parameter type matches boolean primitive formal type). This behavior
       * is because this method is used to determine applicable methods for
       * an actual parameter list, and primitive types are represented by
       * their object duals in reflective method calls.
       *
       * @param formal the formal parameter type to which the actual
       * parameter type should be convertible
       * @param actual the actual parameter type.
       * @return true if either formal type is assignable from actual type,
       * or formal is a primitive type and actual is its corresponding object
       * type or an object type of a primitive type that can be converted to
       * the formal type.
       */
      private static boolean isMethodInvocationConvertible(Class formal,
                                                           Class actual)
      {
          /*
           * if it's a null, it means the arg was null
           */
          if (actual == null && !formal.isPrimitive())
          {
              return true;
          }
  
          /*
           *  Check for identity or widening reference conversion
           */
  
          if (actual != null && formal.isAssignableFrom(actual))
          {
              return true;
          }
  
          /*
           * Check for boxing with widening primitive conversion. Note that
           * actual parameters are never primitives.
           */
  
          if (formal.isPrimitive())
          {
              if(formal == Boolean.TYPE && actual == Boolean.class)
                  return true;
              if(formal == Character.TYPE && actual == Character.class)
                  return true;
              if(formal == Byte.TYPE && actual == Byte.class)
                  return true;
              if(formal == Short.TYPE &&
                 (actual == Short.class || actual == Byte.class))
                  return true;
              if(formal == Integer.TYPE &&
                 (actual == Integer.class || actual == Short.class ||
                  actual == Byte.class))
                  return true;
              if(formal == Long.TYPE &&
                 (actual == Long.class || actual == Integer.class ||
                  actual == Short.class || actual == Byte.class))
                  return true;
              if(formal == Float.TYPE &&
                 (actual == Float.class || actual == Long.class ||
                  actual == Integer.class || actual == Short.class ||
                  actual == Byte.class))
                  return true;
              if(formal == Double.TYPE &&
                 (actual == Double.class || actual == Float.class ||
                  actual == Long.class || actual == Integer.class ||
                  actual == Short.class || actual == Byte.class))
                  return true;
          }
  
          return false;
      }
  
      /**
       * Determines whether a type represented by a class object is
       * convertible to another type represented by a class object using a
       * method invocation conversion, without matching object and primitive
       * types. This method is used to determine the more specific type when
       * comparing signatures of methods.
       *
       * @param formal the formal parameter type to which the actual
       * parameter type should be convertible
       * @param actual the actual parameter type.
       * @return true if either formal type is assignable from actual type,
       * or formal and actual are both primitive types and actual can be
       * subject to widening conversion to formal.
       */
      private static boolean isStrictMethodInvocationConvertible(Class formal,
                                                                 Class actual)
      {
          /*
           * we shouldn't get a null into, but if so
           */
          if (actual == null && !formal.isPrimitive())
          {
              return true;
          }
  
          /*
           *  Check for identity or widening reference conversion
           */
  
          if(formal.isAssignableFrom(actual))
          {
              return true;
          }
  
          /*
           *  Check for widening primitive conversion.
           */
  
          if(formal.isPrimitive())
          {
              if(formal == Short.TYPE && (actual == Byte.TYPE))
                  return true;
              if(formal == Integer.TYPE &&
                 (actual == Short.TYPE || actual == Byte.TYPE))
                  return true;
              if(formal == Long.TYPE &&
                 (actual == Integer.TYPE || actual == Short.TYPE ||
                  actual == Byte.TYPE))
                  return true;
              if(formal == Float.TYPE &&
                 (actual == Long.TYPE || actual == Integer.TYPE ||
                  actual == Short.TYPE || actual == Byte.TYPE))
                  return true;
              if(formal == Double.TYPE &&
                 (actual == Float.TYPE || actual == Long.TYPE ||
                  actual == Integer.TYPE || actual == Short.TYPE ||
                  actual == Byte.TYPE))
                  return true;
          }
          return false;
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java
  
  Index: Uberspect.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  
  import java.util.Iterator;
  import java.lang.reflect.Method;
  
  /**
   * 'Federated' introspection/reflection interface to allow the introspection
   *  behavior in Velocity to be customized.
   *
   * @author <a href="mailto:geirm@apache.org">Geir Magusson Jr.</a>
   * @version $Id: Uberspect.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public interface Uberspect
  {
      /**
       *  Initializer - will be called before use
       */
      public void init() throws Exception;
  
      /**
       *  To support iteratives - #foreach()
       */
      public Iterator getIterator(Object obj, Info info) throws Exception;
  
      /**
       *  Returns a general method, corresponding to $foo.bar( $woogie )
       */
      public VelMethod getMethod(Object obj, String method, Object[] args, Info info) throws Exception;
  
      /**
       * Property getter - returns VelPropertyGet appropos for #set($foo = $bar.woogie)
       */
      public VelPropertyGet getPropertyGet(Object obj, String identifier, Info info) throws Exception;
  
      /**
       * Property setter - returns VelPropertySet appropos for #set($foo.bar = "geir")
       */
      public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info info) throws Exception;
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java
  
  Index: UberspectImpl.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  import org.apache.commons.jexl.util.ArrayIterator;
  import org.apache.commons.jexl.util.EnumerationIterator;
  import org.apache.commons.jexl.util.AbstractExecutor;
  import org.apache.commons.jexl.util.GetExecutor;
  import org.apache.commons.jexl.util.BooleanPropertyExecutor;
  import org.apache.commons.jexl.util.PropertyExecutor;
  import org.apache.commons.logging.Log;
  
  import java.lang.reflect.Method;
  import java.util.Iterator;
  import java.util.Collection;
  import java.util.Map;
  import java.util.Enumeration;
  import java.util.ArrayList;
  
  /**
   *  Implementation of Uberspect to provide the default introspective
   *  functionality of Velocity
   *
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @version $Id: UberspectImpl.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public class UberspectImpl implements Uberspect, UberspectLoggable
  {
      /**
       *  Our runtime logger.
       */
      private Log rlog;
  
      /**
       *  the default Velocity introspector
       */
      private static Introspector introspector;
  
      /**
       *  init - does nothing - we need to have setRuntimeLogger
       *  called before getting our introspector, as the default
       *  vel introspector depends upon it.
       */
      public void init()
          throws Exception
      {
      }
  
      /**
       *  Sets the runtime logger - this must be called before anything
       *  else besides init() as to get the logger.  Makes the pull
       *  model appealing...
       */
      public void setRuntimeLogger(Log runtimeLogger)
      {
          rlog = runtimeLogger;
          introspector = new Introspector(rlog);
      }
  
      /**
       *  To support iteratives - #foreach()
       */
      public Iterator getIterator(Object obj, Info i)
              throws Exception
      {
          if (obj.getClass().isArray())
          {
              return new ArrayIterator(obj);
          }
          else if (obj instanceof Collection)
          {
              return ((Collection) obj).iterator();
          }
          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() + "," + 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() + "," + i.getColumn() + "]"
                            + " in template " + i.getTemplateName()
                            + ". Because it's not resetable,"
                            + " if used in more than once, this may lead to"
                            + " unexpected results.");
  
              return new EnumerationIterator((Enumeration) obj);
          }
  
          /*  we have no clue what this is  */
          rlog.warn ("Could not determine type of iterator in "
                        +  "#foreach loop "
                        + " at [" + i.getLine() + "," + i.getColumn() + "]"
                        + " in template " + i.getTemplateName() );
  
          return null;
      }
  
      /**
       *  Method
       */
      public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i)
              throws Exception
      {
          if (obj == null)
              return null;
  
          Method m = introspector.getMethod(obj.getClass(), methodName, args);
  
          return (m != null) ? new VelMethodImpl(m) : null;
      }
  
      /**
       * Property  getter
       */
      public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i)
              throws Exception
      {
          AbstractExecutor executor;
  
          Class claz = obj.getClass();
  
          /*
           *  first try for a getFoo() type of property
           *  (also getfoo() )
           */
  
          executor = new PropertyExecutor(rlog,introspector, claz, identifier);
  
          /*
           *  if that didn't work, look for get("foo")
           */
  
          if (executor.isAlive() == false)
          {
              executor = new GetExecutor(rlog, introspector, claz, identifier);
          }
  
          /*
           *  finally, look for boolean isFoo()
           */
  
          if( executor.isAlive() == false)
          {
              executor = new BooleanPropertyExecutor(rlog, introspector, claz, identifier);
          }
  
          return (executor != null) ? new VelGetterImpl(executor) : null;
      }
  
      /**
       * Property setter
       */
      public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i)
              throws Exception
      {
          Class claz = obj.getClass();
  
          VelPropertySet vs = null;
          VelMethod vm = null;
          try
          {
              /*
               *  first, we introspect for the set<identifier> setter method
               */
  
              Object[] params = {arg};
  
              try
              {
                  vm = getMethod(obj, "set" + identifier, params, i);
  
                  if (vm == null)
                  {
                     throw new NoSuchMethodException();
                  }
              }
              catch(NoSuchMethodException nsme2)
              {
                  StringBuffer sb = new StringBuffer("set");
                  sb.append(identifier);
  
                  if (Character.isLowerCase( sb.charAt(3)))
                  {
                      sb.setCharAt(3, Character.toUpperCase(sb.charAt(3)));
                  }
                  else
                  {
                      sb.setCharAt(3, Character.toLowerCase(sb.charAt(3)));
                  }
  
                  vm = getMethod(obj, sb.toString(), params, i);
  
                  if (vm == null)
                  {
                     throw new NoSuchMethodException();
                  }
              }
          }
          catch (NoSuchMethodException nsme)
          {
              /*
               *  right now, we only support the Map interface
               */
  
              if (Map.class.isAssignableFrom(claz))
              {
                  Object[] params = {new Object(), new Object()};
  
                  vm = getMethod(obj, "put", params, i);
  
                  if (vm!=null)
                      return new VelSetterImpl(vm, identifier);
              }
         }
  
         return (vm!=null) ?  new VelSetterImpl(vm) : null;
      }
  
      /**
       *  Implementation of VelMethod
       */
      public class VelMethodImpl implements VelMethod
      {
          Method method = null;
  
          public VelMethodImpl(Method m)
          {
              method = m;
          }
  
          private VelMethodImpl()
          {
          }
  
          public Object invoke(Object o, Object[] params)
              throws Exception
          {
              return method.invoke(o, params);
          }
  
          public boolean isCacheable()
          {
              return true;
          }
  
          public String getMethodName()
          {
              return method.getName();
          }
  
          public Class getReturnType()
          {
              return method.getReturnType();
          }
      }
  
      public class VelGetterImpl implements VelPropertyGet
      {
          AbstractExecutor ae = null;
  
          public VelGetterImpl(AbstractExecutor exec)
          {
              ae = exec;
          }
  
          private VelGetterImpl()
          {
          }
  
          public Object invoke(Object o)
              throws Exception
          {
              return ae.execute(o);
          }
  
          public boolean isCacheable()
          {
              return true;
          }
  
          public String getMethodName()
          {
              return ae.getMethod().getName();
          }
  
      }
  
      public class VelSetterImpl implements VelPropertySet
      {
          VelMethod vm = null;
          String putKey = null;
  
          public VelSetterImpl(VelMethod velmethod)
          {
              this.vm = velmethod;
          }
  
          public VelSetterImpl(VelMethod velmethod, String key)
          {
              this.vm = velmethod;
              putKey = key;
          }
  
          private VelSetterImpl()
          {
          }
  
          public Object invoke(Object o, Object value)
              throws Exception
          {
              ArrayList al = new ArrayList();
  
              if (putKey != null)
              {
                  al.add(putKey);
                  al.add(value);
              }
              else
              {
                  al.add(value);
              }
  
              return vm.invoke(o,al.toArray());
          }
  
          public boolean isCacheable()
          {
              return true;
          }
  
          public String getMethodName()
          {
              return vm.getMethodName();
          }
  
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/UberspectLoggable.java
  
  Index: UberspectLoggable.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  import org.apache.commons.logging.Log;
  
  
  /**
   *  Marker interface to let an uberspector indicate it can and wants to
   *  log
   *
   *  Thanks to Paulo for the suggestion
   *
   * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
   * @version $Id: UberspectLoggable.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   *
   */
  public interface UberspectLoggable
  {
      /**
       *  Sets the logger.  This will be called before any calls to the
       *  uberspector
       */
      public void setRuntimeLogger(Log logger);
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/VelMethod.java
  
  Index: VelMethod.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  
  
  /**
   *  Method used for regular method invocation
   *
   *    $foo.bar()
   *
   *
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @version $Id: VelMethod.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public interface VelMethod
  {
      /**
       *  invocation method - called when the method invocationshould be
       *  preformed and a value returned
       */
      public Object invoke(Object o, Object[] params)
          throws Exception;
  
      /**
       *  specifies if this VelMethod is cacheable and able to be
       *  reused for this class of object it was returned for
       *
       *  @return true if can be reused for this class, false if not
       */
      public boolean isCacheable();
  
      /**
       *  returns the method name used
       */
      public String getMethodName();
  
      /**
       *  returns the return type of the method invoked
       */
      public Class getReturnType();
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/VelPropertyGet.java
  
  Index: VelPropertyGet.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  
  /**
   *  Interface defining a 'getter'.  For uses when looking for resolution of
   *  property references
   *
   *       $foo.bar
   *
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @version $Id: VelPropertyGet.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public interface VelPropertyGet
  {
      /**
       *  invocation method - called when the 'get action' should be
       *  preformed and a value returned
       */
      public Object invoke(Object o) throws Exception;
  
      /**
       *  specifies if this VelPropertyGet is cacheable and able to be
       *  reused for this class of object it was returned for
       *
       *  @return true if can be reused for this class, false if not
       */
      public boolean isCacheable();
  
      /**
       *  returns the method name used to return this 'property'
       */
      public String getMethodName();
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jexl/src/java/org/apache/commons/jexl/util/introspection/VelPropertySet.java
  
  Index: VelPropertySet.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.commons.jexl.util.introspection;
  
  
  /**
   *  Interface used for setting values that appear to be properties in
   *  Velocity.  Ex.
   *
   *      #set($foo.bar = "hello")
   *
   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
   * @version $Id: VelPropertySet.java,v 1.1 2002/08/05 05:04:53 geirm Exp $
   */
  public interface VelPropertySet
  {
      /**
       *  method used to set the value in the object
       *
       *  @param o Object on which the method will be called with the arg
       *  @param arg value to be set
       *  @return the value returned from the set operation (impl specific)
       */
      public Object invoke(Object o, Object arg) throws Exception;
  
      /**
       *  specifies if this VelPropertySet is cacheable and able to be
       *  reused for this class of object it was returned for
       *
       *  @return true if can be reused for this class, false if not
       */
      public boolean isCacheable();
  
      /**
       *  returns the method name used to set this 'property'
       */
      public String getMethodName();
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>