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 java.beans.IntrospectionException;
49 import java.lang.reflect.Constructor;
50 import java.security.AccessController;
51 import java.security.PrivilegedAction;
52 import java.util.ArrayList;
53 import java.util.Collections;
54 import java.util.HashMap;
55 import java.util.Iterator;
56 import java.util.List;
57 import java.util.Map;
58
59 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
60 import org.codehaus.groovy.runtime.DefaultGroovyStaticMethods;
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.13 $
69 */
70 public class MetaClassRegistry {
71 private Map metaClasses = Collections.synchronizedMap(new HashMap());
72 private boolean useAccessible;
73 private GroovyClassLoader loader =
74 (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
75 public Object run() {
76 return new GroovyClassLoader(getClass().getClassLoader());
77 }
78 });
79
80 public static final int LOAD_DEFAULT = 0;
81 public static final int DONT_LOAD_DEFAULT = 1;
82 private static MetaClassRegistry instanceInclude;
83 private static MetaClassRegistry instanceExclude;
84
85
86 public MetaClassRegistry() {
87 this(true);
88 }
89
90 public MetaClassRegistry(int loadDefault) {
91 if (loadDefault == LOAD_DEFAULT) {
92 this.useAccessible = true;
93
94 lookup(DefaultGroovyMethods.class).registerInstanceMethods();
95 lookup(DefaultGroovyStaticMethods.class).registerStaticMethods();
96 checkInitialised();
97 } else {
98 this.useAccessible = true;
99
100 }
101 }
102
103 /***
104 * @param useAccessible defines whether or not the {@link AccessibleObject.setAccessible()}
105 * method will be called to enable access to all methods when using reflection
106 */
107 public MetaClassRegistry(boolean useAccessible) {
108 this.useAccessible = useAccessible;
109
110
111 lookup(DefaultGroovyMethods.class).registerInstanceMethods();
112 lookup(DefaultGroovyStaticMethods.class).registerStaticMethods();
113 checkInitialised();
114 }
115
116 public MetaClass getMetaClass(Class theClass) {
117 MetaClass answer = (MetaClass) metaClasses.get(theClass);
118 if (answer == null) {
119 try {
120 answer = new MetaClass(this, theClass);
121 answer.checkInitialised();
122 }
123 catch (IntrospectionException e) {
124 throw new GroovyRuntimeException(
125 "Could not introspect class: " + theClass.getName() + ". Reason: " + e,
126 e);
127 }
128 metaClasses.put(theClass, answer);
129 }
130 return answer;
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 */
166 void checkInitialised() {
167
168
169 List list = new ArrayList(metaClasses.values());
170 for (Iterator iter = list.iterator(); iter.hasNext();) {
171 MetaClass metaClass = (MetaClass) iter.next();
172 metaClass.checkInitialised();
173 }
174 }
175
176 /***
177 * Used by MetaClass when registering new methods which avoids initializing the MetaClass instances on lookup
178 */
179 MetaClass lookup(Class theClass) {
180 MetaClass answer = (MetaClass) metaClasses.get(theClass);
181 if (answer == null) {
182 try {
183 answer = new MetaClass(this, theClass);
184 }
185 catch (IntrospectionException e) {
186 throw new GroovyRuntimeException(
187 "Could not introspect class: " + theClass.getName() + ". Reason: " + e,
188 e);
189 }
190 metaClasses.put(theClass, answer);
191 }
192 return answer;
193 }
194
195
196 public MetaMethod getDefinedMethod(Class theClass, String methodName, Class[] args, boolean isStatic) {
197 MetaClass metaclass = this.getMetaClass(theClass);
198 if (metaclass == null) {
199 return null;
200 } else {
201 if (isStatic) {
202 return metaclass.retrieveStaticMethod(methodName, args);
203 } else {
204 return metaclass.retrieveMethod(methodName, args);
205 }
206 }
207 }
208
209 public Constructor getDefinedConstructor(Class theClass, Class[] args) {
210 MetaClass metaclass = this.getMetaClass(theClass);
211 if (metaclass == null) {
212 return null;
213 } else {
214 return metaclass.retrieveConstructor(args);
215 }
216 }
217 /***
218 * Singleton of MetaClassRegistry. Shall we use threadlocal to store the instance?
219 * @param includeExtension
220 * @return
221 */
222 public static MetaClassRegistry getIntance(int includeExtension) {
223 if (includeExtension != DONT_LOAD_DEFAULT) {
224 if (instanceInclude == null) {
225 instanceInclude = new MetaClassRegistry();
226 }
227 return instanceInclude;
228 }
229 else {
230 if (instanceExclude == null) {
231 instanceExclude = new MetaClassRegistry(DONT_LOAD_DEFAULT);
232 }
233 return instanceExclude;
234 }
235 }
236 }