KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > utils > cache > MethodCache


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 package org.apache.axis.utils.cache;
17
18 import java.lang.reflect.Method JavaDoc;
19 import java.util.Arrays JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Map JavaDoc;
22
23 import org.apache.axis.utils.ClassUtils;
24
25 /**
26  * A cache for methods.
27  * Used to get methods by their signature and stores them in a local
28  * cache for performance reasons.
29  * This class is a singleton - so use getInstance to get an instance of it.
30  *
31  * @author Davanum Srinivas <dims@yahoo.com>
32  * @author Sebastian Dietrich <sebastian.dietrich@anecon.com>
33  */

34 public class MethodCache {
35     /**
36      * The only instance of this class
37      */

38     transient private static MethodCache instance;
39
40     /**
41      * Cache for Methods
42      * In fact this is a map (with classes as keys) of a map (with method-names as keys)
43      */

44     transient private static ThreadLocal JavaDoc cache;
45
46     /**
47      * The <i>private</i> constructor for this class.
48      * Use getInstance to get an instance (the only one).
49      */

50     private MethodCache() {
51         cache = new ThreadLocal JavaDoc();
52     }
53
54     /**
55      * Gets the only instance of this class
56      * @return the only instance of this class
57      */

58     public static MethodCache getInstance() {
59         if (instance == null) {
60             instance = new MethodCache();
61         }
62         return instance;
63     }
64
65     /**
66      * Returns the per thread hashmap (for method caching)
67      */

68     private Map JavaDoc getMethodCache() {
69         Map JavaDoc map = (Map JavaDoc) cache.get();
70         if (map == null) {
71             map = new HashMap JavaDoc();
72             cache.set(map);
73         }
74         return map;
75     }
76
77     /**
78      * Class used as the key for the method cache table.
79      *
80      */

81     static class MethodKey {
82         /** the name of the method in the cache */
83         private final String JavaDoc methodName;
84         /** the list of types accepted by the method as arguments */
85         private final Class JavaDoc[] parameterTypes;
86
87         /**
88          * Creates a new <code>MethodKey</code> instance.
89          *
90          * @param methodName a <code>String</code> value
91          * @param parameterTypes a <code>Class[]</code> value
92          */

93         MethodKey(String JavaDoc methodName, Class JavaDoc[] parameterTypes) {
94             this.methodName = methodName;
95             this.parameterTypes = parameterTypes;
96         }
97
98         public boolean equals(Object JavaDoc other) {
99             MethodKey that = (MethodKey) other;
100             return this.methodName.equals(that.methodName)
101                 && Arrays.equals(this.parameterTypes,
102                                  that.parameterTypes);
103         }
104
105         public int hashCode() {
106             // allow overloaded methods to collide; we'll sort it out
107
// in equals(). Note that String's implementation of
108
// hashCode already caches its value, so there's no point
109
// in doing so here.
110
return methodName.hashCode();
111         }
112     }
113
114     /** used to track methods we've sought but not found in the past */
115     private static final Object JavaDoc NULL_OBJECT = new Object JavaDoc();
116
117     /**
118      * Returns the specified method - if any.
119      *
120      * @param clazz the class to get the method from
121      * @param methodName the name of the method
122      * @param parameterTypes the parameters of the method
123      * @return the found method
124      *
125      * @throws NoSuchMethodException if the method can't be found
126      */

127     public Method JavaDoc getMethod(Class JavaDoc clazz,
128                             String JavaDoc methodName,
129                             Class JavaDoc[] parameterTypes)
130         throws NoSuchMethodException JavaDoc {
131         String JavaDoc className = clazz.getName();
132         Map JavaDoc cache = getMethodCache();
133         Method JavaDoc method = null;
134         Map JavaDoc methods = null;
135
136         // Strategy is as follows:
137
// construct a MethodKey to represent the name/arguments
138
// of a method's signature.
139
//
140
// use the name of the class to retrieve a map of that
141
// class' methods
142
//
143
// if a map exists, use the MethodKey to find the
144
// associated value object. if that object is a Method
145
// instance, return it. if that object is anything
146
// else, then it's a reference to our NULL_OBJECT
147
// instance, indicating that we've previously tried
148
// and failed to find a method meeting our requirements,
149
// so return null
150
//
151
// if the map of methods for the class doesn't exist,
152
// or if no value is associated with our key in that map,
153
// then we perform a reflection-based search for the method.
154
//
155
// if we find a method in that search, we store it in the
156
// map using the key; otherwise, we store a reference
157
// to NULL_OBJECT using the key.
158

159         // Check the cache first.
160
MethodKey key = new MethodKey(methodName, parameterTypes);
161         methods = (Map JavaDoc) cache.get(clazz);
162         if (methods != null) {
163             Object JavaDoc o = methods.get(key);
164             if (o != null) { // cache hit
165
if (o instanceof Method JavaDoc) { // good cache hit
166
return (Method JavaDoc) o;
167                 } else { // bad cache hit
168
// we hit the NULL_OBJECT, so this is a search
169
// that previously failed; no point in doing
170
// it again as it is a worst case search
171
// through the entire classpath.
172
return null;
173                 }
174             } else {
175                 // cache miss: fall through to reflective search
176
}
177         } else {
178             // cache miss: fall through to reflective search
179
}
180
181         try {
182             method = clazz.getMethod(methodName, parameterTypes);
183         } catch (NoSuchMethodException JavaDoc e1) {
184             if (!clazz.isPrimitive() && !className.startsWith("java.") && !className.startsWith("javax.")) {
185                 try {
186                     Class JavaDoc helper = ClassUtils.forName(className + "_Helper");
187                     method = helper.getMethod(methodName, parameterTypes);
188                 } catch (ClassNotFoundException JavaDoc e2) {
189                 }
190             }
191         }
192
193         // first time we've seen this class: set up its method cache
194
if (methods == null) {
195             methods = new HashMap JavaDoc();
196             cache.put(clazz, methods);
197         }
198
199         // when no method is found, cache the NULL_OBJECT
200
// so that we don't have to repeat worst-case searches
201
// every time.
202

203         if (null == method) {
204             methods.put(key, NULL_OBJECT);
205         } else {
206             methods.put(key, method);
207         }
208         return method;
209     }
210 }
211
Popular Tags