001: /*
002: * Copyright 2001,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.commons.jexl.util.introspection;
018:
019: import java.util.Map;
020: import java.util.Set;
021: import java.util.HashMap;
022: import java.util.HashSet;
023:
024: import java.lang.reflect.Method;
025:
026: /**
027: * This basic function of this class is to return a Method object for a
028: * particular class given the name of a method and the parameters to the method
029: * in the form of an Object[]
030: *
031: * The first time the Introspector sees a class it creates a class method map
032: * for the class in question. Basically the class method map is a Hastable where
033: * Method objects are keyed by a concatenation of the method name and the names
034: * of classes that make up the parameters.
035: *
036: * For example, a method with the following signature:
037: *
038: * public void method(String a, StringBuffer b)
039: *
040: * would be mapped by the key:
041: *
042: * "method" + "java.lang.String" + "java.lang.StringBuffer"
043: *
044: * This mapping is performed for all the methods in a class and stored for
045: *
046: * @since 1.0
047: * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
048: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
049: * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
050: * @author <a href="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
051: * @version $Id: IntrospectorBase.java 398464 2006-04-30 23:50:43Z dion $
052: */
053: public class IntrospectorBase {
054: /**
055: * Holds the method maps for the classes we know about, keyed by Class
056: * object.
057: */
058: protected Map classMethodMaps = new HashMap();
059:
060: /**
061: * Holds the qualified class names for the classes we hold in the
062: * classMethodMaps hash.
063: */
064: protected Set cachedClassNames = new HashSet();
065:
066: /**
067: * Gets the method defined by <code>name</code> and <code>params</code>
068: * for the Class <code>c</code>.
069: *
070: * @param c Class in which the method search is taking place
071: * @param name Name of the method being searched for
072: * @param params An array of Objects (not Classes) that describe the the
073: * parameters
074: *
075: * @return The desired Method object.
076: * @throws Exception on any logical error.
077: */
078: public Method getMethod(Class c, String name, Object[] params)
079: throws Exception {
080: if (c == null) {
081: throw new Exception(
082: "Introspector.getMethod(): Class method key was null: "
083: + name);
084: }
085:
086: ClassMap classMap = null;
087:
088: synchronized (classMethodMaps) {
089: classMap = (ClassMap) classMethodMaps.get(c);
090:
091: /*
092: * if we don't have this, check to see if we have it by name. if so,
093: * then we have a classloader change so dump our caches.
094: */
095:
096: if (classMap == null) {
097: if (cachedClassNames.contains(c.getName())) {
098: /*
099: * we have a map for a class with same name, but not this
100: * class we are looking at. This implies a classloader
101: * change, so dump
102: */
103: clearCache();
104: }
105:
106: classMap = createClassMap(c);
107: }
108: }
109:
110: return classMap.findMethod(name, params);
111: }
112:
113: /**
114: * Creates a class map for specific class and registers it in the cache.
115: * Also adds the qualified name to the name->class map for later Classloader
116: * change detection.
117: * @param c class.
118: * @return a {@link ClassMap}
119: */
120: protected ClassMap createClassMap(Class c) {
121: ClassMap classMap = new ClassMap(c);
122: classMethodMaps.put(c, classMap);
123: cachedClassNames.add(c.getName());
124:
125: return classMap;
126: }
127:
128: /**
129: * Clears the classmap and classname caches.
130: */
131: protected void clearCache() {
132: /*
133: * since we are synchronizing on this object, we have to clear it rather
134: * than just dump it.
135: */
136: classMethodMaps.clear();
137:
138: /*
139: * for speed, we can just make a new one and let the old one be GC'd
140: */
141: cachedClassNames = new HashSet();
142: }
143: }
|