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 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*******************************************************************************
  2. * Copyright (c) Jonas Bonér, Alexandre Vasseur
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Common Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/cpl-v10.html
  7. *******************************************************************************/
  8. package org.aspectj.weaver.loadtime;
  9. import org.aspectj.asm.IRelationship;
  10. import org.aspectj.bridge.IMessage;
  11. import org.aspectj.bridge.ISourceLocation;
  12. import org.aspectj.bridge.Message;
  13. import org.aspectj.weaver.ICrossReferenceHandler;
  14. import org.aspectj.weaver.World;
  15. import org.aspectj.weaver.bcel.BcelWeaver;
  16. import org.aspectj.weaver.bcel.BcelWorld;
  17. import org.aspectj.weaver.loadtime.definition.Definition;
  18. import org.aspectj.weaver.loadtime.definition.DocumentParser;
  19. import org.aspectj.weaver.tools.GeneratedClassHandler;
  20. import org.aspectj.weaver.tools.WeavingAdaptor;
  21. import java.io.File;
  22. import java.io.FileOutputStream;
  23. import java.lang.reflect.Method;
  24. import java.net.URL;
  25. import java.util.ArrayList;
  26. import java.util.Enumeration;
  27. import java.util.Iterator;
  28. import java.util.List;
  29. import java.util.Map;
  30. import java.util.WeakHashMap;
  31. /**
  32. * Adapter between the generic class pre processor interface and the AspectJ weaver
  33. * Load time weaving consistency relies on Bcel.setRepository
  34. *
  35. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  36. */
  37. public class Aj implements ClassPreProcessor {
  38. /**
  39. * Initialization
  40. */
  41. public void initialize() {
  42. ;
  43. }
  44. /**
  45. * Weave
  46. *
  47. * @param className
  48. * @param bytes
  49. * @param loader
  50. * @return
  51. */
  52. public byte[] preProcess(String className, byte[] bytes, ClassLoader loader) {
  53. //System.out.println("Aj.preProcess " + className + " @ " + loader + " " + Thread.currentThread());
  54. //TODO av needs to spec and doc that
  55. //TODO av should skip org.aspectj as well unless done somewhere else
  56. if (loader == null
  57. || className == null) {
  58. // skip boot loader or null classes (hibernate)
  59. return bytes;
  60. }
  61. try {
  62. byte[] weaved = WeaverContainer.getWeaver(loader).weaveClass(className, bytes);
  63. //TODO av make dump optionnal and configurable
  64. __dump(className, weaved);
  65. return weaved;
  66. } catch (Throwable t) {
  67. t.printStackTrace();
  68. return bytes;
  69. }
  70. }
  71. /**
  72. * Cache of weaver
  73. * There is one weaver per classloader
  74. */
  75. static class WeaverContainer {
  76. private static Map weavingAdaptors = new WeakHashMap();
  77. static WeavingAdaptor getWeaver(ClassLoader loader) {
  78. synchronized (weavingAdaptors) {
  79. WeavingAdaptor weavingAdaptor = (WeavingAdaptor) weavingAdaptors.get(loader);
  80. if (weavingAdaptor == null) {
  81. weavingAdaptor = new ClassLoaderWeavingAdaptor(loader);
  82. weavingAdaptors.put(loader, weavingAdaptor);
  83. }
  84. return weavingAdaptor;
  85. }
  86. }
  87. }
  88. /**
  89. * Adaptor with the AspectJ WeavingAdaptor
  90. */
  91. static class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
  92. public ClassLoaderWeavingAdaptor(final ClassLoader loader) {
  93. super(null);// at this stage we don't have yet a generatedClassHandler to define to the VM the closures
  94. this.generatedClassHandler = new GeneratedClassHandler() {
  95. /**
  96. * Callback when we need to define a Closure in the JVM
  97. *
  98. * @param name
  99. * @param bytes
  100. */
  101. public void acceptClass(String name, byte[] bytes) {
  102. //TODO av make dump configurable
  103. try {
  104. __dump(name, bytes);
  105. } catch (Throwable throwable) {
  106. throwable.printStackTrace();
  107. }
  108. defineClass(loader, name, bytes);// could be done lazily using the hook
  109. }
  110. };
  111. bcelWorld = new BcelWorld(
  112. loader, messageHandler, new ICrossReferenceHandler() {
  113. public void addCrossReference(ISourceLocation from, ISourceLocation to, IRelationship.Kind kind, boolean runtimeTest) {
  114. ;// for tools only
  115. }
  116. }
  117. );
  118. // //TODO this AJ code will call
  119. // //org.aspectj.apache.bcel.Repository.setRepository(this);
  120. // //ie set some static things
  121. // //==> bogus as Bcel is expected to be
  122. // org.aspectj.apache.bcel.Repository.setRepository(new ClassLoaderRepository(loader));
  123. weaver = new BcelWeaver(bcelWorld);
  124. // register the definitions
  125. registerDefinitions(weaver, loader);
  126. // after adding aspects
  127. weaver.prepareForWeave();
  128. }
  129. }
  130. private static void defineClass(ClassLoader loader, String name, byte[] bytes) {
  131. try {
  132. //TODO av protection domain, and optimize
  133. Method defineClass = ClassLoader.class.getDeclaredMethod(
  134. "defineClass", new Class[]{
  135. String.class, bytes.getClass(), int.class, int.class
  136. }
  137. );
  138. defineClass.setAccessible(true);
  139. defineClass.invoke(
  140. loader, new Object[]{
  141. name,
  142. bytes,
  143. new Integer(0),
  144. new Integer(bytes.length)
  145. }
  146. );
  147. } catch (Throwable t) {
  148. t.printStackTrace();
  149. }
  150. }
  151. /**
  152. * Dump the given bytcode in _dump/...
  153. *
  154. * @param name
  155. * @param b
  156. * @throws Throwable
  157. */
  158. private static void __dump(String name, byte[] b) throws Throwable {
  159. String className = name.replace('.', '/');
  160. final File dir;
  161. if (className.indexOf('/') > 0) {
  162. dir = new File("_dump" + File.separator + className.substring(0, className.lastIndexOf('/')));
  163. } else {
  164. dir = new File("_dump");
  165. }
  166. dir.mkdirs();
  167. String fileName = "_dump" + File.separator + className + ".class";
  168. FileOutputStream os = new FileOutputStream(fileName);
  169. os.write(b);
  170. os.close();
  171. }
  172. /**
  173. * Load and cache the aop.xml/properties according to the classloader visibility rules
  174. *
  175. * @param weaver
  176. * @param loader
  177. */
  178. private static void registerDefinitions(final BcelWeaver weaver, final ClassLoader loader) {
  179. try {
  180. //TODO av underoptimized: we will parse each XML once per CL that see it
  181. Enumeration xmls = loader.getResources("/META-INF/aop.xml");
  182. List definitions = new ArrayList();
  183. //TODO av dev mode needed ? TBD -Daj5.def=...
  184. if (loader != null && loader != ClassLoader.getSystemClassLoader().getParent()) {
  185. String file = System.getProperty("aj5.def", null);
  186. if (file != null) {
  187. definitions.add(DocumentParser.parse((new File(file)).toURL()));
  188. }
  189. }
  190. while (xmls.hasMoreElements()) {
  191. URL xml = (URL) xmls.nextElement();
  192. definitions.add(DocumentParser.parse(xml));
  193. }
  194. registerOptions(weaver, loader, definitions);
  195. registerAspects(weaver, loader, definitions);
  196. registerFilters(weaver, loader, definitions);
  197. } catch (Exception e) {
  198. weaver.getWorld().getMessageHandler().handleMessage(
  199. new Message("Register definition failed", IMessage.FAIL, e, null)
  200. );
  201. }
  202. }
  203. /**
  204. * Configure the weaver according to the option directives
  205. * TODO av - don't know if it is that good to reuse, since we only allow a small subset of options in LTW
  206. *
  207. * @param weaver
  208. * @param loader
  209. * @param definitions
  210. */
  211. private static void registerOptions(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  212. StringBuffer allOptions = new StringBuffer();
  213. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  214. Definition definition = (Definition) iterator.next();
  215. allOptions.append(definition.getWeaverOptions()).append(' ');
  216. }
  217. Options.WeaverOption weaverOption = Options.parse(allOptions.toString(), loader);
  218. // configure the weaver and world
  219. // AV - code duplicates AspectJBuilder.initWorldAndWeaver()
  220. World world = weaver.getWorld();
  221. world.setMessageHandler(weaverOption.messageHandler);
  222. world.setXlazyTjp(weaverOption.lazyTjp);
  223. weaver.setReweavableMode(weaverOption.reWeavable, false);
  224. world.setXnoInline(weaverOption.noInline);
  225. world.setBehaveInJava5Way(weaverOption.java5);
  226. //TODO proceedOnError option
  227. }
  228. /**
  229. * Register the aspect, following include / exclude rules
  230. *
  231. * @param weaver
  232. * @param loader
  233. * @param definitions
  234. */
  235. private static void registerAspects(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  236. //TODO: the exclude aspect allow to exclude aspect defined upper in the CL hierarchy - is it what we want ??
  237. // if not, review the getResource so that we track which resource is defined by which CL
  238. //it aspectClassNames
  239. //exclude if in any of the exclude list
  240. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  241. Definition definition = (Definition) iterator.next();
  242. for (Iterator aspects = definition.getAspectClassNames().iterator(); aspects.hasNext();) {
  243. String aspectClassName = (String) aspects.next();
  244. if (!Definition.isAspectExcluded(aspectClassName, definitions)) {
  245. weaver.addLibraryAspect(aspectClassName);
  246. }
  247. }
  248. }
  249. //it concreteAspects
  250. //exclude if in any of the exclude list
  251. //TODO
  252. }
  253. /**
  254. * Register the include / exclude filters
  255. *
  256. * @param weaver
  257. * @param loader
  258. * @param definitions
  259. */
  260. private static void registerFilters(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  261. //TODO
  262. ;
  263. }
  264. }