KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > definition > SystemDefinitionContainer


1 /**************************************************************************************
2  * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
3  * http://aspectwerkz.codehaus.org *
4  * ---------------------------------------------------------------------------------- *
5  * The software in this package is published under the terms of the LGPL license *
6  * a copy of which has been included with this distribution in the license.txt file. *
7  **************************************************************************************/

8 package org.codehaus.aspectwerkz.definition;
9
10 import org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor;
11
12 import java.net.URL JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Enumeration JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.Map JavaDoc;
17 import java.util.Set JavaDoc;
18 import java.util.WeakHashMap JavaDoc;
19 import java.util.HashSet JavaDoc;
20 import java.util.List JavaDoc;
21 import java.io.File JavaDoc;
22
23 /**
24  * The SystemDefintionContainer maintains all the definition and is aware of the classloader hierarchy. <p/>A
25  * ThreadLocal structure is used during weaving to store current classloader defintion hierarchy. <p/>Due to
26  * getResources() API, we maintain a perClassLoader loaded resource list so that it contains only resource defined
27  * within the classloader and not its parent.
28  *
29  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
30  */

31 public class SystemDefinitionContainer {
32
33     /**
34      * Map of SystemDefinition[List] per ClassLoader.
35      * NOTE: null key is supported
36      */

37     public static final Map JavaDoc s_classLoaderSystemDefinitions = new WeakHashMap JavaDoc();
38     /**
39      * Map of SystemDefinition[List] per ClassLoader, with the hierarchy structure
40      * NOTE: null key is supported
41      */

42     public static Map JavaDoc s_classLoaderHierarchicalSystemDefinitions = new WeakHashMap JavaDoc();
43
44     /**
45      * Map of SystemDefinition location (as URL[List]) per ClassLoader
46      * NOTE: null key is supported
47      */

48     public static final Map JavaDoc s_classLoaderDefinitionLocations = new WeakHashMap JavaDoc();
49
50     /**
51      * Default location for default AspectWerkz definition file, JVM wide
52      */

53     public static final String JavaDoc URL_JVM_OPTION_SYSTEM = System.getProperty(
54             "aspectwerkz.definition.file",
55             "no -Daspectwerkz.definition.file"
56     );
57
58     /**
59      * The AOP deployment descriptor for any deployed unit Note: Tomcat 5 does not handles war/META-INF
60      */

61     public static final String JavaDoc AOP_META_INF_XML_FILE = "META-INF/aop.xml";
62
63     /**
64      * The AOP deployment descriptor for any deployed unit in a webapp TODO for EAR/EJB/JCA stuff
65      */

66     public static final String JavaDoc AOP_WEB_INF_XML_FILE = "../aop.xml";
67
68     public static final String JavaDoc WEB_WEB_INF_XML_FILE = "../web.xml";
69
70     /**
71      * An internal flag to disable registration of the -Daspectwerkz.definition.file definition in the System class
72      * loader. This is used only in offline mode, where these definitions are registered programmatically at the
73      * compilation class loader level.
74      */

75     private static boolean s_disableSystemWideDefinition = false;
76
77     private static final String JavaDoc VIRTUAL_SYSTEM_ID_PREFIX = "virtual_";
78
79     /**
80      * Register a new ClassLoader in the system and gather all its definition and parents definitions.
81      *
82      * @param loader the class loader to register
83      */

84     private static void registerClassLoader(final ClassLoader JavaDoc loader) {
85         synchronized (s_classLoaderSystemDefinitions) {
86             if (s_classLoaderSystemDefinitions.containsKey(loader)) {
87                 return;
88             }
89
90             // else - register
91

92             // skip boot classloader and ext classloader
93
if (loader == null) {
94                 // by defaults, there is always the virtual definition, that has lowest precedence
95
Set JavaDoc defaults = new HashSet JavaDoc();
96                 defaults.add(SystemDefinition.createVirtualDefinitionAt(loader));
97                 s_classLoaderSystemDefinitions.put(loader, defaults);
98                 s_classLoaderDefinitionLocations.put(loader, new ArrayList JavaDoc());
99                 
100                 return;
101             }
102
103             // register parents first
104
registerClassLoader(loader.getParent());
105
106             // then register -D.. if system classloader and then all META-INF/aop.xml
107
try {
108                 final Set JavaDoc definitions = new HashSet JavaDoc();
109                 final List JavaDoc locationOfDefinitions = new ArrayList JavaDoc();
110
111                 // early registration to avoid recursion
112
s_classLoaderSystemDefinitions.put(loader, definitions);
113                 s_classLoaderDefinitionLocations.put(loader, locationOfDefinitions);
114
115                 // is this system classloader ?
116
if ((loader == ClassLoader.getSystemClassLoader()) && !s_disableSystemWideDefinition) {
117                     // -D..file=... sysdef
118
definitions.addAll(DefinitionLoader.getDefaultDefinition(loader));
119                     locationOfDefinitions.add(new File JavaDoc(URL_JVM_OPTION_SYSTEM).toURL());
120                 }
121                 if (loader.getResource(WEB_WEB_INF_XML_FILE) != null) {
122                     Enumeration JavaDoc webres = loader.getResources(AOP_WEB_INF_XML_FILE);
123                     while (webres.hasMoreElements()) {
124                         URL JavaDoc def = (URL JavaDoc) webres.nextElement();
125                         if (isDefinedBy(loader, def)) {
126                             ;
127                         } else {
128                             definitions.addAll(XmlParser.parseNoCache(loader, def));
129                             locationOfDefinitions.add(def);
130                         }
131                     }
132                 }
133                 Enumeration JavaDoc res = loader.getResources(AOP_META_INF_XML_FILE);
134                 while (res.hasMoreElements()) {
135                     URL JavaDoc def = (URL JavaDoc) res.nextElement();
136                     if (isDefinedBy(loader, def)) {
137                         ;
138                     } else {
139                         definitions.addAll(XmlParser.parseNoCache(loader, def));
140                         locationOfDefinitions.add(def);
141                     }
142                 }
143
144                 // there is always the virtual definition, that has lowest precedence
145
definitions.add(SystemDefinition.createVirtualDefinitionAt(loader));
146
147                 dump(loader);
148             } catch (Throwable JavaDoc t) {
149                 t.printStackTrace();
150             }
151         }
152     }
153
154     /**
155      * Hotdeploy a list of SystemDefintions as defined at the level of the given ClassLoader
156      * <p/>
157      * Note: this is used for Offline mode.
158      *
159      * @param loader ClassLoader
160      * @param definitions SystemDefinitions list
161      */

162     public static void deployDefinitions(final ClassLoader JavaDoc loader, final Set JavaDoc definitions) {
163         synchronized (s_classLoaderSystemDefinitions) {
164
165             // make sure the classloader is known
166
registerClassLoader(loader);
167
168             //unchanged: s_classLoaderDefinitionLocations
169

170             // propagate change by flushing hierachical cache in all childs
171
flushHierarchicalSystemDefinitionsBelow(loader);
172
173             // update
174
Set JavaDoc defs = (Set JavaDoc) s_classLoaderSystemDefinitions.get(loader);
175             defs.addAll(definitions);
176             dump(loader);
177         }
178     }
179
180     private static void flushHierarchicalSystemDefinitionsBelow(ClassLoader JavaDoc loader) {
181         // lock already owned
182
//synchronized (s_classLoaderSystemDefinitions) {
183
Map JavaDoc classLoaderHierarchicalSystemDefinitions = new WeakHashMap JavaDoc();
184         for (Iterator JavaDoc iterator = s_classLoaderHierarchicalSystemDefinitions.entrySet().iterator(); iterator.hasNext();) {
185             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iterator.next();
186             ClassLoader JavaDoc currentLoader = (ClassLoader JavaDoc) entry.getKey();
187             if (isChildOf(currentLoader, loader)) {
188                 ;// flushed
189
} else {
190                 classLoaderHierarchicalSystemDefinitions.put(currentLoader, entry.getValue());
191             }
192         }
193         s_classLoaderHierarchicalSystemDefinitions = classLoaderHierarchicalSystemDefinitions;
194         //}
195
}
196
197     /**
198      * Lookup for a given SystemDefinition by uuid within a given ClassLoader.
199      * <p/>
200      * The lookup does go thru the ClassLoader hierarchy
201      *
202      * @param loader ClassLoader
203      * @param uuid system uuid
204      * @return SystemDefinition or null if no such defined definition
205      */

206     public static SystemDefinition getDefinitionFor(final ClassLoader JavaDoc loader, final String JavaDoc uuid) {
207         for (Iterator JavaDoc defs = getDefinitionsFor(loader).iterator(); defs.hasNext();) {
208             SystemDefinition def = (SystemDefinition) defs.next();
209             if (def.getUuid().equals(uuid)) {
210                 return def;
211             }
212         }
213         return null;
214     }
215
216     /**
217      * Return the list of SystemDefinitions visible at the given ClassLoader level.
218      * <p/>
219      * It does handle the ClassLoader hierarchy.
220      *
221      * @param loader
222      * @return SystemDefinitions list
223      */

224     public static Set JavaDoc getDefinitionsFor(final ClassLoader JavaDoc loader) {
225         return getHierarchicalDefinitionsFor(loader);
226     }
227
228     /**
229      * Return the list of SystemDefinitions defined at the given ClassLoader level.
230      * <p/>
231      * It does NOT handle the ClassLoader hierarchy.
232      *
233      * @param loader
234      * @return SystemDefinitions list
235      */

236     public static Set JavaDoc getDefinitionsAt(final ClassLoader JavaDoc loader) {
237         // make sure the classloader is registered
238
registerClassLoader(loader);
239         return (Set JavaDoc) s_classLoaderSystemDefinitions.get(loader);
240     }
241
242 // /**
243
// * Returns all the system definitions, including the virtual system.
244
// *
245
// * @param loader
246
// * @return
247
// */
248
// public static Set getRegularAndVirtualDefinitionsFor(final ClassLoader loader) {
249
// final Set allDefs = new HashSet();
250
// allDefs.addAll(getDefinitionsFor(loader));
251
// allDefs.add(getVirtualDefinitionFor(loader));
252
// return allDefs;
253
// }
254

255     /**
256      * Returns the virtual system for the class loader specified.
257      * <p/>
258      * There is ONE and ONLY ONE virtual system per classloader ie several per classloader
259      * hierachy. This definition hosts hotdeployed aspects. This method returns the
260      * one corresponding to the given classloader only.
261      *
262      * @param loader the class loader
263      * @return the virtual system
264      */

265     public static SystemDefinition getVirtualDefinitionAt(final ClassLoader JavaDoc loader) {
266         // since virtual uuid is mapped to a classloader, a direct lookup on uuid is enough
267
return getDefinitionFor(loader, getVirtualDefinitionUuid(loader));
268     }
269
270     /**
271      * Returns the uuid for the virtual system definition for the given classloader
272      *
273      * @param loader
274      * @return
275      */

276     public static String JavaDoc getVirtualDefinitionUuid(ClassLoader JavaDoc loader) {
277         // handle bootclassloader with care
278
int hash = loader == null ? 0 : loader.hashCode();
279         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(VIRTUAL_SYSTEM_ID_PREFIX);
280         return sb.append(hash).toString();
281     }
282
283 // /**
284
// * Returns the list of all ClassLoaders registered so far Note: when a child ClassLoader is registered, all its
285
// * parent hierarchy is registered
286
// *
287
// * @return ClassLoader Set
288
// */
289
// public static Set getAllRegisteredClassLoaders() {
290
// return s_classLoaderSystemDefinitions.keySet();
291
// }
292

293     /**
294      * Turns on the option to avoid -Daspectwerkz.definition.file handling.
295      */

296     public static void disableSystemWideDefinition() {
297         s_disableSystemWideDefinition = true;
298     }
299
300     /**
301      * Returns the gathered SystemDefinition visible from a classloader.
302      * <p/>
303      * This method is using a cache. Caution when
304      * modifying this method since when an aop.xml is loaded, the aspect classes gets loaded as well, which triggers
305      * this cache, while the system is in fact not yet initialized properly. </p>
306      *
307      * @param loader
308      * @return set with the system definitions
309      */

310     private static Set JavaDoc getHierarchicalDefinitionsFor(final ClassLoader JavaDoc loader) {
311         synchronized (s_classLoaderSystemDefinitions) {
312             // check cache
313
if (s_classLoaderHierarchicalSystemDefinitions.containsKey(loader)) {
314                 return (Set JavaDoc) s_classLoaderHierarchicalSystemDefinitions.get(loader);
315             } else {
316                 // make sure the classloader is known
317
registerClassLoader(loader);
318
319                 Set JavaDoc defs = new HashSet JavaDoc();
320                 // put it in the cache now since this method is recursive
321
s_classLoaderHierarchicalSystemDefinitions.put(loader, defs);
322                 if (loader == null) {
323                     ; // go on to put in the cache at the end
324
} else {
325                     ClassLoader JavaDoc parent = loader.getParent();
326                     defs.addAll(getHierarchicalDefinitionsFor(parent));
327                 }
328                 defs.addAll((Set JavaDoc) s_classLoaderSystemDefinitions.get(loader));
329
330                 return defs;
331             }
332         }
333     }
334
335     /**
336      * Check if a given resource has already been registered to a classloader and its parent hierachy
337      *
338      * @param loader the classloader which might define the resource
339      * @param def the resource
340      * @return true if classloader or its parent defines the resource
341      * @TODO what if child shares parent path?
342      * @TODO What happens with smylinking and xml in jars etc ?
343      * @TODO Needs test
344      * @TODO No need for the s_ map
345      * @TODO KICK the def map and crawl up the CL parents and redo a getResources check instead
346      */

347     private static boolean isDefinedBy(final ClassLoader JavaDoc loader, final URL JavaDoc def) {
348         if (loader == null) {
349             return false;
350         }
351         ArrayList JavaDoc defLocation = (ArrayList JavaDoc) s_classLoaderDefinitionLocations.get(loader);
352         if (defLocation != null) {
353             for (Iterator JavaDoc it = defLocation.iterator(); it.hasNext();) {
354                 URL JavaDoc definedDef = (URL JavaDoc) it.next();
355                 if (definedDef.sameFile(def)) {
356                     return true;
357                 }
358             }
359         }
360         return isDefinedBy(loader.getParent(), def);
361     }
362
363     /**
364      * Pretty dump a classloader
365      *
366      * @param loader
367      */

368     private static void dump(final ClassLoader JavaDoc loader) {
369         if (!AspectWerkzPreProcessor.VERBOSE) {
370             return;
371         }
372
373         StringBuffer JavaDoc dump = new StringBuffer JavaDoc("******************************************************************");
374         dump.append("\n* ClassLoader = ");
375
376         //Note: Tomcat classLoader.toString is too verbose so we allow 120 chars.
377
if ((loader != null) && (loader.toString().length() < 120)) {
378             dump.append(loader.toString()).append("@").append(loader.hashCode());
379         } else if (loader != null) {
380             dump.append(loader.getClass().getName()).append("@").append(loader.hashCode());
381         } else {
382             dump.append("null");
383         }
384
385         Set JavaDoc defs = (Set JavaDoc) s_classLoaderSystemDefinitions.get(loader);
386         for (Iterator JavaDoc it = defs.iterator(); it.hasNext();) {
387             SystemDefinition def = (SystemDefinition) it.next();
388             dump.append("\n* SystemID = ").append(def.getUuid());
389             dump.append(", ").append(def.getAspectDefinitions().size()).append(" aspects.");
390         }
391         for (Iterator JavaDoc it = ((List JavaDoc) s_classLoaderDefinitionLocations.get(loader)).iterator(); it.hasNext();) {
392             dump.append("\n* ").append(it.next());
393         }
394         dump.append("\n******************************************************************");
395         System.out.println(dump.toString());
396     }
397
398     /**
399      * Returns true if the given classloader is a child of the given parent classloader
400      *
401      * @param loader
402      * @param parentLoader
403      * @return
404      */

405     private static boolean isChildOf(ClassLoader JavaDoc loader, ClassLoader JavaDoc parentLoader) {
406         if (loader == null) {
407             if (parentLoader == null) {
408                 return true;
409             } else {
410                 return false;
411             }
412         } else if (loader.equals(parentLoader)) {
413             return true;
414         } else {
415             return isChildOf(loader.getParent(), parentLoader);
416         }
417     }
418 }
Popular Tags