KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > groovy > lang > MetaClassRegistry


1 /*
2  $Id: MetaClassRegistry.java,v 1.20 2005/04/13 14:15:26 jstrachan Exp $
3
4  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5
6  Redistribution and use of this software and associated documentation
7  ("Software"), with or without modification, are permitted provided
8  that the following conditions are met:
9
10  1. Redistributions of source code must retain copyright
11     statements and notices. Redistributions must also contain a
12     copy of this document.
13
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus. For written permission,
22     please contact info@codehaus.org.
23
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44
45  */

46 package groovy.lang;
47
48 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
49 import org.codehaus.groovy.runtime.DefaultGroovyStaticMethods;
50
51 import java.beans.IntrospectionException JavaDoc;
52 import java.lang.reflect.Constructor JavaDoc;
53 import java.security.AccessController JavaDoc;
54 import java.security.PrivilegedAction JavaDoc;
55 import java.util.ArrayList JavaDoc;
56 import java.util.Collections JavaDoc;
57 import java.util.Iterator JavaDoc;
58 import java.util.List JavaDoc;
59 import java.util.Map JavaDoc;
60 import java.util.WeakHashMap JavaDoc;
61
62 /**
63  * A registery of MetaClass instances which caches introspection &
64  * reflection information and allows methods to be dynamically added to
65  * existing classes at runtime
66  *
67  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>
68  * @version $Revision: 1.20 $
69  */

70 public class MetaClassRegistry {
71     private Map JavaDoc metaClasses = Collections.synchronizedMap(new WeakHashMap JavaDoc());
72     private boolean useAccessible;
73     private Map JavaDoc loaderMap = Collections.synchronizedMap(new WeakHashMap JavaDoc());
74     private GroovyClassLoader loader =
75             (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
76                 public Object JavaDoc run() {
77                     return new GroovyClassLoader(getClass().getClassLoader());
78                 }
79             });
80
81     public static final int LOAD_DEFAULT = 0;
82     public static final int DONT_LOAD_DEFAULT = 1;
83     private static MetaClassRegistry instanceInclude;
84     private static MetaClassRegistry instanceExclude;
85
86
87     public MetaClassRegistry() {
88         this(true);
89     }
90
91     public MetaClassRegistry(int loadDefault) {
92         if (loadDefault == LOAD_DEFAULT) {
93             this.useAccessible = true;
94             // lets register the default methods
95
lookup(DefaultGroovyMethods.class).registerInstanceMethods();
96             lookup(DefaultGroovyStaticMethods.class).registerStaticMethods();
97             checkInitialised();
98         }
99         else {
100             this.useAccessible = true;
101             // do nothing to avoid loading DefaultGroovyMethod
102
}
103     }
104
105     /**
106      * @param useAccessible defines whether or not the {@link java.lang.reflect.AccessibleObject.setAccessible();}
107      * method will be called to enable access to all methods when using reflection
108      */

109     public MetaClassRegistry(boolean useAccessible) {
110         this.useAccessible = useAccessible;
111
112         // lets register the default methods
113
lookup(DefaultGroovyMethods.class).registerInstanceMethods();
114         lookup(DefaultGroovyStaticMethods.class).registerStaticMethods();
115         checkInitialised();
116     }
117
118     public MetaClass getMetaClass(Class JavaDoc theClass) {
119         synchronized (theClass) {
120             MetaClass answer = (MetaClass) metaClasses.get(theClass);
121             if (answer == null) {
122                 try {
123                     answer = new MetaClass(this, theClass);
124                     answer.checkInitialised();
125                 }
126                 catch (IntrospectionException JavaDoc e) {
127                     throw new GroovyRuntimeException("Could not introspect class: " + theClass.getName() + ". Reason: " + e,
128                             e);
129                 }
130                 metaClasses.put(theClass, answer);
131             }
132             return answer;
133         }
134     }
135
136     public void removeMetaClass(Class JavaDoc theClass) {
137         metaClasses.remove(theClass);
138     }
139
140
141     /**
142      * Registers a new MetaClass in the registry to customize the type
143      *
144      * @param theClass
145      * @param theMetaClass
146      */

147     public void setMetaClass(Class JavaDoc theClass, MetaClass theMetaClass) {
148         metaClasses.put(theClass, theMetaClass);
149     }
150
151     public boolean useAccessible() {
152         return useAccessible;
153     }
154
155     /**
156      * A helper class to load meta class bytecode into the class loader
157      */

158     public Class JavaDoc loadClass(final String JavaDoc name, final byte[] bytecode) throws ClassNotFoundException JavaDoc {
159         return (Class JavaDoc) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
160             public Object JavaDoc run() {
161                 return getGroovyLoader(loader).defineClass(name, bytecode, getClass().getProtectionDomain());
162             }
163         });
164     }
165
166     public Class JavaDoc loadClass(final ClassLoader JavaDoc loader, final String JavaDoc name, final byte[] bytecode) throws ClassNotFoundException JavaDoc {
167         return (Class JavaDoc) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
168             public Object JavaDoc run() {
169                 return getGroovyLoader(loader).defineClass(name, bytecode, getClass().getProtectionDomain());
170             }
171         });
172          }
173
174     public Class JavaDoc loadClass(ClassLoader JavaDoc loader, String JavaDoc name) throws ClassNotFoundException JavaDoc {
175         return getGroovyLoader(loader).loadClass(name);
176     }
177
178     public Class JavaDoc loadClass(String JavaDoc name) throws ClassNotFoundException JavaDoc {
179         return getGroovyLoader(loader).loadClass(name);
180     }
181
182     private GroovyClassLoader getGroovyLoader(ClassLoader JavaDoc loader) {
183         if (loader instanceof GroovyClassLoader) {
184             return (GroovyClassLoader) loader;
185         }
186         
187         synchronized (loaderMap) {
188             GroovyClassLoader groovyLoader = (GroovyClassLoader) loaderMap.get(loader);
189             if (groovyLoader == null) {
190                 if (loader == null || loader == getClass().getClassLoader()) {
191                     groovyLoader = this.loader;
192                 }
193                 else {
194                     // lets check that the class loader can see the Groovy classes
195
// if so we'll use that, otherwise lets use the local class loader
196
try {
197                         loader.loadClass(getClass().getName());
198
199                         // thats fine, lets use the loader
200
groovyLoader = new GroovyClassLoader(loader);
201                     }
202                     catch (ClassNotFoundException JavaDoc e) {
203
204                         // we can't see the groovy classes here
205
// so lets try create a new loader
206
ClassLoader JavaDoc localLoader = getClass().getClassLoader();
207                         groovyLoader = new GroovyClassLoader(localLoader);
208                     }
209                 }
210                 loaderMap.put(loader, groovyLoader);
211             }
212
213             return groovyLoader;
214         }
215     }
216
217     /**
218      * Ensures that all the registered MetaClass instances are initalized
219      */

220     void checkInitialised() {
221         // lets copy all the classes in the repository right now
222
// to avoid concurrent modification exception
223
List JavaDoc list = new ArrayList JavaDoc(metaClasses.values());
224         for (Iterator JavaDoc iter = list.iterator(); iter.hasNext();) {
225             MetaClass metaClass = (MetaClass) iter.next();
226             metaClass.checkInitialised();
227         }
228     }
229
230     /**
231      * Used by MetaClass when registering new methods which avoids initializing the MetaClass instances on lookup
232      */

233     MetaClass lookup(Class JavaDoc theClass) {
234         MetaClass answer = (MetaClass) metaClasses.get(theClass);
235         if (answer == null) {
236             try {
237                 answer = new MetaClass(this, theClass);
238             }
239             catch (IntrospectionException JavaDoc e) {
240                 throw new GroovyRuntimeException("Could not introspect class: " + theClass.getName() + ". Reason: " + e,
241                         e);
242             }
243             metaClasses.put(theClass, answer);
244         }
245         return answer;
246     }
247
248
249     public MetaMethod getDefinedMethod(Class JavaDoc theClass, String JavaDoc methodName, Class JavaDoc[] args, boolean isStatic) {
250         MetaClass metaclass = this.getMetaClass(theClass);
251         if (metaclass == null) {
252             return null;
253         }
254         else {
255             if (isStatic) {
256                 return metaclass.retrieveStaticMethod(methodName, args);
257             }
258             else {
259                 return metaclass.retrieveMethod(methodName, args);
260             }
261         }
262     }
263
264     public Constructor JavaDoc getDefinedConstructor(Class JavaDoc theClass, Class JavaDoc[] args) {
265         MetaClass metaclass = this.getMetaClass(theClass);
266         if (metaclass == null) {
267             return null;
268         }
269         else {
270             return metaclass.retrieveConstructor(args);
271         }
272     }
273
274     /**
275      * Singleton of MetaClassRegistry. Shall we use threadlocal to store the instance?
276      *
277      * @param includeExtension
278      * @return
279      */

280     public static MetaClassRegistry getIntance(int includeExtension) {
281         if (includeExtension != DONT_LOAD_DEFAULT) {
282             if (instanceInclude == null) {
283                 instanceInclude = new MetaClassRegistry();
284             }
285             return instanceInclude;
286         }
287         else {
288             if (instanceExclude == null) {
289                 instanceExclude = new MetaClassRegistry(DONT_LOAD_DEFAULT);
290             }
291             return instanceExclude;
292         }
293     }
294 }
295
Popular Tags