001: package murlen.util.fscript.introspection;
002:
003: /*
004: * The Apache Software License, Version 1.1
005: *
006: * Copyright (c) 2001 The Apache Software Foundation. All rights
007: * reserved.
008: *
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution, if
022: * any, must include the following acknowlegement:
023: * "This product includes software developed by the
024: * Apache Software Foundation (http://www.apache.org/)."
025: * Alternately, this acknowlegement may appear in the software itself,
026: * if and wherever such third-party acknowlegements normally appear.
027: *
028: * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
029: * Foundation" must not be used to endorse or promote products derived
030: * from this software without prior written permission. For written
031: * permission, please contact apache@apache.org.
032: *
033: * 5. Products derived from this software may not be called "Apache"
034: * nor may "Apache" appear in their names without prior written
035: * permission of the Apache Group.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
041: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
042: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
043: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
044: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
045: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
046: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
047: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
048: * SUCH DAMAGE.
049: * ====================================================================
050: *
051: * This software consists of voluntary contributions made by many
052: * individuals on behalf of the Apache Software Foundation. For more
053: * information on the Apache Software Foundation, please see
054: * <http://www.apache.org/>.
055: */
056:
057: import java.util.Map;
058: import java.util.Set;
059: import java.util.HashMap;
060: import java.util.HashSet;
061:
062: import java.lang.reflect.Method;
063:
064: /**
065: * This basic function of this class is to return a Method
066: * object for a particular class given the name of a method
067: * and the parameters to the method in the form of an Object[]
068: *
069: * The first time the Introspector sees a
070: * class it creates a class method map for the
071: * class in question. Basically the class method map
072: * is a Hastable where Method objects are keyed by a
073: * concatenation of the method name and the names of
074: * classes that make up the parameters.
075: *
076: * For example, a method with the following signature:
077: *
078: * public void method(String a, StringBuffer b)
079: *
080: * would be mapped by the key:
081: *
082: * "method" + "java.lang.String" + "java.lang.StringBuffer"
083: *
084: * This mapping is performed for all the methods in a class
085: * and stored for
086: * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
087: * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
088: * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
089: * @author <a href="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
090: * @version $Id: IntrospectorBase.java,v 1.1.1.1 2004/07/28 01:28:05 murlen Exp $
091: */
092: public class IntrospectorBase {
093: /**
094: * Holds the method maps for the classes we know about, keyed by
095: * Class object.
096: */
097: protected Map classMethodMaps = new HashMap();
098:
099: /**
100: * Holds the qualified class names for the classes
101: * we hold in the classMethodMaps hash
102: */
103: protected Set cachedClassNames = new HashSet();
104:
105: /**
106: * Gets the method defined by <code>name</code> and
107: * <code>params</code> for the Class <code>c</code>.
108: *
109: * @param c Class in which the method search is taking place
110: * @param name Name of the method being searched for
111: * @param params An array of Objects (not Classes) that describe the
112: * the parameters
113: *
114: * @return The desired Method object.
115: */
116: public Method getMethod(Class c, String name, Object[] params)
117: throws Exception {
118: if (c == null) {
119: throw new Exception(
120: "Introspector.getMethod(): Class method key was null: "
121: + name);
122: }
123:
124: ClassMap classMap = null;
125:
126: synchronized (classMethodMaps) {
127: classMap = (ClassMap) classMethodMaps.get(c);
128:
129: /*
130: * if we don't have this, check to see if we have it
131: * by name. if so, then we have a classloader change
132: * so dump our caches.
133: */
134:
135: if (classMap == null) {
136: if (cachedClassNames.contains(c.getName())) {
137: /*
138: * we have a map for a class with same name, but not
139: * this class we are looking at. This implies a
140: * classloader change, so dump
141: */
142: clearCache();
143: }
144:
145: classMap = createClassMap(c);
146: }
147: }
148:
149: return classMap.findMethod(name, params);
150: }
151:
152: /**
153: * Creates a class map for specific class and registers it in the
154: * cache. Also adds the qualified name to the name->class map
155: * for later Classloader change detection.
156: */
157: protected ClassMap createClassMap(Class c) {
158: ClassMap classMap = new ClassMap(c);
159: classMethodMaps.put(c, classMap);
160: cachedClassNames.add(c.getName());
161:
162: return classMap;
163: }
164:
165: /**
166: * Clears the classmap and classname
167: * caches
168: */
169: protected void clearCache() {
170: /*
171: * since we are synchronizing on this
172: * object, we have to clear it rather than
173: * just dump it.
174: */
175: classMethodMaps.clear();
176:
177: /*
178: * for speed, we can just make a new one
179: * and let the old one be GC'd
180: */
181: cachedClassNames = new HashSet();
182: }
183: }
|