KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > definition > SystemDefinitionContainer


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

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

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

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

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

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

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

60   public static final String JavaDoc AOP_META_INF_XML_FILE = "META-INF/aop_xml";
61
62   /**
63    * The AOP deployment descriptor for any deployed unit in a webapp.
64    */

65   public static final String JavaDoc AOP_WEB_INF_XML_FILE = "../aop.xml";
66
67   public static final String JavaDoc WEB_WEB_INF_XML_FILE = "../web.xml";
68
69   /**
70    * The UUID of the single AspectWerkz system if only one definition is used.
71    */

72   public static final String JavaDoc DEFAULT_SYSTEM = "default";
73   /**
74    * The path to the definition file.
75    */

76   public static final String JavaDoc DEFINITION_FILE = System.getProperty("aspectwerkz.definition.file", null);
77   /**
78    * The default name for the definition file.
79    */

80   public static final String JavaDoc DEFAULT_DEFINITION_FILE_NAME = "aspectwerkz.xml";
81   
82   /**
83    * An internal flag to disable registration of the -Daspectwerkz.definition.file definition in the System class
84    * loader. This is used only in offline mode, where these definitions are registered programmatically at the
85    * compilation class loader level.
86    */

87   private static boolean s_disableSystemWideDefinition = false;
88
89   private static final String JavaDoc VIRTUAL_SYSTEM_ID_PREFIX = "virtual_";
90
91   /**
92    * Register a new ClassLoader in the system and gather all its definition and parents definitions.
93    *
94    * @param loader the class loader to register
95    */

96   private static void registerClassLoader(final ClassLoader JavaDoc loader) {
97     synchronized (s_classLoaderSystemDefinitions) {
98       if (s_classLoaderSystemDefinitions.containsKey(loader)) {
99         return;
100       }
101
102       // else - register
103

104       // skip boot classloader and ext classloader
105
if (loader == null) {
106         // by defaults, there is always the virtual definition, that has lowest precedence
107
Set JavaDoc defaults = new HashSet JavaDoc();
108         //TODO AVOPT
109
defaults.add(SystemDefinition.createVirtualDefinitionAt(loader));
110         s_classLoaderSystemDefinitions.put(loader, defaults);
111         s_classLoaderDefinitionLocations.put(loader, new ArrayList JavaDoc());
112
113         return;
114       }
115
116       // register parents first
117
registerClassLoader(loader.getParent());
118
119       // then register -D.. if system classloader and then all META-INF/aop.xml
120
try {
121         final Set JavaDoc definitions = new HashSet JavaDoc();
122         final List JavaDoc locationOfDefinitions = new ArrayList JavaDoc();
123
124         // early registration to avoid recursion
125
s_classLoaderSystemDefinitions.put(loader, definitions);
126         s_classLoaderDefinitionLocations.put(loader, locationOfDefinitions);
127
128         // is this system classloader ?
129
if ((loader == ClassLoader.getSystemClassLoader()) && !s_disableSystemWideDefinition) {
130           // -D..file=... sysdef
131
definitions.addAll(getDefaultDefinition(loader));
132           locationOfDefinitions.add(new File JavaDoc(URL_JVM_OPTION_SYSTEM).toURL());
133         }
134         
135         // causes dead lock on WLS when invoking getResource(..) - https://jira.terracotta.lan/jira/browse/LKC-2548
136
// code is not needed since we never use an aop.xml file anyway
137
// if (loader.getResource(WEB_WEB_INF_XML_FILE) != null) {
138
// Enumeration webres = loader.getResources(AOP_WEB_INF_XML_FILE);
139
// while (webres.hasMoreElements()) {
140
// URL def = (URL) webres.nextElement();
141
// if (isDefinedBy(loader, def)) {
142
// ;
143
// } else {
144
// definitions.addAll(XmlParser.parseNoCache(loader, def));
145
// locationOfDefinitions.add(def);
146
// }
147
// }
148
// }
149
// Enumeration res = loader.getResources(AOP_META_INF_XML_FILE);
150
// while (res.hasMoreElements()) {
151
// URL def = (URL) res.nextElement();
152
// if (isDefinedBy(loader, def)) {
153
// ;
154
// } else {
155
// definitions.addAll(XmlParser.parseNoCache(loader, def));
156
// locationOfDefinitions.add(def);
157
// }
158
// }
159

160         // there is always the virtual definition, that has lowest precedence
161
SystemDefinition virtualDef = SystemDefinitionContainer.getVirtualDefinitionFor(loader);
162         if (virtualDef == null) {
163           definitions.add(SystemDefinition.createVirtualDefinitionAt(loader));
164         }
165
166         printDeploymentInfoFor(loader);
167       } catch (Throwable JavaDoc t) {
168         t.printStackTrace();
169       }
170     }
171   }
172
173   /**
174    * Hotdeploy a list of SystemDefintions as defined at the level of the given ClassLoader
175    * <p/>
176    * Note: this is used for Offline mode.
177    *
178    * @param loader ClassLoader
179    * @param definitions SystemDefinitions list
180    */

181   public static void deployDefinitions(final ClassLoader JavaDoc loader, final Set JavaDoc definitions) {
182     synchronized (s_classLoaderSystemDefinitions) {
183
184       // make sure the classloader is known
185
registerClassLoader(loader);
186
187       //unchanged: s_classLoaderDefinitionLocations
188

189       // propagate change by flushing hierarchical cache in all childs
190
flushHierarchicalSystemDefinitionsBelow(loader);
191
192       // update
193
Set JavaDoc defs = (Set JavaDoc) s_classLoaderSystemDefinitions.get(loader);
194       defs.addAll(definitions);
195       printDeploymentInfoFor(loader);
196     }
197   }
198
199   /**
200    * Lookup for a given SystemDefinition by uuid within a given ClassLoader.
201    * <p/>
202    * The lookup does go thru the ClassLoader hierarchy
203    *
204    * @param loader ClassLoader
205    * @param uuid system uuid
206    * @return SystemDefinition or null if no such defined definition
207    */

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

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

238   public static Set JavaDoc getAllDefinitionsFor(final ClassLoader JavaDoc loader) {
239     // make sure the classloader is registered
240
registerClassLoader(loader);
241     return (Set JavaDoc) s_classLoaderSystemDefinitions.get(loader);
242   }
243
244   /**
245    * Returns the virtual system for the class loader specified.
246    * <p/>
247    * There is ONE and ONLY ONE virtual system per classloader ie several per classloader
248    * hierachy. This definition hosts hotdeployed aspects. This method returns the
249    * one corresponding to the given classloader only.
250    *
251    * @param loader the class loader
252    * @return the virtual system
253    */

254   public static SystemDefinition getVirtualDefinitionFor(final ClassLoader JavaDoc loader) {
255     // since virtual uuid is mapped to a classloader, a direct lookup on uuid is enough
256
return getDefinitionFor(loader, getVirtualDefinitionUuidFor(loader));
257   }
258
259   /**
260    * Returns the uuid for the virtual system definition for the given classloader
261    *
262    * @param loader
263    * @return uuit
264    */

265   public static String JavaDoc getVirtualDefinitionUuidFor(final ClassLoader JavaDoc loader) {
266     // handle bootclassloader with care
267
int hash = loader == null ? 0 : loader.hashCode();
268     StringBuffer JavaDoc sb = new StringBuffer JavaDoc(VIRTUAL_SYSTEM_ID_PREFIX);
269     return sb.append(hash).toString();
270   }
271
272   /**
273    * Turns on the option to avoid -Daspectwerkz.definition.file handling.
274    */

275   public static void disableSystemWideDefinition() {
276     synchronized (s_classLoaderSystemDefinitions) {
277       s_disableSystemWideDefinition = true;
278     }
279   }
280
281   /**
282    * Pretty printDeploymentInfo a classloader
283    *
284    * @param loader
285    */

286   public static void printDeploymentInfoFor(final ClassLoader JavaDoc loader) {
287     if (!Properties.PRINT_DEPLOYMENT_INFO) {
288       return;
289     }
290
291     StringBuffer JavaDoc dump = new StringBuffer JavaDoc("******************************************************************");
292     dump.append("\n* class loader = ");
293
294     //Note: Tomcat classLoader.toString is too verbose so we allow 120 chars.
295
if ((loader != null) && (loader.toString().length() < 120)) {
296       dump.append(loader.toString()).append("@").append(loader.hashCode());
297     } else if (loader != null) {
298       dump.append(loader.getClass().getName()).append("@").append(loader.hashCode());
299     } else {
300       dump.append("null");
301     }
302
303     Set JavaDoc defs = (Set JavaDoc) s_classLoaderSystemDefinitions.get(loader);
304     for (Iterator JavaDoc it = defs.iterator(); it.hasNext();) {
305       SystemDefinition def = (SystemDefinition) it.next();
306       Collection JavaDoc aspects = def.getAspectDefinitions();
307       dump.append("\n* system id = ").append(def.getUuid());
308       dump.append(", ").append(aspects.size()).append(" aspects.");
309       for (Iterator JavaDoc it2 = aspects.iterator(); it2.hasNext();) {
310         AspectDefinition aspect = (AspectDefinition) it2.next();
311         dump.append("\n* aspect: " + aspect.getClassName());
312       }
313     }
314     for (Iterator JavaDoc it = ((List JavaDoc) s_classLoaderDefinitionLocations.get(loader)).iterator(); it.hasNext();) {
315       dump.append("\n* ").append(it.next());
316     }
317     dump.append("\n******************************************************************");
318     System.out.println(dump.toString());
319   }
320
321   /**
322    * Returns true if the given classloader is a child of the given parent classloader
323    *
324    * @param loader
325    * @param parentLoader
326    * @return bool
327    */

328   public static boolean isChildOf(final ClassLoader JavaDoc loader, final ClassLoader JavaDoc parentLoader) {
329     if (loader == null) {
330       if (parentLoader == null) {
331         return true;
332       } else {
333         return false;
334       }
335     } else if (loader.equals(parentLoader)) {
336       return true;
337     } else {
338       return isChildOf(loader.getParent(), parentLoader);
339     }
340   }
341
342
343   /**
344    * Returns the gathered SystemDefinition visible from a classloader.
345    * <p/>
346    * This method is using a cache. Caution when
347    * modifying this method since when an aop.xml is loaded, the aspect classes gets loaded as well, which triggers
348    * this cache, while the system is in fact not yet initialized properly. </p>
349    *
350    * @param loader
351    * @return set with the system definitions
352    */

353   private static Set JavaDoc getHierarchicalDefinitionsFor(final ClassLoader JavaDoc loader) {
354     synchronized (s_classLoaderSystemDefinitions) {
355       // make sure the classloader is known
356
registerClassLoader(loader);
357
358       Set JavaDoc defs = new HashSet JavaDoc();
359       // put it in the cache now since this method is recursive
360
s_classLoaderHierarchicalSystemDefinitions.put(loader, defs);
361       if (loader == null) {
362         // go on to put in the cache at the end
363
} else {
364         ClassLoader JavaDoc parent = loader.getParent();
365         defs.addAll(getHierarchicalDefinitionsFor(parent));
366       }
367       defs.addAll((Set JavaDoc) s_classLoaderSystemDefinitions.get(loader));
368
369       return defs;
370     }
371   }
372
373   /**
374    * Check if a given resource has already been registered to a classloader and its parent hierachy
375    *
376    * @param loader the classloader which might define the resource
377    * @param def the resource
378    * @return true if classloader or its parent defines the resource
379    * @TODO what if child shares parent path?
380    * @TODO What happens with smylinking and xml in jars etc ?
381    * @TODO Needs test
382    * @TODO No need for the s_ map
383    * @TODO KICK the def map and crawl up the CL parents and redo a getResources check instead
384    */

385   private static boolean isDefinedBy(final ClassLoader JavaDoc loader, final URL JavaDoc def) {
386     if (loader == null) {
387       return false;
388     }
389     ArrayList JavaDoc defLocation = (ArrayList JavaDoc) s_classLoaderDefinitionLocations.get(loader);
390     if (defLocation != null) {
391       for (Iterator JavaDoc it = defLocation.iterator(); it.hasNext();) {
392         URL JavaDoc definedDef = (URL JavaDoc) it.next();
393         if (definedDef.sameFile(def)) {
394           return true;
395         }
396       }
397     }
398     return isDefinedBy(loader.getParent(), def);
399   }
400
401   private static void flushHierarchicalSystemDefinitionsBelow(final ClassLoader JavaDoc loader) {
402     Map JavaDoc classLoaderHierarchicalSystemDefinitions = new WeakHashMap JavaDoc();
403     for (Iterator JavaDoc iterator = s_classLoaderHierarchicalSystemDefinitions.entrySet().iterator(); iterator.hasNext();) {
404       Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iterator.next();
405       ClassLoader JavaDoc currentLoader = (ClassLoader JavaDoc) entry.getKey();
406       if (isChildOf(currentLoader, loader)) {
407         // flushed
408
} else {
409         classLoaderHierarchicalSystemDefinitions.put(currentLoader, entry.getValue());
410       }
411     }
412     s_classLoaderHierarchicalSystemDefinitions = classLoaderHierarchicalSystemDefinitions;
413   }
414
415   /**
416    * Returns the default defintion.
417    *
418    * @param loader
419    * @return the default defintion
420    */

421   public static Set JavaDoc getDefaultDefinition(final ClassLoader JavaDoc loader) {
422     if (DEFINITION_FILE != null) {
423       File JavaDoc file = new File JavaDoc(DEFINITION_FILE);
424       if (file.canRead()) {
425         try {
426           return XmlParser.parseNoCache(loader, file.toURL());
427         } catch (MalformedURLException JavaDoc e) {
428           System.err.println("<WARN> Cannot read " + DEFINITION_FILE);
429           e.printStackTrace();
430         }
431       } else {
432         System.err.println("<WARN> Cannot read " + DEFINITION_FILE);
433       }
434     }
435     return new HashSet JavaDoc();
436   }
437
438 }
Popular Tags