1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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;
52 import java.lang.reflect.Constructor;
53 import java.security.AccessController;
54 import java.security.PrivilegedAction;
55 import java.util.*;
56
57 /***
58 * A registery of MetaClass instances which caches introspection &
59 * reflection information and allows methods to be dynamically added to
60 * existing classes at runtime
61 *
62 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
63 * @version $Revision: 1.17 $
64 */
65 public class MetaClassRegistry {
66 private Map metaClasses = Collections.synchronizedMap(new HashMap());
67 private boolean useAccessible;
68 private GroovyClassLoader loader =
69 (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
70 public Object run() {
71 return new GroovyClassLoader(getClass().getClassLoader());
72 }
73 });
74
75 public static final int LOAD_DEFAULT = 0;
76 public static final int DONT_LOAD_DEFAULT = 1;
77 private static MetaClassRegistry instanceInclude;
78 private static MetaClassRegistry instanceExclude;
79
80
81 public MetaClassRegistry() {
82 this(true);
83 }
84
85 public MetaClassRegistry(int loadDefault) {
86 if (loadDefault == LOAD_DEFAULT) {
87 this.useAccessible = true;
88
89 lookup(DefaultGroovyMethods.class).registerInstanceMethods();
90 lookup(DefaultGroovyStaticMethods.class).registerStaticMethods();
91 checkInitialised();
92 } else {
93 this.useAccessible = true;
94
95 }
96 }
97
98 /***
99 * @param useAccessible defines whether or not the {@link AccessibleObject.setAccessible()}
100 * method will be called to enable access to all methods when using reflection
101 */
102 public MetaClassRegistry(boolean useAccessible) {
103 this.useAccessible = useAccessible;
104
105
106 lookup(DefaultGroovyMethods.class).registerInstanceMethods();
107 lookup(DefaultGroovyStaticMethods.class).registerStaticMethods();
108 checkInitialised();
109 }
110
111 public MetaClass getMetaClass(Class theClass) {
112 synchronized(theClass) {
113 MetaClass answer = (MetaClass) metaClasses.get(theClass);
114 if (answer == null) {
115 try {
116 answer = new MetaClass(this, theClass);
117 answer.checkInitialised();
118 } catch (IntrospectionException e) {
119 throw new GroovyRuntimeException("Could not introspect class: " + theClass.getName() + ". Reason: " + e,
120 e);
121 }
122 metaClasses.put(theClass, answer);
123 }
124 return answer;
125 }
126 }
127
128 public void removeMetaClass(Class theClass) {
129 metaClasses.remove(theClass);
130 }
131
132
133 /***
134 * Registers a new MetaClass in the registry to customize the type
135 *
136 * @param theClass
137 * @param theMetaClass
138 */
139 public void setMetaClass(Class theClass, MetaClass theMetaClass) {
140 metaClasses.put(theClass, theMetaClass);
141 }
142
143 public boolean useAccessible() {
144 return useAccessible;
145 }
146
147 /***
148 * A helper class to load meta class bytecode into the class loader
149 */
150 public Class loadClass(final String name, final byte[] bytecode) throws ClassNotFoundException {
151 return (Class) AccessController.doPrivileged(new PrivilegedAction() {
152 public Object run() {
153 return loader.defineClass(name, bytecode, getClass().getProtectionDomain());
154 }
155 });
156 }
157
158 public Class loadClass(String name) throws ClassNotFoundException {
159 return loader.loadClass(name);
160 }
161
162 /***
163 * Ensures that all the registered MetaClass instances are initalized
164 */
165 void checkInitialised() {
166
167
168 List list = new ArrayList(metaClasses.values());
169 for (Iterator iter = list.iterator(); iter.hasNext();) {
170 MetaClass metaClass = (MetaClass) iter.next();
171 metaClass.checkInitialised();
172 }
173 }
174
175 /***
176 * Used by MetaClass when registering new methods which avoids initializing the MetaClass instances on lookup
177 */
178 MetaClass lookup(Class theClass) {
179 MetaClass answer = (MetaClass) metaClasses.get(theClass);
180 if (answer == null) {
181 try {
182 answer = new MetaClass(this, theClass);
183 } catch (IntrospectionException e) {
184 throw new GroovyRuntimeException("Could not introspect class: " + theClass.getName() + ". Reason: " + e,
185 e);
186 }
187 metaClasses.put(theClass, answer);
188 }
189 return answer;
190 }
191
192
193 public MetaMethod getDefinedMethod(Class theClass, String methodName, Class[] args, boolean isStatic) {
194 MetaClass metaclass = this.getMetaClass(theClass);
195 if (metaclass == null) {
196 return null;
197 } else {
198 if (isStatic) {
199 return metaclass.retrieveStaticMethod(methodName, args);
200 } else {
201 return metaclass.retrieveMethod(methodName, args);
202 }
203 }
204 }
205
206 public Constructor getDefinedConstructor(Class theClass, Class[] args) {
207 MetaClass metaclass = this.getMetaClass(theClass);
208 if (metaclass == null) {
209 return null;
210 } else {
211 return metaclass.retrieveConstructor(args);
212 }
213 }
214
215 /***
216 * Singleton of MetaClassRegistry. Shall we use threadlocal to store the instance?
217 *
218 * @param includeExtension
219 * @return
220 */
221 public static MetaClassRegistry getIntance(int includeExtension) {
222 if (includeExtension != DONT_LOAD_DEFAULT) {
223 if (instanceInclude == null) {
224 instanceInclude = new MetaClassRegistry();
225 }
226 return instanceInclude;
227 } else {
228 if (instanceExclude == null) {
229 instanceExclude = new MetaClassRegistry(DONT_LOAD_DEFAULT);
230 }
231 return instanceExclude;
232 }
233 }
234 }