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.16 $
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 MetaClass answer = (MetaClass) metaClasses.get(theClass);
113 if (answer == null) {
114 try {
115 answer = new MetaClass(this, theClass);
116 answer.checkInitialised();
117 } catch (IntrospectionException e) {
118 throw new GroovyRuntimeException("Could not introspect class: " + theClass.getName() + ". Reason: " + e,
119 e);
120 }
121 metaClasses.put(theClass, answer);
122 }
123 return answer;
124 }
125
126 public void removeMetaClass(Class theClass) {
127 metaClasses.remove(theClass);
128 }
129
130
131 /***
132 * Registers a new MetaClass in the registry to customize the type
133 *
134 * @param theClass
135 * @param theMetaClass
136 */
137 public void setMetaClass(Class theClass, MetaClass theMetaClass) {
138 metaClasses.put(theClass, theMetaClass);
139 }
140
141 public boolean useAccessible() {
142 return useAccessible;
143 }
144
145 /***
146 * A helper class to load meta class bytecode into the class loader
147 */
148 public Class loadClass(final String name, final byte[] bytecode) throws ClassNotFoundException {
149 return (Class) AccessController.doPrivileged(new PrivilegedAction() {
150 public Object run() {
151 return loader.defineClass(name, bytecode, getClass().getProtectionDomain());
152 }
153 });
154 }
155
156 public Class loadClass(String name) throws ClassNotFoundException {
157 return loader.loadClass(name);
158 }
159
160 /***
161 * Ensures that all the registered MetaClass instances are initalized
162 */
163 void checkInitialised() {
164
165
166 List list = new ArrayList(metaClasses.values());
167 for (Iterator iter = list.iterator(); iter.hasNext();) {
168 MetaClass metaClass = (MetaClass) iter.next();
169 metaClass.checkInitialised();
170 }
171 }
172
173 /***
174 * Used by MetaClass when registering new methods which avoids initializing the MetaClass instances on lookup
175 */
176 MetaClass lookup(Class theClass) {
177 MetaClass answer = (MetaClass) metaClasses.get(theClass);
178 if (answer == null) {
179 try {
180 answer = new MetaClass(this, theClass);
181 } catch (IntrospectionException e) {
182 throw new GroovyRuntimeException("Could not introspect class: " + theClass.getName() + ". Reason: " + e,
183 e);
184 }
185 metaClasses.put(theClass, answer);
186 }
187 return answer;
188 }
189
190
191 public MetaMethod getDefinedMethod(Class theClass, String methodName, Class[] args, boolean isStatic) {
192 MetaClass metaclass = this.getMetaClass(theClass);
193 if (metaclass == null) {
194 return null;
195 } else {
196 if (isStatic) {
197 return metaclass.retrieveStaticMethod(methodName, args);
198 } else {
199 return metaclass.retrieveMethod(methodName, args);
200 }
201 }
202 }
203
204 public Constructor getDefinedConstructor(Class theClass, Class[] args) {
205 MetaClass metaclass = this.getMetaClass(theClass);
206 if (metaclass == null) {
207 return null;
208 } else {
209 return metaclass.retrieveConstructor(args);
210 }
211 }
212
213 /***
214 * Singleton of MetaClassRegistry. Shall we use threadlocal to store the instance?
215 *
216 * @param includeExtension
217 * @return
218 */
219 public static MetaClassRegistry getIntance(int includeExtension) {
220 if (includeExtension != DONT_LOAD_DEFAULT) {
221 if (instanceInclude == null) {
222 instanceInclude = new MetaClassRegistry();
223 }
224 return instanceInclude;
225 } else {
226 if (instanceExclude == null) {
227 instanceExclude = new MetaClassRegistry(DONT_LOAD_DEFAULT);
228 }
229 return instanceExclude;
230 }
231 }
232 }