View Javadoc

    1   /*
    2    * Copyright 2001,2004 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16
    17  package org.apache.commons.jexl.util.introspection;
    18
    19
    20  import java.util.Map;
    21  import java.util.Set;
    22  import java.util.HashMap;
    23  import java.util.HashSet;
    24
    25  import java.lang.reflect.Method;
    26
    27  /***
    28   * This basic function of this class is to return a Method
    29   * object for a particular class given the name of a method
    30   * and the parameters to the method in the form of an Object[]
    31   *
    32   * The first time the Introspector sees a
    33   * class it creates a class method map for the
    34   * class in question. Basically the class method map
    35   * is a Hastable where Method objects are keyed by a
    36   * concatenation of the method name and the names of
    37   * classes that make up the parameters.
    38   *
    39   * For example, a method with the following signature:
    40   *
    41   * public void method(String a, StringBuffer b)
    42   *
    43   * would be mapped by the key:
    44   *
    45   * "method" + "java.lang.String" + "java.lang.StringBuffer"
    46   *
    47   * This mapping is performed for all the methods in a class
    48   * and stored for
    49   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
    50   * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
    51   * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
    52   * @author <a href="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
    53   * @version $Id: IntrospectorBase.java,v 1.3 2004/02/28 13:45:21 yoavs Exp $
    54   */
    55  public class IntrospectorBase
    56  {
    57      /***
    58       * Holds the method maps for the classes we know about, keyed by
    59       * Class object.
    60       */
    61      protected  Map classMethodMaps = new HashMap();
    62
    63      /***
    64       * Holds the qualified class names for the classes
    65       * we hold in the classMethodMaps hash
    66       */
    67      protected Set cachedClassNames = new HashSet();
    68
    69      /***
    70       * Gets the method defined by <code>name</code> and
    71       * <code>params</code> for the Class <code>c</code>.
    72       *
    73       * @param c Class in which the method search is taking place
    74       * @param name Name of the method being searched for
    75       * @param params An array of Objects (not Classes) that describe the
    76       *               the parameters
    77       *
    78       * @return The desired Method object.
    79       */
    80      public Method getMethod(Class c, String name, Object[] params)
    81          throws Exception
    82      {
    83          if (c == null)
    84          {
    85              throw new Exception (
    86                  "Introspector.getMethod(): Class method key was null: " + name );
    87          }
    88
    89          ClassMap classMap = null;
    90
    91          synchronized(classMethodMaps)
    92          {
    93              classMap = (ClassMap)classMethodMaps.get(c);
    94
    95              /*
    96               *  if we don't have this, check to see if we have it
    97               *  by name.  if so, then we have a classloader change
    98               *  so dump our caches.
    99               */
    100
    101             if (classMap == null)
    102             {
    103                 if ( cachedClassNames.contains( c.getName() ))
    104                 {
    105                     /*
    106                      * we have a map for a class with same name, but not
    107                      * this class we are looking at.  This implies a
    108                      * classloader change, so dump
    109                      */
    110                     clearCache();
    111                 }
    112
    113                 classMap = createClassMap(c);
    114             }
    115         }
    116
    117         return classMap.findMethod(name, params);
    118     }
    119
    120     /***
    121      * Creates a class map for specific class and registers it in the
    122      * cache.  Also adds the qualified name to the name->class map
    123      * for later Classloader change detection.
    124      */
    125     protected ClassMap createClassMap(Class c)
    126     {
    127         ClassMap classMap = new ClassMap( c );
    128         classMethodMaps.put(c, classMap);
    129         cachedClassNames.add( c.getName() );
    130
    131         return classMap;
    132     }
    133
    134     /***
    135      * Clears the classmap and classname
    136      * caches
    137      */
    138     protected void clearCache()
    139     {
    140         /*
    141          *  since we are synchronizing on this
    142          *  object, we have to clear it rather than
    143          *  just dump it.
    144          */
    145         classMethodMaps.clear();
    146
    147         /*
    148          * for speed, we can just make a new one
    149          * and let the old one be GC'd
    150          */
    151         cachedClassNames = new HashSet();
    152     }
    153 }