Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

ClassLoaderWeavingAdaptor.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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. * David Knibb weaving context enhancments
  12. *******************************************************************************/
  13. package org.aspectj.weaver.loadtime;
  14. import org.aspectj.asm.IRelationship;
  15. import org.aspectj.bridge.IMessage;
  16. import org.aspectj.bridge.ISourceLocation;
  17. import org.aspectj.bridge.Message;
  18. import org.aspectj.bridge.MessageUtil;
  19. import org.aspectj.weaver.ICrossReferenceHandler;
  20. import org.aspectj.weaver.ResolvedType;
  21. import org.aspectj.weaver.UnresolvedType;
  22. import org.aspectj.weaver.World;
  23. import org.aspectj.weaver.bcel.BcelWeaver;
  24. import org.aspectj.weaver.bcel.BcelWorld;
  25. import org.aspectj.weaver.loadtime.definition.Definition;
  26. import org.aspectj.weaver.loadtime.definition.DocumentParser;
  27. import org.aspectj.weaver.patterns.PatternParser;
  28. import org.aspectj.weaver.patterns.TypePattern;
  29. import org.aspectj.weaver.tools.GeneratedClassHandler;
  30. import org.aspectj.weaver.tools.WeavingAdaptor;
  31. import java.io.File;
  32. import java.io.InputStream;
  33. import java.io.IOException;
  34. import java.net.URL;
  35. import java.util.ArrayList;
  36. import java.util.Enumeration;
  37. import java.util.HashMap;
  38. import java.util.Iterator;
  39. import java.util.List;
  40. import java.util.Properties;
  41. import java.util.StringTokenizer;
  42. /**
  43. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  44. */
  45. public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
  46. private final static String AOP_XML = "META-INF/aop.xml";
  47. private List m_dumpTypePattern = new ArrayList();
  48. private List m_includeTypePattern = new ArrayList();
  49. private List m_excludeTypePattern = new ArrayList();
  50. private List m_aspectExcludeTypePattern = new ArrayList();
  51. private StringBuffer namespace;
  52. private IWeavingContext weavingContext;
  53. public ClassLoaderWeavingAdaptor(final ClassLoader loader, IWeavingContext wContext) {
  54. super(null);// at this stage we don't have yet a generatedClassHandler to define to the VM the closures
  55. this.generatedClassHandler = new GeneratedClassHandler() {
  56. /**
  57. * Callback when we need to define a Closure in the JVM
  58. *
  59. * @param name
  60. * @param bytes
  61. */
  62. public void acceptClass(String name, byte[] bytes) {
  63. //TODO av make dump configurable
  64. try {
  65. if (shouldDump(name.replace('/', '.'))) {
  66. Aj.dump(name, bytes);
  67. }
  68. } catch (Throwable throwable) {
  69. throwable.printStackTrace();
  70. }
  71. Aj.defineClass(loader, name, bytes);// could be done lazily using the hook
  72. }
  73. };
  74. if(wContext==null){
  75. weavingContext = new DefaultWeavingContext(loader);
  76. }else{
  77. weavingContext = wContext ;
  78. }
  79. bcelWorld = new BcelWorld(
  80. loader, messageHandler, new ICrossReferenceHandler() {
  81. public void addCrossReference(ISourceLocation from, ISourceLocation to, IRelationship.Kind kind, boolean runtimeTest) {
  82. ;// for tools only
  83. }
  84. }
  85. );
  86. // //TODO this AJ code will call
  87. // //org.aspectj.apache.bcel.Repository.setRepository(this);
  88. // //ie set some static things
  89. // //==> bogus as Bcel is expected to be
  90. // org.aspectj.apache.bcel.Repository.setRepository(new ClassLoaderRepository(loader));
  91. weaver = new BcelWeaver(bcelWorld);
  92. // register the definitions
  93. registerDefinitions(weaver, loader);
  94. messageHandler = bcelWorld.getMessageHandler();
  95. // after adding aspects
  96. weaver.prepareForWeave();
  97. }
  98. /**
  99. * Load and cache the aop.xml/properties according to the classloader visibility rules
  100. *
  101. * @param weaver
  102. * @param loader
  103. */
  104. private void registerDefinitions(final BcelWeaver weaver, final ClassLoader loader) {
  105. try {
  106. MessageUtil.info(messageHandler, "register classloader " + ((loader!=null)?loader.getClass().getName()+"@"+loader.hashCode():"null"));
  107. //TODO av underoptimized: we will parse each XML once per CL that see it
  108. List definitions = new ArrayList();
  109. //TODO av dev mode needed ? TBD -Daj5.def=...
  110. if (ClassLoader.getSystemClassLoader().equals(loader)) {
  111. String file = System.getProperty("aj5.def", null);
  112. if (file != null) {
  113. MessageUtil.info(messageHandler, "using (-Daj5.def) " + file);
  114. definitions.add(DocumentParser.parse((new File(file)).toURL()));
  115. }
  116. }
  117. String resourcePath = System.getProperty("org.aspectj.weaver.loadtime.configuration",AOP_XML);
  118. StringTokenizer st = new StringTokenizer(resourcePath,";");
  119. while(st.hasMoreTokens()){
  120. Enumeration xmls = weavingContext.getResources(st.nextToken());
  121. // System.out.println("? registerDefinitions: found-aop.xml=" + xmls.hasMoreElements() + ", loader=" + loader);
  122. while (xmls.hasMoreElements()) {
  123. URL xml = (URL) xmls.nextElement();
  124. MessageUtil.info(messageHandler, "using " + xml.getFile());
  125. definitions.add(DocumentParser.parse(xml));
  126. }
  127. }
  128. // still go thru if definitions is empty since we will configure
  129. // the default message handler in there
  130. registerOptions(weaver, loader, definitions);
  131. registerAspectExclude(weaver, loader, definitions);
  132. registerAspects(weaver, loader, definitions);
  133. registerIncludeExclude(weaver, loader, definitions);
  134. registerDump(weaver, loader, definitions);
  135. } catch (Exception e) {
  136. weaver.getWorld().getMessageHandler().handleMessage(
  137. new Message("Register definition failed", IMessage.WARNING, e, null)
  138. );
  139. }
  140. }
  141. /**
  142. * Configure the weaver according to the option directives
  143. * TODO av - don't know if it is that good to reuse, since we only allow a small subset of options in LTW
  144. *
  145. * @param weaver
  146. * @param loader
  147. * @param definitions
  148. */
  149. private void registerOptions(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  150. StringBuffer allOptions = new StringBuffer();
  151. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  152. Definition definition = (Definition) iterator.next();
  153. allOptions.append(definition.getWeaverOptions()).append(' ');
  154. }
  155. Options.WeaverOption weaverOption = Options.parse(allOptions.toString(), loader);
  156. // configure the weaver and world
  157. // AV - code duplicates AspectJBuilder.initWorldAndWeaver()
  158. World world = weaver.getWorld();
  159. world.setMessageHandler(weaverOption.messageHandler);
  160. world.setXlazyTjp(weaverOption.lazyTjp);
  161. world.setXHasMemberSupportEnabled(weaverOption.hasMember);
  162. world.setPinpointMode(weaverOption.pinpoint);
  163. weaver.setReweavableMode(weaverOption.reWeavable, false);
  164. world.setXnoInline(weaverOption.noInline);
  165. world.setBehaveInJava5Way(weaverOption.java5);//TODO should be autodetected ?
  166. //-Xlintfile: first so that lint wins
  167. if (weaverOption.lintFile != null) {
  168. InputStream resource = null;
  169. try {
  170. resource = loader.getResourceAsStream(weaverOption.lintFile);
  171. Exception failure = null;
  172. if (resource != null) {
  173. try {
  174. Properties properties = new Properties();
  175. properties.load(resource);
  176. world.getLint().setFromProperties(properties);
  177. } catch (IOException e) {
  178. failure = e;
  179. }
  180. }
  181. if (failure != null || resource == null) {
  182. world.getMessageHandler().handleMessage(new Message(
  183. "Cannot access resource for -Xlintfile:"+weaverOption.lintFile,
  184. IMessage.WARNING,
  185. failure,
  186. null));
  187. }
  188. } finally {
  189. try { resource.close(); } catch (Throwable t) {;}
  190. }
  191. }
  192. if (weaverOption.lint != null) {
  193. if (weaverOption.lint.equals("default")) {//FIXME should be AjBuildConfig.AJLINT_DEFAULT but yetanother deps..
  194. bcelWorld.getLint().loadDefaultProperties();
  195. } else {
  196. bcelWorld.getLint().setAll(weaverOption.lint);
  197. }
  198. }
  199. //TODO proceedOnError option
  200. }
  201. private void registerAspectExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  202. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  203. Definition definition = (Definition) iterator.next();
  204. for (Iterator iterator1 = definition.getAspectExcludePatterns().iterator(); iterator1.hasNext();) {
  205. String exclude = (String) iterator1.next();
  206. TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
  207. m_aspectExcludeTypePattern.add(excludePattern);
  208. }
  209. }
  210. }
  211. /**
  212. * Register the aspect, following include / exclude rules
  213. *
  214. * @param weaver
  215. * @param loader
  216. * @param definitions
  217. */
  218. private void registerAspects(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  219. //TODO: the exclude aspect allow to exclude aspect defined upper in the CL hierarchy - is it what we want ??
  220. // if not, review the getResource so that we track which resource is defined by which CL
  221. //it aspectClassNames
  222. //exclude if in any of the exclude list
  223. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  224. Definition definition = (Definition) iterator.next();
  225. for (Iterator aspects = definition.getAspectClassNames().iterator(); aspects.hasNext();) {
  226. String aspectClassName = (String) aspects.next();
  227. if (acceptAspect(aspectClassName)) {
  228. weaver.addLibraryAspect(aspectClassName);
  229. //generate key for SC
  230. String aspectCode = readAspect(aspectClassName, loader);
  231. if(namespace==null){
  232. namespace=new StringBuffer(aspectCode);
  233. }else{
  234. namespace = namespace.append(";"+aspectCode);
  235. }
  236. }
  237. }
  238. }
  239. //it concreteAspects
  240. //exclude if in any of the exclude list
  241. //TODO
  242. }
  243. /**
  244. * Register the include / exclude filters
  245. *
  246. * @param weaver
  247. * @param loader
  248. * @param definitions
  249. */
  250. private void registerIncludeExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  251. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  252. Definition definition = (Definition) iterator.next();
  253. for (Iterator iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) {
  254. String include = (String) iterator1.next();
  255. TypePattern includePattern = new PatternParser(include).parseTypePattern();
  256. m_includeTypePattern.add(includePattern);
  257. }
  258. for (Iterator iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) {
  259. String exclude = (String) iterator1.next();
  260. TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
  261. m_excludeTypePattern.add(excludePattern);
  262. }
  263. }
  264. }
  265. /**
  266. * Register the dump filter
  267. *
  268. * @param weaver
  269. * @param loader
  270. * @param definitions
  271. */
  272. private void registerDump(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  273. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  274. Definition definition = (Definition) iterator.next();
  275. for (Iterator iterator1 = definition.getDumpPatterns().iterator(); iterator1.hasNext();) {
  276. String dump = (String) iterator1.next();
  277. TypePattern pattern = new PatternParser(dump).parseTypePattern();
  278. m_dumpTypePattern.add(pattern);
  279. }
  280. }
  281. }
  282. protected boolean accept(String className) {
  283. // avoid ResolvedType if not needed
  284. if (m_excludeTypePattern.isEmpty() && m_includeTypePattern.isEmpty()) {
  285. return true;
  286. }
  287. //TODO AV - optimize for className.startWith only
  288. ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(className), true);
  289. //exclude are "AND"ed
  290. for (Iterator iterator = m_excludeTypePattern.iterator(); iterator.hasNext();) {
  291. TypePattern typePattern = (TypePattern) iterator.next();
  292. if (typePattern.matchesStatically(classInfo)) {
  293. // exclude match - skip
  294. return false;
  295. }
  296. }
  297. //include are "OR"ed
  298. boolean accept = true;//defaults to true if no include
  299. for (Iterator iterator = m_includeTypePattern.iterator(); iterator.hasNext();) {
  300. TypePattern typePattern = (TypePattern) iterator.next();
  301. accept = typePattern.matchesStatically(classInfo);
  302. if (accept) {
  303. break;
  304. }
  305. // goes on if this include did not match ("OR"ed)
  306. }
  307. return accept;
  308. }
  309. private boolean acceptAspect(String aspectClassName) {
  310. // avoid ResolvedType if not needed
  311. if (m_aspectExcludeTypePattern.isEmpty()) {
  312. return true;
  313. }
  314. //TODO AV - optimize for className.startWith only
  315. ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(aspectClassName), true);
  316. //exclude are "AND"ed
  317. for (Iterator iterator = m_aspectExcludeTypePattern.iterator(); iterator.hasNext();) {
  318. TypePattern typePattern = (TypePattern) iterator.next();
  319. if (typePattern.matchesStatically(classInfo)) {
  320. // exclude match - skip
  321. return false;
  322. }
  323. }
  324. return true;
  325. }
  326. public boolean shouldDump(String className) {
  327. // avoid ResolvedType if not needed
  328. if (m_dumpTypePattern.isEmpty()) {
  329. return false;
  330. }
  331. //TODO AV - optimize for className.startWith only
  332. ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(className), true);
  333. //dump
  334. for (Iterator iterator = m_dumpTypePattern.iterator(); iterator.hasNext();) {
  335. TypePattern typePattern = (TypePattern) iterator.next();
  336. if (typePattern.matchesStatically(classInfo)) {
  337. // dump match
  338. return true;
  339. }
  340. }
  341. return false;
  342. }
  343. /*
  344. * shared classes methods
  345. */
  346. /**
  347. * @return Returns the key.
  348. */
  349. public String getNamespace() {
  350. if(namespace==null) return "";
  351. else return new String(namespace);
  352. }
  353. /**
  354. * Check to see if any classes are stored in the generated classes cache.
  355. * Then flush the cache if it is not empty
  356. * @return true if a class has been generated and is stored in the cache
  357. */
  358. public boolean generatedClassesExist(){
  359. if(generatedClasses.size()>0) {
  360. return true;
  361. }
  362. return false;
  363. }
  364. /**
  365. * Flush the generated classes cache
  366. */
  367. public void flushGeneratedClasses(){
  368. generatedClasses = new HashMap();
  369. }
  370. /**
  371. * Read in an aspect from the disk and return its bytecode as a String
  372. * @param name the name of the aspect to read in
  373. * @return the bytecode representation of the aspect
  374. */
  375. private String readAspect(String name, ClassLoader loader){
  376. try {
  377. String result = "";
  378. InputStream is = loader.getResourceAsStream(name.replace('.','/')+".class");
  379. int b = is.read();
  380. while(b!=-1){
  381. result = result + b;
  382. b=is.read();
  383. }
  384. is.close();
  385. return result;
  386. } catch (IOException e) {
  387. e.printStackTrace();
  388. return "";
  389. }catch (NullPointerException e) {
  390. //probably tried to read in a "non aspect @missing@" aspect
  391. System.err.println("ClassLoaderWeavingAdaptor.readAspect() name: "+name+" Exception: "+e);
  392. return "";
  393. }
  394. }
  395. }