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.

ClassLoaderWeavingAdaptor.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  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 java.io.File;
  15. import java.io.IOException;
  16. import java.io.InputStream;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.net.MalformedURLException;
  20. import java.net.URL;
  21. import java.util.ArrayList;
  22. import java.util.Enumeration;
  23. import java.util.HashMap;
  24. import java.util.HashSet;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.Properties;
  28. import java.util.Set;
  29. import java.util.StringTokenizer;
  30. import org.aspectj.bridge.AbortException;
  31. import org.aspectj.bridge.Constants;
  32. import org.aspectj.util.LangUtil;
  33. import org.aspectj.weaver.Lint;
  34. import org.aspectj.weaver.ResolvedType;
  35. import org.aspectj.weaver.UnresolvedType;
  36. import org.aspectj.weaver.World;
  37. import org.aspectj.weaver.Lint.Kind;
  38. import org.aspectj.weaver.bcel.BcelWeakClassLoaderReference;
  39. import org.aspectj.weaver.bcel.BcelWeaver;
  40. import org.aspectj.weaver.bcel.BcelWorld;
  41. import org.aspectj.weaver.bcel.Utility;
  42. import org.aspectj.weaver.loadtime.definition.Definition;
  43. import org.aspectj.weaver.loadtime.definition.DocumentParser;
  44. import org.aspectj.weaver.ltw.LTWWorld;
  45. import org.aspectj.weaver.patterns.PatternParser;
  46. import org.aspectj.weaver.patterns.TypePattern;
  47. import org.aspectj.weaver.tools.GeneratedClassHandler;
  48. import org.aspectj.weaver.tools.Trace;
  49. import org.aspectj.weaver.tools.TraceFactory;
  50. import org.aspectj.weaver.tools.WeavingAdaptor;
  51. /**
  52. * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
  53. */
  54. public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
  55. private final static String AOP_XML = Constants.AOP_USER_XML + ";" + Constants.AOP_AJC_XML + ";" + Constants.AOP_OSGI_XML;
  56. private boolean initialized;
  57. private List m_dumpTypePattern = new ArrayList();
  58. private boolean m_dumpBefore = false;
  59. private boolean dumpDirPerClassloader = false;
  60. private List m_includeTypePattern = new ArrayList();
  61. private List m_excludeTypePattern = new ArrayList();
  62. private List m_includeStartsWith = new ArrayList();
  63. private List m_excludeStartsWith = new ArrayList();
  64. private List m_aspectExcludeTypePattern = new ArrayList();
  65. private List m_aspectExcludeStartsWith = new ArrayList();
  66. private List m_aspectIncludeTypePattern = new ArrayList();
  67. private List m_aspectIncludeStartsWith = new ArrayList();
  68. private StringBuffer namespace;
  69. private IWeavingContext weavingContext;
  70. private List concreteAspects = new ArrayList();
  71. private static Trace trace = TraceFactory.getTraceFactory().getTrace(ClassLoaderWeavingAdaptor.class);
  72. public ClassLoaderWeavingAdaptor() {
  73. super();
  74. if (trace.isTraceEnabled()) {
  75. trace.enter("<init>", this);
  76. }
  77. if (trace.isTraceEnabled()) {
  78. trace.exit("<init>");
  79. }
  80. }
  81. /**
  82. * We don't need a reference to the class loader and using it during construction can cause problems with recursion. It also
  83. * makes sense to supply the weaving context during initialization to.
  84. *
  85. * @deprecated
  86. */
  87. public ClassLoaderWeavingAdaptor(final ClassLoader deprecatedLoader, final IWeavingContext deprecatedContext) {
  88. super();
  89. if (trace.isTraceEnabled()) {
  90. trace.enter("<init>", this, new Object[] { deprecatedLoader, deprecatedContext });
  91. }
  92. if (trace.isTraceEnabled()) {
  93. trace.exit("<init>");
  94. }
  95. }
  96. class SimpleGeneratedClassHandler implements GeneratedClassHandler {
  97. private BcelWeakClassLoaderReference loaderRef;
  98. SimpleGeneratedClassHandler(ClassLoader loader) {
  99. loaderRef = new BcelWeakClassLoaderReference(loader);
  100. }
  101. /**
  102. * Callback when we need to define a Closure in the JVM
  103. *
  104. */
  105. public void acceptClass(String name, byte[] bytes) {
  106. try {
  107. if (shouldDump(name.replace('/', '.'), false)) {
  108. dump(name, bytes, false);
  109. }
  110. } catch (Throwable throwable) {
  111. throwable.printStackTrace();
  112. }
  113. defineClass(loaderRef.getClassLoader(), name, bytes); // could be done lazily using the hook
  114. }
  115. }
  116. protected void initialize(final ClassLoader classLoader, IWeavingContext context) {
  117. if (initialized) {
  118. return;
  119. }
  120. boolean success = true;
  121. // if (trace.isTraceEnabled()) trace.enter("initialize",this,new Object[] { classLoader, context });
  122. this.weavingContext = context;
  123. if (weavingContext == null) {
  124. weavingContext = new DefaultWeavingContext(classLoader);
  125. }
  126. createMessageHandler();
  127. this.generatedClassHandler = new SimpleGeneratedClassHandler(classLoader);
  128. List definitions = weavingContext.getDefinitions(classLoader, this);
  129. if (definitions.isEmpty()) {
  130. disable(); // TODO maw Needed to ensure messages are flushed
  131. if (trace.isTraceEnabled()) {
  132. trace.exit("initialize", definitions);
  133. }
  134. return;
  135. }
  136. bcelWorld = new LTWWorld(classLoader, weavingContext, // TODO when the world works in terms of the context, we can remove
  137. // the loader...
  138. getMessageHandler(), null);
  139. weaver = new BcelWeaver(bcelWorld);
  140. // register the definitions
  141. success = registerDefinitions(weaver, classLoader, definitions);
  142. if (success) {
  143. // after adding aspects
  144. weaver.prepareForWeave();
  145. enable(); // TODO maw Needed to ensure messages are flushed
  146. success = weaveAndDefineConceteAspects();
  147. }
  148. if (success) {
  149. enable();
  150. } else {
  151. disable();
  152. bcelWorld = null;
  153. weaver = null;
  154. }
  155. initialized = true;
  156. if (trace.isTraceEnabled()) {
  157. trace.exit("initialize", isEnabled());
  158. }
  159. }
  160. /**
  161. * Load and cache the aop.xml/properties according to the classloader visibility rules
  162. *
  163. * @param weaver
  164. * @param loader
  165. */
  166. List parseDefinitions(final ClassLoader loader) {
  167. if (trace.isTraceEnabled()) {
  168. trace.enter("parseDefinitions", this);
  169. }
  170. List definitions = new ArrayList();
  171. try {
  172. info("register classloader " + getClassLoaderName(loader));
  173. // TODO av underoptimized: we will parse each XML once per CL that see it
  174. // TODO av dev mode needed ? TBD -Daj5.def=...
  175. if (loader.equals(ClassLoader.getSystemClassLoader())) {
  176. String file = System.getProperty("aj5.def", null);
  177. if (file != null) {
  178. info("using (-Daj5.def) " + file);
  179. definitions.add(DocumentParser.parse((new File(file)).toURL()));
  180. }
  181. }
  182. String resourcePath = System.getProperty("org.aspectj.weaver.loadtime.configuration", AOP_XML);
  183. if (trace.isTraceEnabled()) {
  184. trace.event("parseDefinitions", this, resourcePath);
  185. }
  186. StringTokenizer st = new StringTokenizer(resourcePath, ";");
  187. while (st.hasMoreTokens()) {
  188. String nextDefinition = st.nextToken();
  189. if (nextDefinition.startsWith("file:")) {
  190. try {
  191. String fpath = new URL(nextDefinition).getFile();
  192. File configFile = new File(fpath);
  193. if (!configFile.exists()) {
  194. warn("configuration does not exist: " + nextDefinition);
  195. } else {
  196. definitions.add(DocumentParser.parse(configFile.toURL()));
  197. }
  198. } catch (MalformedURLException mue) {
  199. error("malformed definition url: " + nextDefinition);
  200. }
  201. } else {
  202. Enumeration xmls = weavingContext.getResources(nextDefinition);
  203. // System.out.println("? registerDefinitions: found-aop.xml=" + xmls.hasMoreElements() + ", loader=" + loader);
  204. Set seenBefore = new HashSet();
  205. while (xmls.hasMoreElements()) {
  206. URL xml = (URL) xmls.nextElement();
  207. if (trace.isTraceEnabled()) {
  208. trace.event("parseDefinitions", this, xml);
  209. }
  210. if (!seenBefore.contains(xml)) {
  211. info("using configuration " + weavingContext.getFile(xml));
  212. definitions.add(DocumentParser.parse(xml));
  213. seenBefore.add(xml);
  214. } else {
  215. warn("ignoring duplicate definition: " + xml);
  216. }
  217. }
  218. }
  219. }
  220. if (definitions.isEmpty()) {
  221. info("no configuration found. Disabling weaver for class loader " + getClassLoaderName(loader));
  222. }
  223. } catch (Exception e) {
  224. definitions.clear();
  225. warn("parse definitions failed", e);
  226. }
  227. if (trace.isTraceEnabled()) {
  228. trace.exit("parseDefinitions", definitions);
  229. }
  230. return definitions;
  231. }
  232. private boolean registerDefinitions(final BcelWeaver weaver, final ClassLoader loader, List definitions) {
  233. if (trace.isTraceEnabled()) {
  234. trace.enter("registerDefinitions", this, definitions);
  235. }
  236. boolean success = true;
  237. try {
  238. registerOptions(weaver, loader, definitions);
  239. registerAspectExclude(weaver, loader, definitions);
  240. registerAspectInclude(weaver, loader, definitions);
  241. success = registerAspects(weaver, loader, definitions);
  242. registerIncludeExclude(weaver, loader, definitions);
  243. registerDump(weaver, loader, definitions);
  244. } catch (Exception ex) {
  245. trace.error("register definition failed", ex);
  246. success = false;
  247. warn("register definition failed", (ex instanceof AbortException) ? null : ex);
  248. }
  249. if (trace.isTraceEnabled()) {
  250. trace.exit("registerDefinitions", success);
  251. }
  252. return success;
  253. }
  254. private String getClassLoaderName(ClassLoader loader) {
  255. return weavingContext.getClassLoaderName();
  256. }
  257. /**
  258. * Configure the weaver according to the option directives TODO av - don't know if it is that good to reuse, since we only allow
  259. * a small subset of options in LTW
  260. *
  261. * @param weaver
  262. * @param loader
  263. * @param definitions
  264. */
  265. private void registerOptions(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  266. StringBuffer allOptions = new StringBuffer();
  267. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  268. Definition definition = (Definition) iterator.next();
  269. allOptions.append(definition.getWeaverOptions()).append(' ');
  270. }
  271. Options.WeaverOption weaverOption = Options.parse(allOptions.toString(), loader, getMessageHandler());
  272. // configure the weaver and world
  273. // AV - code duplicates AspectJBuilder.initWorldAndWeaver()
  274. World world = weaver.getWorld();
  275. setMessageHandler(weaverOption.messageHandler);
  276. world.setXlazyTjp(weaverOption.lazyTjp);
  277. world.setXHasMemberSupportEnabled(weaverOption.hasMember);
  278. world.setTiming(weaverOption.timers);
  279. world.setOptionalJoinpoints(weaverOption.optionalJoinpoints);
  280. world.setPinpointMode(weaverOption.pinpoint);
  281. weaver.setReweavableMode(weaverOption.notReWeavable);
  282. world.performExtraConfiguration(weaverOption.xSet);
  283. world.setXnoInline(weaverOption.noInline);
  284. // AMC - autodetect as per line below, needed for AtAjLTWTests.testLTWUnweavable
  285. world.setBehaveInJava5Way(LangUtil.is15VMOrGreater());
  286. world.setAddSerialVerUID(weaverOption.addSerialVersionUID);
  287. /* First load defaults */
  288. bcelWorld.getLint().loadDefaultProperties();
  289. /* Second overlay LTW defaults */
  290. bcelWorld.getLint().adviceDidNotMatch.setKind(null);
  291. /* Third load user file using -Xlintfile so that -Xlint wins */
  292. if (weaverOption.lintFile != null) {
  293. InputStream resource = null;
  294. try {
  295. resource = loader.getResourceAsStream(weaverOption.lintFile);
  296. Exception failure = null;
  297. if (resource != null) {
  298. try {
  299. Properties properties = new Properties();
  300. properties.load(resource);
  301. world.getLint().setFromProperties(properties);
  302. } catch (IOException e) {
  303. failure = e;
  304. }
  305. }
  306. if (failure != null || resource == null) {
  307. warn("Cannot access resource for -Xlintfile:" + weaverOption.lintFile, failure);
  308. // world.getMessageHandler().handleMessage(new Message(
  309. // "Cannot access resource for -Xlintfile:"+weaverOption.lintFile,
  310. // IMessage.WARNING,
  311. // failure,
  312. // null));
  313. }
  314. } finally {
  315. try {
  316. resource.close();
  317. } catch (Throwable t) {
  318. }
  319. }
  320. }
  321. /* Fourth override with -Xlint */
  322. if (weaverOption.lint != null) {
  323. if (weaverOption.lint.equals("default")) {// FIXME should be AjBuildConfig.AJLINT_DEFAULT but yetanother deps..
  324. bcelWorld.getLint().loadDefaultProperties();
  325. } else {
  326. bcelWorld.getLint().setAll(weaverOption.lint);
  327. }
  328. }
  329. // TODO proceedOnError option
  330. }
  331. private void registerAspectExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  332. String fastMatchInfo = null;
  333. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  334. Definition definition = (Definition) iterator.next();
  335. for (Iterator iterator1 = definition.getAspectExcludePatterns().iterator(); iterator1.hasNext();) {
  336. String exclude = (String) iterator1.next();
  337. TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
  338. m_aspectExcludeTypePattern.add(excludePattern);
  339. fastMatchInfo = looksLikeStartsWith(exclude);
  340. if (fastMatchInfo != null) {
  341. m_aspectExcludeStartsWith.add(fastMatchInfo);
  342. }
  343. }
  344. }
  345. }
  346. private void registerAspectInclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  347. String fastMatchInfo = null;
  348. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  349. Definition definition = (Definition) iterator.next();
  350. for (Iterator iterator1 = definition.getAspectIncludePatterns().iterator(); iterator1.hasNext();) {
  351. String include = (String) iterator1.next();
  352. TypePattern includePattern = new PatternParser(include).parseTypePattern();
  353. m_aspectIncludeTypePattern.add(includePattern);
  354. fastMatchInfo = looksLikeStartsWith(include);
  355. if (fastMatchInfo != null) {
  356. m_aspectIncludeStartsWith.add(fastMatchInfo);
  357. }
  358. }
  359. }
  360. }
  361. protected void lint(String name, String[] infos) {
  362. Lint lint = bcelWorld.getLint();
  363. Kind kind = lint.getLintKind(name);
  364. kind.signal(infos, null, null);
  365. }
  366. @Override
  367. public String getContextId() {
  368. return weavingContext.getId();
  369. }
  370. /**
  371. * Register the aspect, following include / exclude rules
  372. *
  373. * @param weaver
  374. * @param loader
  375. * @param definitions
  376. */
  377. private boolean registerAspects(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  378. if (trace.isTraceEnabled()) {
  379. trace.enter("registerAspects", this, new Object[] { weaver, loader, definitions });
  380. }
  381. boolean success = true;
  382. // TODO: the exclude aspect allow to exclude aspect defined upper in the CL hierarchy - is it what we want ??
  383. // if not, review the getResource so that we track which resource is defined by which CL
  384. // iterate aspectClassNames
  385. // exclude if in any of the exclude list
  386. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  387. Definition definition = (Definition) iterator.next();
  388. for (Iterator aspects = definition.getAspectClassNames().iterator(); aspects.hasNext();) {
  389. String aspectClassName = (String) aspects.next();
  390. if (acceptAspect(aspectClassName)) {
  391. info("register aspect " + aspectClassName);
  392. // System.err.println("? ClassLoaderWeavingAdaptor.registerAspects() aspectName=" + aspectClassName +
  393. // ", loader=" + loader + ", bundle=" + weavingContext.getClassLoaderName());
  394. /* ResolvedType aspect = */weaver.addLibraryAspect(aspectClassName);
  395. // generate key for SC
  396. if (namespace == null) {
  397. namespace = new StringBuffer(aspectClassName);
  398. } else {
  399. namespace = namespace.append(";" + aspectClassName);
  400. }
  401. } else {
  402. // warn("aspect excluded: " + aspectClassName);
  403. lint("aspectExcludedByConfiguration", new String[] { aspectClassName, getClassLoaderName(loader) });
  404. }
  405. }
  406. }
  407. // iterate concreteAspects
  408. // exclude if in any of the exclude list - note that the user defined name matters for that to happen
  409. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  410. Definition definition = (Definition) iterator.next();
  411. for (Definition.ConcreteAspect concreteAspect : definition.getConcreteAspects()) {
  412. if (acceptAspect(concreteAspect.name)) {
  413. info("define aspect " + concreteAspect.name);
  414. ConcreteAspectCodeGen gen = new ConcreteAspectCodeGen(concreteAspect, weaver.getWorld());
  415. if (!gen.validate()) {
  416. error("Concrete-aspect '" + concreteAspect.name + "' could not be registered");
  417. success = false;
  418. break;
  419. }
  420. ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes()));
  421. concreteAspects.add(gen);
  422. weaver.addLibraryAspect(concreteAspect.name);
  423. // generate key for SC
  424. if (namespace == null) {
  425. namespace = new StringBuffer(concreteAspect.name);
  426. } else {
  427. namespace = namespace.append(";" + concreteAspect.name);
  428. }
  429. }
  430. }
  431. }
  432. /* We couldn't register one or more aspects so disable the adaptor */
  433. if (!success) {
  434. warn("failure(s) registering aspects. Disabling weaver for class loader " + getClassLoaderName(loader));
  435. }
  436. /* We didn't register any aspects so disable the adaptor */
  437. else if (namespace == null) {
  438. success = false;
  439. info("no aspects registered. Disabling weaver for class loader " + getClassLoaderName(loader));
  440. }
  441. if (trace.isTraceEnabled()) {
  442. trace.exit("registerAspects", success);
  443. }
  444. return success;
  445. }
  446. private boolean weaveAndDefineConceteAspects() {
  447. if (trace.isTraceEnabled()) {
  448. trace.enter("weaveAndDefineConceteAspects", this, concreteAspects);
  449. }
  450. boolean success = true;
  451. for (Iterator iterator = concreteAspects.iterator(); iterator.hasNext();) {
  452. ConcreteAspectCodeGen gen = (ConcreteAspectCodeGen) iterator.next();
  453. String name = gen.getClassName();
  454. byte[] bytes = gen.getBytes();
  455. try {
  456. byte[] newBytes = weaveClass(name, bytes, true);
  457. this.generatedClassHandler.acceptClass(name, newBytes);
  458. } catch (IOException ex) {
  459. trace.error("weaveAndDefineConceteAspects", ex);
  460. error("exception weaving aspect '" + name + "'", ex);
  461. }
  462. }
  463. if (trace.isTraceEnabled()) {
  464. trace.exit("weaveAndDefineConceteAspects", success);
  465. }
  466. return success;
  467. }
  468. /**
  469. * Register the include / exclude filters We duplicate simple patterns in startWith filters that will allow faster matching
  470. * without ResolvedType
  471. *
  472. * @param weaver
  473. * @param loader
  474. * @param definitions
  475. */
  476. private void registerIncludeExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  477. String fastMatchInfo = null;
  478. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  479. Definition definition = (Definition) iterator.next();
  480. for (Iterator iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) {
  481. String include = (String) iterator1.next();
  482. TypePattern includePattern = new PatternParser(include).parseTypePattern();
  483. m_includeTypePattern.add(includePattern);
  484. fastMatchInfo = looksLikeStartsWith(include);
  485. if (fastMatchInfo != null) {
  486. m_includeStartsWith.add(fastMatchInfo);
  487. }
  488. }
  489. for (Iterator iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) {
  490. String exclude = (String) iterator1.next();
  491. TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
  492. m_excludeTypePattern.add(excludePattern);
  493. fastMatchInfo = looksLikeStartsWith(exclude);
  494. if (fastMatchInfo != null) {
  495. m_excludeStartsWith.add(fastMatchInfo);
  496. }
  497. }
  498. }
  499. }
  500. /**
  501. * Checks if the type pattern can be handled as a startswith check
  502. *
  503. * TODO AV - enhance to support "char.sss" ie FQN direclty (match iff equals) we could also add support for "*..*charss"
  504. * endsWith style?
  505. *
  506. * @param typePattern
  507. * @return null if not possible, or the startWith sequence to test against
  508. */
  509. private String looksLikeStartsWith(String typePattern) {
  510. if (typePattern.indexOf('@') >= 0 || typePattern.indexOf('+') >= 0 || typePattern.indexOf(' ') >= 0
  511. || typePattern.charAt(typePattern.length() - 1) != '*') {
  512. return null;
  513. }
  514. // now must looks like with "charsss..*" or "cha.rss..*" etc
  515. // note that "*" and "*..*" won't be fast matched
  516. // and that "charsss.*" will not neither
  517. int length = typePattern.length();
  518. if (typePattern.endsWith("..*") && length > 3) {
  519. if (typePattern.indexOf("..") == length - 3 // no ".." before last sequence
  520. && typePattern.indexOf('*') == length - 1) { // no "*" before last sequence
  521. return typePattern.substring(0, length - 2).replace('$', '.');
  522. // ie "charsss." or "char.rss." etc
  523. }
  524. }
  525. return null;
  526. }
  527. /**
  528. * Register the dump filter
  529. *
  530. * @param weaver
  531. * @param loader
  532. * @param definitions
  533. */
  534. private void registerDump(final BcelWeaver weaver, final ClassLoader loader, final List definitions) {
  535. for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
  536. Definition definition = (Definition) iterator.next();
  537. for (Iterator iterator1 = definition.getDumpPatterns().iterator(); iterator1.hasNext();) {
  538. String dump = (String) iterator1.next();
  539. TypePattern pattern = new PatternParser(dump).parseTypePattern();
  540. m_dumpTypePattern.add(pattern);
  541. }
  542. if (definition.shouldDumpBefore()) {
  543. m_dumpBefore = true;
  544. }
  545. if (definition.createDumpDirPerClassloader()) {
  546. dumpDirPerClassloader = true;
  547. }
  548. }
  549. }
  550. @Override
  551. protected boolean accept(String className, byte[] bytes) {
  552. // avoid ResolvedType if not needed
  553. if (m_excludeTypePattern.isEmpty() && m_includeTypePattern.isEmpty()) {
  554. return true;
  555. }
  556. // still try to avoid ResolvedType if we have simple patterns
  557. String fastClassName = className.replace('/', '.').replace('$', '.');
  558. for (int i = 0; i < m_excludeStartsWith.size(); i++) {
  559. if (fastClassName.startsWith((String) m_excludeStartsWith.get(i))) {
  560. return false;
  561. }
  562. }
  563. /*
  564. * Bug 120363 If we have an exclude pattern that cannot be matched using "starts with" then we cannot fast accept
  565. */
  566. if (m_excludeTypePattern.isEmpty()) {
  567. boolean fastAccept = false;// defaults to false if no fast include
  568. for (int i = 0; i < m_includeStartsWith.size(); i++) {
  569. fastAccept = fastClassName.startsWith((String) m_includeStartsWith.get(i));
  570. if (fastAccept) {
  571. break;
  572. }
  573. }
  574. }
  575. // needs further analysis
  576. // TODO AV - needs refactoring
  577. // during LTW this calling resolve at that stage is BAD as we do have the bytecode from the classloader hook
  578. // but still go thru resolve that will do a getResourcesAsStream on disk
  579. // this is also problematic for jit stub which are not on disk - as often underlying infra
  580. // does returns null or some other info for getResourceAsStream (f.e. WLS 9 CR248491)
  581. // Instead I parse the given bytecode. But this also means it will be parsed again in
  582. // new WeavingClassFileProvider() from WeavingAdaptor.getWovenBytes()...
  583. ensureDelegateInitialized(className, bytes);
  584. ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();// BAD:
  585. // weaver.getWorld().resolve(UnresolvedType.forName(
  586. // className), true);
  587. // exclude are "AND"ed
  588. for (Iterator iterator = m_excludeTypePattern.iterator(); iterator.hasNext();) {
  589. TypePattern typePattern = (TypePattern) iterator.next();
  590. if (typePattern.matchesStatically(classInfo)) {
  591. // exclude match - skip
  592. return false;
  593. }
  594. }
  595. // include are "OR"ed
  596. boolean accept = true;// defaults to true if no include
  597. for (Iterator iterator = m_includeTypePattern.iterator(); iterator.hasNext();) {
  598. TypePattern typePattern = (TypePattern) iterator.next();
  599. accept = typePattern.matchesStatically(classInfo);
  600. if (accept) {
  601. break;
  602. }
  603. // goes on if this include did not match ("OR"ed)
  604. }
  605. return accept;
  606. }
  607. // FIXME we don't use include/exclude of others aop.xml
  608. // this can be nice but very dangerous as well to change that
  609. private boolean acceptAspect(String aspectClassName) {
  610. // avoid ResolvedType if not needed
  611. if (m_aspectExcludeTypePattern.isEmpty() && m_aspectIncludeTypePattern.isEmpty()) {
  612. return true;
  613. }
  614. // still try to avoid ResolvedType if we have simple patterns
  615. // EXCLUDE: if one match then reject
  616. String fastClassName = aspectClassName.replace('/', '.').replace('.', '$');
  617. for (int i = 0; i < m_aspectExcludeStartsWith.size(); i++) {
  618. if (fastClassName.startsWith((String) m_aspectExcludeStartsWith.get(i))) {
  619. return false;
  620. }
  621. }
  622. // INCLUDE: if one match then accept
  623. for (int i = 0; i < m_aspectIncludeStartsWith.size(); i++) {
  624. if (fastClassName.startsWith((String) m_aspectIncludeStartsWith.get(i))) {
  625. return true;
  626. }
  627. }
  628. // needs further analysis
  629. ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(aspectClassName), true);
  630. // exclude are "AND"ed
  631. for (Iterator iterator = m_aspectExcludeTypePattern.iterator(); iterator.hasNext();) {
  632. TypePattern typePattern = (TypePattern) iterator.next();
  633. if (typePattern.matchesStatically(classInfo)) {
  634. // exclude match - skip
  635. return false;
  636. }
  637. }
  638. // include are "OR"ed
  639. boolean accept = true;// defaults to true if no include
  640. for (Iterator iterator = m_aspectIncludeTypePattern.iterator(); iterator.hasNext();) {
  641. TypePattern typePattern = (TypePattern) iterator.next();
  642. accept = typePattern.matchesStatically(classInfo);
  643. if (accept) {
  644. break;
  645. }
  646. // goes on if this include did not match ("OR"ed)
  647. }
  648. return accept;
  649. }
  650. @Override
  651. protected boolean shouldDump(String className, boolean before) {
  652. // Don't dump before weaving unless asked to
  653. if (before && !m_dumpBefore) {
  654. return false;
  655. }
  656. // avoid ResolvedType if not needed
  657. if (m_dumpTypePattern.isEmpty()) {
  658. return false;
  659. }
  660. // TODO AV - optimize for className.startWith only
  661. ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(className), true);
  662. // dump
  663. for (Iterator iterator = m_dumpTypePattern.iterator(); iterator.hasNext();) {
  664. TypePattern typePattern = (TypePattern) iterator.next();
  665. if (typePattern.matchesStatically(classInfo)) {
  666. // dump match
  667. return true;
  668. }
  669. }
  670. return false;
  671. }
  672. @Override
  673. protected String getDumpDir() {
  674. if (dumpDirPerClassloader) {
  675. StringBuffer dir = new StringBuffer();
  676. dir.append("_ajdump").append(File.separator).append(weavingContext.getId());
  677. return dir.toString();
  678. } else {
  679. return super.getDumpDir();
  680. }
  681. }
  682. /*
  683. * shared classes methods
  684. */
  685. /**
  686. * @return Returns the key.
  687. */
  688. public String getNamespace() {
  689. // System.out.println("ClassLoaderWeavingAdaptor.getNamespace() classloader=" + weavingContext.getClassLoaderName() +
  690. // ", namespace=" + namespace);
  691. if (namespace == null) {
  692. return "";
  693. } else {
  694. return new String(namespace);
  695. }
  696. }
  697. /**
  698. * Check to see if any classes are stored in the generated classes cache. Then flush the cache if it is not empty
  699. *
  700. * @param className TODO
  701. * @return true if a class has been generated and is stored in the cache
  702. */
  703. public boolean generatedClassesExistFor(String className) {
  704. // System.err.println("? ClassLoaderWeavingAdaptor.generatedClassesExist() classname=" + className + ", size=" +
  705. // generatedClasses);
  706. if (className == null) {
  707. return !generatedClasses.isEmpty();
  708. } else {
  709. return generatedClasses.containsKey(className);
  710. }
  711. }
  712. /**
  713. * Flush the generated classes cache
  714. */
  715. public void flushGeneratedClasses() {
  716. // System.err.println("? ClassLoaderWeavingAdaptor.flushGeneratedClasses() generatedClasses=" + generatedClasses);
  717. generatedClasses = new HashMap();
  718. }
  719. private void defineClass(ClassLoader loader, String name, byte[] bytes) {
  720. if (trace.isTraceEnabled()) {
  721. trace.enter("defineClass", this, new Object[] { loader, name, bytes });
  722. }
  723. Object clazz = null;
  724. debug("generating class '" + name + "'");
  725. try {
  726. // TODO av protection domain, and optimize
  727. Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, bytes.getClass(),
  728. int.class, int.class });
  729. defineClass.setAccessible(true);
  730. clazz = defineClass.invoke(loader, new Object[] { name, bytes, new Integer(0), new Integer(bytes.length) });
  731. } catch (InvocationTargetException e) {
  732. if (e.getTargetException() instanceof LinkageError) {
  733. warn("define generated class failed", e.getTargetException());
  734. // is already defined (happens for X$ajcMightHaveAspect interfaces since aspects are reweaved)
  735. // TODO maw I don't think this is OK and
  736. } else {
  737. warn("define generated class failed", e.getTargetException());
  738. }
  739. } catch (Exception e) {
  740. warn("define generated class failed", e);
  741. }
  742. if (trace.isTraceEnabled()) {
  743. trace.exit("defineClass", clazz);
  744. }
  745. }
  746. }