You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Aj.java 13KB

13 years ago
11 years ago
11 years ago
13 years ago
11 years ago
13 years ago
13 years ago
11 years ago
13 years ago
9 years ago
9 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*******************************************************************************
  2. * Copyright (c) 2005 Contributors.
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Alexandre Vasseur initial implementation
  11. *******************************************************************************/
  12. package org.aspectj.weaver.loadtime;
  13. import java.lang.ref.ReferenceQueue;
  14. import java.lang.ref.WeakReference;
  15. import java.security.ProtectionDomain;
  16. import java.util.ArrayList;
  17. import java.util.Collections;
  18. import java.util.HashMap;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.Set;
  23. import java.util.StringTokenizer;
  24. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  25. import org.aspectj.weaver.Dump;
  26. import org.aspectj.weaver.tools.Trace;
  27. import org.aspectj.weaver.tools.TraceFactory;
  28. import org.aspectj.weaver.tools.WeavingAdaptor;
  29. import org.aspectj.weaver.tools.cache.SimpleCache;
  30. import org.aspectj.weaver.tools.cache.SimpleCacheFactory;
  31. /**
  32. * Adapter between the generic class pre processor interface and the AspectJ weaver Load time weaving consistency relies on
  33. * Bcel.setRepository
  34. *
  35. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  36. */
  37. public class Aj implements ClassPreProcessor {
  38. private IWeavingContext weavingContext;
  39. public static SimpleCache laCache=SimpleCacheFactory.createSimpleCache();
  40. /**
  41. * References are added to this queue when their associated classloader is removed, and once on here that indicates that we
  42. * should tidy up the adaptor map and remove the adaptor (weaver) from the map we are maintaining from adaptorkey > adaptor
  43. * (weaver)
  44. */
  45. private static ReferenceQueue adaptorQueue = new ReferenceQueue();
  46. private static Trace trace = TraceFactory.getTraceFactory().getTrace(Aj.class);
  47. public Aj() {
  48. this(null);
  49. }
  50. public Aj(IWeavingContext context) {
  51. if (trace.isTraceEnabled())
  52. trace.enter("<init>", this, new Object[] { context, getClass().getClassLoader() });
  53. this.weavingContext = context;
  54. if (trace.isTraceEnabled())
  55. trace.exit("<init>");
  56. }
  57. /**
  58. * Initialization
  59. */
  60. public void initialize() {
  61. }
  62. private final static String deleLoader = "sun.reflect.DelegatingClassLoader";
  63. /**
  64. * Weave
  65. *
  66. * @param className
  67. * @param bytes
  68. * @param loader
  69. * @return woven bytes
  70. */
  71. public byte[] preProcess(String className, byte[] bytes, ClassLoader loader, ProtectionDomain protectionDomain) {
  72. // TODO AV needs to doc that
  73. if (loader == null || className == null || loader.getClass().getName().equals(deleLoader)) {
  74. // skip boot loader, null classes (hibernate), or those from a reflection loader
  75. return bytes;
  76. }
  77. if (loadersToSkip != null) {
  78. // Check whether to reject it
  79. if (loadersToSkip.contains(loader.getClass().getName())) {
  80. // System.out.println("debug: no weaver created for loader '"+loader.getClass().getName()+"'");
  81. return bytes;
  82. }
  83. }
  84. if (trace.isTraceEnabled())
  85. trace.enter("preProcess", this, new Object[] { className, bytes, loader });
  86. if (trace.isTraceEnabled())
  87. trace.event("preProcess", this, new Object[] { loader.getParent(), Thread.currentThread().getContextClassLoader() });
  88. try {
  89. synchronized (loader) {
  90. if (SimpleCacheFactory.isEnabled()) {
  91. byte[] cacheBytes= laCache.getAndInitialize(className, bytes,loader,protectionDomain);
  92. if (cacheBytes!=null){
  93. return cacheBytes;
  94. }
  95. }
  96. WeavingAdaptor weavingAdaptor = WeaverContainer.getWeaver(loader, weavingContext);
  97. if (weavingAdaptor == null) {
  98. if (trace.isTraceEnabled())
  99. trace.exit("preProcess");
  100. return bytes;
  101. }
  102. try {
  103. weavingAdaptor.setActiveProtectionDomain(protectionDomain);
  104. byte[] newBytes = weavingAdaptor.weaveClass(className, bytes, false);
  105. Dump.dumpOnExit(weavingAdaptor.getMessageHolder(), true);
  106. if (trace.isTraceEnabled())
  107. trace.exit("preProcess", newBytes);
  108. if (SimpleCacheFactory.isEnabled()) {
  109. laCache.put(className, bytes, newBytes);
  110. }
  111. return newBytes;
  112. } finally {
  113. weavingAdaptor.setActiveProtectionDomain(null);
  114. }
  115. }
  116. /* Don't like to do this but JVMTI swallows all exceptions */
  117. } catch (Throwable th) {
  118. trace.error(className, th);
  119. Dump.dumpWithException(th);
  120. // FIXME AV wondering if we should have the option to fail (throw runtime exception) here
  121. // would make sense at least in test f.e. see TestHelper.handleMessage()
  122. if (trace.isTraceEnabled())
  123. trace.exit("preProcess", th);
  124. return bytes;
  125. } finally {
  126. CompilationAndWeavingContext.resetForThread();
  127. }
  128. }
  129. /**
  130. * An AdaptorKey is a WeakReference wrapping a classloader reference that will enqueue to a specified queue when the classloader
  131. * is GC'd. Since the AdaptorKey is used as a key into a hashmap we need to give it a non-varying hashcode/equals
  132. * implementation, and we need that hashcode not to vary even when the internal referent has been GC'd. The hashcode is
  133. * calculated on creation of the AdaptorKey based on the loader instance that it is wrapping. This means even when the referent
  134. * is gone we can still use the AdaptorKey and it will 'point' to the same place as it always did.
  135. */
  136. private static class AdaptorKey extends WeakReference {
  137. private final int loaderHashCode, sysHashCode, hashValue;
  138. private final String loaderClass;
  139. public AdaptorKey(ClassLoader loader) {
  140. super(loader, adaptorQueue);
  141. loaderHashCode = loader.hashCode();
  142. sysHashCode = System.identityHashCode(loader);
  143. loaderClass = loader.getClass().getName();
  144. hashValue = loaderHashCode + sysHashCode + loaderClass.hashCode();
  145. }
  146. public ClassLoader getClassLoader() {
  147. ClassLoader instance = (ClassLoader) get();
  148. // Assert instance!=null - shouldn't be asked for after a GC of the referent has occurred !
  149. return instance;
  150. }
  151. public boolean equals(Object obj) {
  152. if (!(obj instanceof AdaptorKey)) {
  153. return false;
  154. }
  155. AdaptorKey other = (AdaptorKey) obj;
  156. return (other.loaderHashCode == loaderHashCode)
  157. && (other.sysHashCode == sysHashCode)
  158. && loaderClass.equals(other.loaderClass);
  159. }
  160. public int hashCode() {
  161. return hashValue;
  162. }
  163. }
  164. /**
  165. * The reference queue is only processed when a request is made for a weaver adaptor. This means there can be one or two stale
  166. * weavers left around. If the user knows they have finished all their weaving, they might wish to call removeStaleAdaptors
  167. * which will process anything left on the reference queue containing adaptorKeys for garbage collected classloaders.
  168. *
  169. * @param displayProgress produce System.err info on the tidying up process
  170. * @return number of stale weavers removed
  171. */
  172. public static int removeStaleAdaptors(boolean displayProgress) {
  173. int removed = 0;
  174. synchronized (WeaverContainer.weavingAdaptors) {
  175. if (displayProgress) {
  176. System.err.println("Weaver adaptors before queue processing:");
  177. Map<AdaptorKey,ExplicitlyInitializedClassLoaderWeavingAdaptor> m = WeaverContainer.weavingAdaptors;
  178. Set<AdaptorKey> keys = m.keySet();
  179. for (Iterator<AdaptorKey> iterator = keys.iterator(); iterator.hasNext();) {
  180. Object object = iterator.next();
  181. System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object));
  182. }
  183. }
  184. Object o = adaptorQueue.poll();
  185. while (o != null) {
  186. if (displayProgress)
  187. System.err.println("Processing referencequeue entry " + o);
  188. AdaptorKey wo = (AdaptorKey) o;
  189. boolean didit = WeaverContainer.weavingAdaptors.remove(wo) != null;
  190. if (didit) {
  191. removed++;
  192. } else {
  193. throw new RuntimeException("Eh?? key=" + wo);
  194. }
  195. if (displayProgress)
  196. System.err.println("Removed? " + didit);
  197. o = adaptorQueue.poll();
  198. }
  199. if (displayProgress) {
  200. System.err.println("Weaver adaptors after queue processing:");
  201. Map<AdaptorKey,ExplicitlyInitializedClassLoaderWeavingAdaptor> m = WeaverContainer.weavingAdaptors;
  202. Set<AdaptorKey> keys = m.keySet();
  203. for (Iterator<AdaptorKey> iterator = keys.iterator(); iterator.hasNext();) {
  204. Object object = iterator.next();
  205. System.err.println(object + " = " + WeaverContainer.weavingAdaptors.get(object));
  206. }
  207. }
  208. }
  209. return removed;
  210. }
  211. /**
  212. * @return the number of entries still in the weavingAdaptors map
  213. */
  214. public static int getActiveAdaptorCount() {
  215. return WeaverContainer.weavingAdaptors.size();
  216. }
  217. /**
  218. * Process the reference queue that contains stale AdaptorKeys - the keys are put on the queue when their classloader referent
  219. * is garbage collected and so the associated adaptor (weaver) should be removed from the map
  220. */
  221. public static void checkQ() {
  222. synchronized (adaptorQueue) {
  223. Object o = adaptorQueue.poll();
  224. while (o != null) {
  225. AdaptorKey wo = (AdaptorKey) o;
  226. // boolean removed =
  227. WeaverContainer.weavingAdaptors.remove(wo);
  228. // DBG System.err.println("Evicting key " + wo + " = " + didit);
  229. o = adaptorQueue.poll();
  230. }
  231. }
  232. }
  233. public static List<String> loadersToSkip = null;
  234. static {
  235. // pr271840 - touch the types early and outside the locks
  236. new ExplicitlyInitializedClassLoaderWeavingAdaptor(new ClassLoaderWeavingAdaptor());
  237. try {
  238. String loadersToSkipProperty = System.getProperty("aj.weaving.loadersToSkip","");
  239. StringTokenizer st = new StringTokenizer(loadersToSkipProperty, ",");
  240. if (loadersToSkipProperty != null && loadersToSkip == null) {
  241. if (st.hasMoreTokens()) {
  242. // System.out.println("aj.weaving.loadersToSkip is set. Skipping loaders: '"+loadersToSkipProperty+"'");
  243. loadersToSkip = new ArrayList<String>();
  244. }
  245. while (st.hasMoreTokens()) {
  246. String nextLoader = st.nextToken();
  247. loadersToSkip.add(nextLoader);
  248. }
  249. }
  250. } catch (Exception e) {
  251. // Likely security issue related to property access...
  252. }
  253. }
  254. /**
  255. * Cache of weaver There is one weaver per classloader
  256. */
  257. static class WeaverContainer {
  258. final static Map<AdaptorKey,ExplicitlyInitializedClassLoaderWeavingAdaptor> weavingAdaptors =
  259. Collections.synchronizedMap(new HashMap<AdaptorKey,ExplicitlyInitializedClassLoaderWeavingAdaptor>());
  260. static WeavingAdaptor getWeaver(ClassLoader loader, IWeavingContext weavingContext) {
  261. ExplicitlyInitializedClassLoaderWeavingAdaptor adaptor = null;
  262. AdaptorKey adaptorKey = new AdaptorKey(loader);
  263. String loaderClassName = loader.getClass().getName();
  264. synchronized (weavingAdaptors) {
  265. checkQ();
  266. if (loader.equals(myClassLoader)){
  267. adaptor = myClassLoaderAdaptor;
  268. } else {
  269. adaptor = (ExplicitlyInitializedClassLoaderWeavingAdaptor) weavingAdaptors.get(adaptorKey);
  270. }
  271. if (adaptor == null) {
  272. // create it and put it back in the weavingAdaptors map but avoid any kind of instantiation
  273. // within the synchronized block
  274. ClassLoaderWeavingAdaptor weavingAdaptor = new ClassLoaderWeavingAdaptor();
  275. adaptor = new ExplicitlyInitializedClassLoaderWeavingAdaptor(weavingAdaptor);
  276. if(myClassLoaderAdaptor == null && loader.equals(myClassLoader)){
  277. myClassLoaderAdaptor = adaptor;
  278. } else {
  279. weavingAdaptors.put(adaptorKey, adaptor);
  280. }
  281. }
  282. }
  283. // perform the initialization
  284. return adaptor.getWeavingAdaptor(loader, weavingContext);
  285. }
  286. private static final ClassLoader myClassLoader = WeavingAdaptor.class.getClassLoader();
  287. private static ExplicitlyInitializedClassLoaderWeavingAdaptor myClassLoaderAdaptor;
  288. }
  289. static class ExplicitlyInitializedClassLoaderWeavingAdaptor {
  290. private final ClassLoaderWeavingAdaptor weavingAdaptor;
  291. private boolean isInitialized;
  292. public ExplicitlyInitializedClassLoaderWeavingAdaptor(ClassLoaderWeavingAdaptor weavingAdaptor) {
  293. this.weavingAdaptor = weavingAdaptor;
  294. this.isInitialized = false;
  295. }
  296. private void initialize(ClassLoader loader, IWeavingContext weavingContext) {
  297. if (!isInitialized) {
  298. isInitialized = true;
  299. weavingAdaptor.initialize(loader, weavingContext);
  300. }
  301. }
  302. public ClassLoaderWeavingAdaptor getWeavingAdaptor(ClassLoader loader, IWeavingContext weavingContext) {
  303. initialize(loader, weavingContext);
  304. return weavingAdaptor;
  305. }
  306. }
  307. /**
  308. * Returns a namespace based on the contest of the aspects available
  309. */
  310. public String getNamespace(ClassLoader loader) {
  311. ClassLoaderWeavingAdaptor weavingAdaptor = (ClassLoaderWeavingAdaptor) WeaverContainer.getWeaver(loader, weavingContext);
  312. return weavingAdaptor.getNamespace();
  313. }
  314. /**
  315. * Check to see if any classes have been generated for a particular classes loader. Calls
  316. * ClassLoaderWeavingAdaptor.generatedClassesExist()
  317. *
  318. * @param loader the class cloder
  319. * @return true if classes have been generated.
  320. */
  321. public boolean generatedClassesExist(ClassLoader loader) {
  322. return ((ClassLoaderWeavingAdaptor) WeaverContainer.getWeaver(loader, weavingContext)).generatedClassesExistFor(null);
  323. }
  324. public void flushGeneratedClasses(ClassLoader loader) {
  325. ((ClassLoaderWeavingAdaptor) WeaverContainer.getWeaver(loader, weavingContext)).flushGeneratedClasses();
  326. }
  327. }