Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ClassLoaderWeavingAdaptor.java 34KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. /*******************************************************************************
  2. * Copyright (c) 2005, 2017 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. package org.aspectj.weaver.loadtime;
  10. import java.io.File;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.lang.reflect.Field;
  14. import java.lang.reflect.InvocationTargetException;
  15. import java.lang.reflect.Method;
  16. import java.net.MalformedURLException;
  17. import java.net.URL;
  18. import java.security.ProtectionDomain;
  19. import java.util.ArrayList;
  20. import java.util.Enumeration;
  21. import java.util.HashMap;
  22. import java.util.HashSet;
  23. import java.util.Iterator;
  24. import java.util.LinkedList;
  25. import java.util.List;
  26. import java.util.Properties;
  27. import java.util.Set;
  28. import java.util.StringTokenizer;
  29. import org.aspectj.bridge.AbortException;
  30. import org.aspectj.bridge.Constants;
  31. import org.aspectj.bridge.MessageUtil;
  32. import org.aspectj.util.LangUtil;
  33. import org.aspectj.weaver.IUnwovenClassFile;
  34. import org.aspectj.weaver.Lint;
  35. import org.aspectj.weaver.Lint.Kind;
  36. import org.aspectj.weaver.ResolvedType;
  37. import org.aspectj.weaver.UnresolvedType;
  38. import org.aspectj.weaver.World;
  39. import org.aspectj.weaver.bcel.BcelWeakClassLoaderReference;
  40. import org.aspectj.weaver.bcel.BcelWeaver;
  41. import org.aspectj.weaver.bcel.BcelWorld;
  42. import org.aspectj.weaver.bcel.Utility;
  43. import org.aspectj.weaver.loadtime.definition.Definition;
  44. import org.aspectj.weaver.loadtime.definition.DocumentParser;
  45. import org.aspectj.weaver.ltw.LTWWorld;
  46. import org.aspectj.weaver.patterns.PatternParser;
  47. import org.aspectj.weaver.patterns.TypePattern;
  48. import org.aspectj.weaver.tools.GeneratedClassHandler;
  49. import org.aspectj.weaver.tools.Trace;
  50. import org.aspectj.weaver.tools.TraceFactory;
  51. import org.aspectj.weaver.tools.WeavingAdaptor;
  52. import org.aspectj.weaver.tools.cache.WeavedClassCache;
  53. import sun.misc.Unsafe;
  54. /**
  55. * @author Alexandre Vasseur
  56. * @author Andy Clement
  57. * @author Abraham Nevado
  58. * @author David Knibb
  59. * @author John Kew
  60. */
  61. public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
  62. private final static String AOP_XML = Constants.AOP_USER_XML + ";" + Constants.AOP_AJC_XML + ";" + Constants.AOP_OSGI_XML;
  63. private boolean initialized;
  64. private List<TypePattern> dumpTypePattern = new ArrayList<TypePattern>();
  65. private boolean dumpBefore = false;
  66. private boolean dumpDirPerClassloader = false;
  67. private boolean hasExcludes = false;
  68. private List<TypePattern> excludeTypePattern = new ArrayList<TypePattern>(); // anything
  69. private List<String> excludeStartsWith = new ArrayList<String>(); // com.foo..*
  70. private List<String> excludeStarDotDotStar = new ArrayList<String>(); // *..*CGLIB*
  71. private List<String> excludeExactName = new ArrayList<String>(); // com.foo.Bar
  72. private List<String> excludeEndsWith = new ArrayList<String>(); // com.foo.Bar
  73. private List<String[]> excludeSpecial = new ArrayList<String[]>();
  74. private boolean hasIncludes = false;
  75. private List<TypePattern> includeTypePattern = new ArrayList<TypePattern>();
  76. private List<String> includeStartsWith = new ArrayList<String>();
  77. private List<String> includeExactName = new ArrayList<String>();
  78. private boolean includeStar = false;
  79. private List<TypePattern> aspectExcludeTypePattern = new ArrayList<TypePattern>();
  80. private List<String> aspectExcludeStartsWith = new ArrayList<String>();
  81. private List<TypePattern> aspectIncludeTypePattern = new ArrayList<TypePattern>();
  82. private List<String> aspectIncludeStartsWith = new ArrayList<String>();
  83. private StringBuffer namespace;
  84. private IWeavingContext weavingContext;
  85. private List<ConcreteAspectCodeGen> concreteAspects = new ArrayList<ConcreteAspectCodeGen>();
  86. private static Trace trace = TraceFactory.getTraceFactory().getTrace(ClassLoaderWeavingAdaptor.class);
  87. public ClassLoaderWeavingAdaptor() {
  88. super();
  89. if (trace.isTraceEnabled()) {
  90. trace.enter("<init>", this);
  91. }
  92. if (trace.isTraceEnabled()) {
  93. trace.exit("<init>");
  94. }
  95. }
  96. /**
  97. * We don't need a reference to the class loader and using it during construction can cause problems with recursion. It also
  98. * makes sense to supply the weaving context during initialization to.
  99. *
  100. * @deprecated
  101. */
  102. public ClassLoaderWeavingAdaptor(final ClassLoader deprecatedLoader, final IWeavingContext deprecatedContext) {
  103. super();
  104. if (trace.isTraceEnabled()) {
  105. trace.enter("<init>", this, new Object[] { deprecatedLoader, deprecatedContext });
  106. }
  107. if (trace.isTraceEnabled()) {
  108. trace.exit("<init>");
  109. }
  110. }
  111. class SimpleGeneratedClassHandler implements GeneratedClassHandler {
  112. private BcelWeakClassLoaderReference loaderRef;
  113. SimpleGeneratedClassHandler(ClassLoader loader) {
  114. loaderRef = new BcelWeakClassLoaderReference(loader);
  115. }
  116. /**
  117. * Callback when we need to define a Closure in the JVM
  118. *
  119. */
  120. public void acceptClass (String name, byte[] originalBytes, byte[] wovenBytes) {
  121. try {
  122. if (shouldDump(name.replace('/', '.'), false)) {
  123. dump(name, wovenBytes, false);
  124. }
  125. } catch (Throwable throwable) {
  126. throwable.printStackTrace();
  127. }
  128. if (activeProtectionDomain != null) {
  129. defineClass(loaderRef.getClassLoader(), name, wovenBytes, activeProtectionDomain);
  130. } else {
  131. defineClass(loaderRef.getClassLoader(), name, wovenBytes); // could be done lazily using the hook
  132. }
  133. }
  134. }
  135. public void initialize(final ClassLoader classLoader, IWeavingContext context) {
  136. if (initialized) {
  137. return;
  138. }
  139. boolean success = true;
  140. this.weavingContext = context;
  141. if (weavingContext == null) {
  142. weavingContext = new DefaultWeavingContext(classLoader);
  143. }
  144. createMessageHandler();
  145. this.generatedClassHandler = new SimpleGeneratedClassHandler(classLoader);
  146. List<Definition> definitions = weavingContext.getDefinitions(classLoader, this);
  147. if (definitions.isEmpty()) {
  148. disable(); // TODO maw Needed to ensure messages are flushed
  149. if (trace.isTraceEnabled()) {
  150. trace.exit("initialize", definitions);
  151. }
  152. return;
  153. }
  154. // TODO when the world works in terms of the context, we can remove the loader
  155. bcelWorld = new LTWWorld(classLoader, weavingContext, getMessageHandler(), null);
  156. weaver = new BcelWeaver(bcelWorld);
  157. // register the definitions
  158. success = registerDefinitions(weaver, classLoader, definitions);
  159. if (success) {
  160. // after adding aspects
  161. weaver.prepareForWeave();
  162. enable(); // TODO maw Needed to ensure messages are flushed
  163. success = weaveAndDefineConceteAspects();
  164. }
  165. if (success) {
  166. enable();
  167. } else {
  168. disable();
  169. bcelWorld = null;
  170. weaver = null;
  171. }
  172. if (WeavedClassCache.isEnabled()) {
  173. initializeCache(classLoader, getAspectClassNames(definitions), generatedClassHandler, getMessageHandler());
  174. }
  175. initialized = true;
  176. if (trace.isTraceEnabled()) {
  177. trace.exit("initialize", isEnabled());
  178. }
  179. }
  180. /**
  181. * Get the list of all aspects from the defintion list
  182. * @param definitions
  183. * @return
  184. */
  185. List<String> getAspectClassNames(List<Definition> definitions) {
  186. List<String> aspects = new LinkedList<String>();
  187. for (Iterator<Definition> it = definitions.iterator(); it.hasNext(); ) {
  188. Definition def = it.next();
  189. List<String> defAspects = def.getAspectClassNames();
  190. if (defAspects != null) {
  191. aspects.addAll(defAspects);
  192. }
  193. }
  194. return aspects;
  195. }
  196. /**
  197. * Load and cache the aop.xml/properties according to the classloader visibility rules
  198. *
  199. * @param loader
  200. */
  201. List<Definition> parseDefinitions(final ClassLoader loader) {
  202. if (trace.isTraceEnabled()) {
  203. trace.enter("parseDefinitions", this);
  204. }
  205. List<Definition> definitions = new ArrayList<Definition>();
  206. try {
  207. info("register classloader " + getClassLoaderName(loader));
  208. // TODO av underoptimized: we will parse each XML once per CL that see it
  209. // TODO av dev mode needed ? TBD -Daj5.def=...
  210. if (loader.equals(ClassLoader.getSystemClassLoader())) {
  211. String file = System.getProperty("aj5.def", null);
  212. if (file != null) {
  213. info("using (-Daj5.def) " + file);
  214. definitions.add(DocumentParser.parse((new File(file)).toURI().toURL()));
  215. }
  216. }
  217. String resourcePath = System.getProperty("org.aspectj.weaver.loadtime.configuration", AOP_XML);
  218. if (trace.isTraceEnabled()) {
  219. trace.event("parseDefinitions", this, resourcePath);
  220. }
  221. StringTokenizer st = new StringTokenizer(resourcePath, ";");
  222. while (st.hasMoreTokens()) {
  223. String nextDefinition = st.nextToken();
  224. if (nextDefinition.startsWith("file:")) {
  225. try {
  226. String fpath = new URL(nextDefinition).getFile();
  227. File configFile = new File(fpath);
  228. if (!configFile.exists()) {
  229. warn("configuration does not exist: " + nextDefinition);
  230. } else {
  231. definitions.add(DocumentParser.parse(configFile.toURI().toURL()));
  232. }
  233. } catch (MalformedURLException mue) {
  234. error("malformed definition url: " + nextDefinition);
  235. }
  236. } else {
  237. Enumeration<URL> xmls = weavingContext.getResources(nextDefinition);
  238. // System.out.println("? registerDefinitions: found-aop.xml=" + xmls.hasMoreElements() + ", loader=" + loader);
  239. Set<URL> seenBefore = new HashSet<URL>();
  240. while (xmls.hasMoreElements()) {
  241. URL xml = xmls.nextElement();
  242. if (trace.isTraceEnabled()) {
  243. trace.event("parseDefinitions", this, xml);
  244. }
  245. if (!seenBefore.contains(xml)) {
  246. info("using configuration " + weavingContext.getFile(xml));
  247. definitions.add(DocumentParser.parse(xml));
  248. seenBefore.add(xml);
  249. } else {
  250. debug("ignoring duplicate definition: " + xml);
  251. }
  252. }
  253. }
  254. }
  255. if (definitions.isEmpty()) {
  256. info("no configuration found. Disabling weaver for class loader " + getClassLoaderName(loader));
  257. }
  258. } catch (Exception e) {
  259. definitions.clear();
  260. warn("parse definitions failed", e);
  261. }
  262. if (trace.isTraceEnabled()) {
  263. trace.exit("parseDefinitions", definitions);
  264. }
  265. return definitions;
  266. }
  267. private boolean registerDefinitions(final BcelWeaver weaver, final ClassLoader loader, List<Definition> definitions) {
  268. if (trace.isTraceEnabled()) {
  269. trace.enter("registerDefinitions", this, definitions);
  270. }
  271. boolean success = true;
  272. try {
  273. registerOptions(weaver, loader, definitions);
  274. registerAspectExclude(weaver, loader, definitions);
  275. registerAspectInclude(weaver, loader, definitions);
  276. success = registerAspects(weaver, loader, definitions);
  277. registerIncludeExclude(weaver, loader, definitions);
  278. registerDump(weaver, loader, definitions);
  279. } catch (Exception ex) {
  280. trace.error("register definition failed", ex);
  281. success = false;
  282. warn("register definition failed", (ex instanceof AbortException) ? null : ex);
  283. }
  284. if (trace.isTraceEnabled()) {
  285. trace.exit("registerDefinitions", success);
  286. }
  287. return success;
  288. }
  289. private String getClassLoaderName(ClassLoader loader) {
  290. return weavingContext.getClassLoaderName();
  291. }
  292. /**
  293. * Configure the weaver according to the option directives TODO av - don't know if it is that good to reuse, since we only allow
  294. * a small subset of options in LTW
  295. *
  296. * @param weaver
  297. * @param loader
  298. * @param definitions
  299. */
  300. private void registerOptions(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) {
  301. StringBuffer allOptions = new StringBuffer();
  302. for (Definition definition : definitions) {
  303. allOptions.append(definition.getWeaverOptions()).append(' ');
  304. }
  305. Options.WeaverOption weaverOption = Options.parse(allOptions.toString(), loader, getMessageHandler());
  306. // configure the weaver and world
  307. // AV - code duplicates AspectJBuilder.initWorldAndWeaver()
  308. World world = weaver.getWorld();
  309. setMessageHandler(weaverOption.messageHandler);
  310. world.setXlazyTjp(weaverOption.lazyTjp);
  311. world.setXHasMemberSupportEnabled(weaverOption.hasMember);
  312. world.setTiming(weaverOption.timers, true);
  313. world.setOptionalJoinpoints(weaverOption.optionalJoinpoints);
  314. world.setPinpointMode(weaverOption.pinpoint);
  315. weaver.setReweavableMode(weaverOption.notReWeavable);
  316. if (weaverOption.loadersToSkip != null && weaverOption.loadersToSkip.length() > 0) {
  317. Aj.loadersToSkip = LangUtil.anySplit(weaverOption.loadersToSkip, ",");
  318. }
  319. if (Aj.loadersToSkip != null) {
  320. MessageUtil.info(world.getMessageHandler(),"no longer creating weavers for these classloaders: "+Aj.loadersToSkip);
  321. }
  322. world.performExtraConfiguration(weaverOption.xSet);
  323. world.setXnoInline(weaverOption.noInline);
  324. // AMC - autodetect as per line below, needed for AtAjLTWTests.testLTWUnweavable
  325. world.setBehaveInJava5Way(LangUtil.is15VMOrGreater());
  326. world.setAddSerialVerUID(weaverOption.addSerialVersionUID);
  327. /* First load defaults */
  328. bcelWorld.getLint().loadDefaultProperties();
  329. /* Second overlay LTW defaults */
  330. bcelWorld.getLint().adviceDidNotMatch.setKind(null);
  331. /* Third load user file using -Xlintfile so that -Xlint wins */
  332. if (weaverOption.lintFile != null) {
  333. InputStream resource = null;
  334. try {
  335. resource = loader.getResourceAsStream(weaverOption.lintFile);
  336. Exception failure = null;
  337. if (resource != null) {
  338. try {
  339. Properties properties = new Properties();
  340. properties.load(resource);
  341. world.getLint().setFromProperties(properties);
  342. } catch (IOException e) {
  343. failure = e;
  344. }
  345. }
  346. if (failure != null || resource == null) {
  347. warn("Cannot access resource for -Xlintfile:" + weaverOption.lintFile, failure);
  348. // world.getMessageHandler().handleMessage(new Message(
  349. // "Cannot access resource for -Xlintfile:"+weaverOption.lintFile,
  350. // IMessage.WARNING,
  351. // failure,
  352. // null));
  353. }
  354. } finally {
  355. try {
  356. resource.close();
  357. } catch (Throwable t) {
  358. }
  359. }
  360. }
  361. /* Fourth override with -Xlint */
  362. if (weaverOption.lint != null) {
  363. if (weaverOption.lint.equals("default")) {// FIXME should be AjBuildConfig.AJLINT_DEFAULT but yetanother deps..
  364. bcelWorld.getLint().loadDefaultProperties();
  365. } else {
  366. bcelWorld.getLint().setAll(weaverOption.lint);
  367. if (weaverOption.lint.equals("ignore")) {
  368. bcelWorld.setAllLintIgnored();
  369. }
  370. }
  371. }
  372. // TODO proceedOnError option
  373. }
  374. private void registerAspectExclude(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) {
  375. String fastMatchInfo = null;
  376. for (Definition definition : definitions) {
  377. for (String exclude : definition.getAspectExcludePatterns()) {
  378. TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
  379. aspectExcludeTypePattern.add(excludePattern);
  380. fastMatchInfo = looksLikeStartsWith(exclude);
  381. if (fastMatchInfo != null) {
  382. aspectExcludeStartsWith.add(fastMatchInfo);
  383. }
  384. }
  385. }
  386. }
  387. private void registerAspectInclude(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) {
  388. String fastMatchInfo = null;
  389. for (Definition definition : definitions) {
  390. for (String include : definition.getAspectIncludePatterns()) {
  391. TypePattern includePattern = new PatternParser(include).parseTypePattern();
  392. aspectIncludeTypePattern.add(includePattern);
  393. fastMatchInfo = looksLikeStartsWith(include);
  394. if (fastMatchInfo != null) {
  395. aspectIncludeStartsWith.add(fastMatchInfo);
  396. }
  397. }
  398. }
  399. }
  400. protected void lint(String name, String[] infos) {
  401. Lint lint = bcelWorld.getLint();
  402. Kind kind = lint.getLintKind(name);
  403. kind.signal(infos, null, null);
  404. }
  405. @Override
  406. public String getContextId() {
  407. return weavingContext.getId();
  408. }
  409. /**
  410. * Register the aspect, following include / exclude rules
  411. *
  412. * @param weaver
  413. * @param loader
  414. * @param definitions
  415. */
  416. private boolean registerAspects(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) {
  417. if (trace.isTraceEnabled()) {
  418. trace.enter("registerAspects", this, new Object[] { weaver, loader, definitions });
  419. }
  420. boolean success = true;
  421. // TODO: the exclude aspect allow to exclude aspect defined upper in the CL hierarchy - is it what we want ??
  422. // if not, review the getResource so that we track which resource is defined by which CL
  423. // iterate aspectClassNames
  424. // exclude if in any of the exclude list
  425. for (Definition definition : definitions) {
  426. for (String aspectClassName : definition.getAspectClassNames()) {
  427. if (acceptAspect(aspectClassName)) {
  428. info("register aspect " + aspectClassName);
  429. // System.err.println("? ClassLoaderWeavingAdaptor.registerAspects() aspectName=" + aspectClassName +
  430. // ", loader=" + loader + ", bundle=" + weavingContext.getClassLoaderName());
  431. String requiredType = definition.getAspectRequires(aspectClassName);
  432. if (requiredType != null) {
  433. // This aspect expresses that it requires a type to be around, otherwise it should 'switch off'
  434. ((BcelWorld) weaver.getWorld()).addAspectRequires(aspectClassName, requiredType);
  435. }
  436. String definedScope = definition.getScopeForAspect(aspectClassName);
  437. if (definedScope != null) {
  438. ((BcelWorld) weaver.getWorld()).addScopedAspect(aspectClassName, definedScope);
  439. }
  440. // ResolvedType aspect =
  441. weaver.addLibraryAspect(aspectClassName);
  442. // generate key for SC
  443. if (namespace == null) {
  444. namespace = new StringBuffer(aspectClassName);
  445. } else {
  446. namespace = namespace.append(";").append(aspectClassName);
  447. }
  448. } else {
  449. // warn("aspect excluded: " + aspectClassName);
  450. lint("aspectExcludedByConfiguration", new String[] { aspectClassName, getClassLoaderName(loader) });
  451. }
  452. }
  453. }
  454. // iterate concreteAspects
  455. // exclude if in any of the exclude list - note that the user defined name matters for that to happen
  456. for (Definition definition : definitions) {
  457. for (Definition.ConcreteAspect concreteAspect : definition.getConcreteAspects()) {
  458. if (acceptAspect(concreteAspect.name)) {
  459. info("define aspect " + concreteAspect.name);
  460. ConcreteAspectCodeGen gen = new ConcreteAspectCodeGen(concreteAspect, weaver.getWorld());
  461. if (!gen.validate()) {
  462. error("Concrete-aspect '" + concreteAspect.name + "' could not be registered");
  463. success = false;
  464. break;
  465. }
  466. ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes()),
  467. true);
  468. concreteAspects.add(gen);
  469. weaver.addLibraryAspect(concreteAspect.name);
  470. // generate key for SC
  471. if (namespace == null) {
  472. namespace = new StringBuffer(concreteAspect.name);
  473. } else {
  474. namespace = namespace.append(";" + concreteAspect.name);
  475. }
  476. }
  477. }
  478. }
  479. /* We couldn't register one or more aspects so disable the adaptor */
  480. if (!success) {
  481. warn("failure(s) registering aspects. Disabling weaver for class loader " + getClassLoaderName(loader));
  482. }
  483. /* We didn't register any aspects so disable the adaptor */
  484. else if (namespace == null) {
  485. success = false;
  486. info("no aspects registered. Disabling weaver for class loader " + getClassLoaderName(loader));
  487. }
  488. if (trace.isTraceEnabled()) {
  489. trace.exit("registerAspects", success);
  490. }
  491. return success;
  492. }
  493. private boolean weaveAndDefineConceteAspects() {
  494. if (trace.isTraceEnabled()) {
  495. trace.enter("weaveAndDefineConceteAspects", this, concreteAspects);
  496. }
  497. boolean success = true;
  498. for (ConcreteAspectCodeGen gen : concreteAspects) {
  499. String name = gen.getClassName();
  500. byte[] bytes = gen.getBytes();
  501. try {
  502. byte[] newBytes = weaveClass(name, bytes, true);
  503. this.generatedClassHandler.acceptClass(name, bytes, newBytes);
  504. } catch (IOException ex) {
  505. trace.error("weaveAndDefineConceteAspects", ex);
  506. error("exception weaving aspect '" + name + "'", ex);
  507. }
  508. }
  509. if (trace.isTraceEnabled()) {
  510. trace.exit("weaveAndDefineConceteAspects", success);
  511. }
  512. return success;
  513. }
  514. /**
  515. * Register the include / exclude filters. We duplicate simple patterns in startWith filters that will allow faster matching
  516. * without ResolvedType
  517. *
  518. * @param weaver
  519. * @param loader
  520. * @param definitions
  521. */
  522. private void registerIncludeExclude(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) {
  523. String fastMatchInfo = null;
  524. for (Definition definition : definitions) {
  525. for (Iterator<String> iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) {
  526. hasIncludes = true;
  527. String include = iterator1.next();
  528. fastMatchInfo = looksLikeStartsWith(include);
  529. if (fastMatchInfo != null) {
  530. includeStartsWith.add(fastMatchInfo);
  531. } else if (include.equals("*")) {
  532. includeStar = true;
  533. } else if ((fastMatchInfo = looksLikeExactName(include)) != null) {
  534. includeExactName.add(fastMatchInfo);
  535. } else {
  536. TypePattern includePattern = new PatternParser(include).parseTypePattern();
  537. includeTypePattern.add(includePattern);
  538. }
  539. }
  540. for (Iterator<String> iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) {
  541. hasExcludes = true;
  542. String exclude = iterator1.next();
  543. fastMatchInfo = looksLikeStartsWith(exclude);
  544. if (fastMatchInfo != null) {
  545. excludeStartsWith.add(fastMatchInfo);
  546. } else if ((fastMatchInfo = looksLikeStarDotDotStarExclude(exclude)) != null) {
  547. excludeStarDotDotStar.add(fastMatchInfo);
  548. } else if ((fastMatchInfo = looksLikeExactName(exclude)) != null) {
  549. excludeExactName.add(exclude);
  550. } else if ((fastMatchInfo = looksLikeEndsWith(exclude)) != null) {
  551. excludeEndsWith.add(fastMatchInfo);
  552. } else if (exclude
  553. .equals("org.codehaus.groovy..* && !org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController*")) {
  554. // TODO need a more sophisticated analysis here, to allow for similar situations
  555. excludeSpecial.add(new String[] { "org.codehaus.groovy.",
  556. "org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController" });
  557. // for the related test:
  558. // } else if (exclude.equals("testdata..* && !testdata.sub.Oran*")) {
  559. // excludeSpecial.add(new String[] { "testdata.", "testdata.sub.Oran" });
  560. } else {
  561. TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
  562. excludeTypePattern.add(excludePattern);
  563. }
  564. }
  565. }
  566. }
  567. /**
  568. * Checks if the pattern looks like "*..*XXXX*" and if so returns XXXX. This will enable fast name matching of CGLIB exclusion
  569. *
  570. */
  571. private String looksLikeStarDotDotStarExclude(String typePattern) {
  572. if (!typePattern.startsWith("*..*")) {
  573. return null;
  574. }
  575. if (!typePattern.endsWith("*")) {
  576. return null;
  577. }
  578. String subPattern = typePattern.substring(4, typePattern.length() - 1);
  579. if (hasStarDot(subPattern, 0)) {
  580. return null;
  581. }
  582. return subPattern.replace('$', '.');
  583. }
  584. /**
  585. * Checks if the pattern looks like "com.foo.Bar" - an exact name
  586. */
  587. private String looksLikeExactName(String typePattern) {
  588. if (hasSpaceAnnotationPlus(typePattern, 0) || typePattern.indexOf("*") != -1) {
  589. return null;
  590. }
  591. return typePattern.replace('$', '.');
  592. }
  593. /**
  594. * Checks if the pattern looks like "*Exception"
  595. */
  596. private String looksLikeEndsWith(String typePattern) {
  597. if (typePattern.charAt(0) != '*') {
  598. return null;
  599. }
  600. if (hasSpaceAnnotationPlus(typePattern, 1) || hasStarDot(typePattern, 1)) {
  601. return null;
  602. }
  603. return typePattern.substring(1).replace('$', '.');
  604. }
  605. /**
  606. * Determine if something in the string is going to affect our ability to optimize. Checks for: ' ' '@' '+'
  607. */
  608. private boolean hasSpaceAnnotationPlus(String string, int pos) {
  609. for (int i = pos, max = string.length(); i < max; i++) {
  610. char ch = string.charAt(i);
  611. if (ch == ' ' || ch == '@' || ch == '+') {
  612. return true;
  613. }
  614. }
  615. return false;
  616. }
  617. /**
  618. * Determine if something in the string is going to affect our ability to optimize. Checks for: '*' '.'
  619. */
  620. private boolean hasStarDot(String string, int pos) {
  621. for (int i = pos, max = string.length(); i < max; i++) {
  622. char ch = string.charAt(i);
  623. if (ch == '*' || ch == '.') {
  624. return true;
  625. }
  626. }
  627. return false;
  628. }
  629. /**
  630. * Checks if the type pattern looks like "com.foo..*"
  631. */
  632. private String looksLikeStartsWith(String typePattern) {
  633. if (hasSpaceAnnotationPlus(typePattern, 0) || typePattern.charAt(typePattern.length() - 1) != '*') {
  634. return null;
  635. }
  636. // now must looks like with "charsss..*" or "cha.rss..*" etc
  637. // note that "*" and "*..*" won't be fast matched
  638. // and that "charsss.*" will not neither
  639. int length = typePattern.length();
  640. if (typePattern.endsWith("..*") && length > 3) {
  641. if (typePattern.indexOf("..") == length - 3 // no ".." before last sequence
  642. && typePattern.indexOf('*') == length - 1) { // no earlier '*'
  643. return typePattern.substring(0, length - 2).replace('$', '.'); // "charsss." or "char.rss." etc
  644. }
  645. }
  646. return null;
  647. }
  648. /**
  649. * Register the dump filter
  650. *
  651. * @param weaver
  652. * @param loader
  653. * @param definitions
  654. */
  655. private void registerDump(final BcelWeaver weaver, final ClassLoader loader, final List<Definition> definitions) {
  656. for (Definition definition : definitions) {
  657. for (Iterator<String> iterator1 = definition.getDumpPatterns().iterator(); iterator1.hasNext();) {
  658. String dump = iterator1.next();
  659. TypePattern pattern = new PatternParser(dump).parseTypePattern();
  660. dumpTypePattern.add(pattern);
  661. }
  662. if (definition.shouldDumpBefore()) {
  663. dumpBefore = true;
  664. }
  665. if (definition.createDumpDirPerClassloader()) {
  666. dumpDirPerClassloader = true;
  667. }
  668. }
  669. }
  670. /**
  671. * Determine whether a type should be accepted for weaving, by checking it against any includes/excludes.
  672. *
  673. * @param className the name of the type to possibly accept
  674. * @param bytes the bytecode for the type (in case we need to look inside, eg. annotations)
  675. * @return true if it should be accepted for weaving
  676. */
  677. @Override
  678. protected boolean accept(String className, byte[] bytes) {
  679. if (!hasExcludes && !hasIncludes) {
  680. return true;
  681. }
  682. // still try to avoid ResolvedType if we have simple patterns
  683. String fastClassName = className.replace('/', '.');
  684. for (String excludeStartsWithString : excludeStartsWith) {
  685. if (fastClassName.startsWith(excludeStartsWithString)) {
  686. return false;
  687. }
  688. }
  689. // Fast exclusion of patterns like: "*..*CGLIB*"
  690. if (!excludeStarDotDotStar.isEmpty()) {
  691. for (String namePiece : excludeStarDotDotStar) {
  692. int index = fastClassName.lastIndexOf('.');
  693. if (fastClassName.indexOf(namePiece, index + 1) != -1) {
  694. return false;
  695. }
  696. }
  697. }
  698. fastClassName = fastClassName.replace('$', '.');
  699. if (!excludeEndsWith.isEmpty()) {
  700. for (String lastPiece : excludeEndsWith) {
  701. if (fastClassName.endsWith(lastPiece)) {
  702. return false;
  703. }
  704. }
  705. }
  706. // Fast exclusion of exact names
  707. if (!excludeExactName.isEmpty()) {
  708. for (String name : excludeExactName) {
  709. if (fastClassName.equals(name)) {
  710. return false;
  711. }
  712. }
  713. }
  714. if (!excludeSpecial.isEmpty()) {
  715. for (String[] entry : excludeSpecial) {
  716. String excludeThese = entry[0];
  717. String exceptThese = entry[1];
  718. if (fastClassName.startsWith(excludeThese) && !fastClassName.startsWith(exceptThese)) {
  719. return false;
  720. }
  721. }
  722. }
  723. /*
  724. * Bug 120363 If we have an exclude pattern that cannot be matched using "starts with" then we cannot fast accept
  725. */
  726. boolean didSomeIncludeMatching = false;
  727. if (excludeTypePattern.isEmpty()) {
  728. if (includeStar) {
  729. return true;
  730. }
  731. if (!includeExactName.isEmpty()) {
  732. didSomeIncludeMatching = true;
  733. for (String exactname : includeExactName) {
  734. if (fastClassName.equals(exactname)) {
  735. return true;
  736. }
  737. }
  738. }
  739. boolean fastAccept = false;// defaults to false if no fast include
  740. for (int i = 0; i < includeStartsWith.size(); i++) {
  741. didSomeIncludeMatching = true;
  742. fastAccept = fastClassName.startsWith(includeStartsWith.get(i));
  743. if (fastAccept) {
  744. return true;
  745. }
  746. }
  747. // We may have processed all patterns now... check that and return
  748. if (includeTypePattern.isEmpty()) {
  749. return !didSomeIncludeMatching;
  750. }
  751. }
  752. boolean accept;
  753. try {
  754. ensureDelegateInitialized(className, bytes);
  755. ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();
  756. // exclude are "AND"ed
  757. for (TypePattern typePattern : excludeTypePattern) {
  758. if (typePattern.matchesStatically(classInfo)) {
  759. // exclude match - skip
  760. return false;
  761. }
  762. }
  763. // include are "OR"ed
  764. if (includeStar) {
  765. return true;
  766. }
  767. if (!includeExactName.isEmpty()) {
  768. didSomeIncludeMatching = true;
  769. for (String exactname : includeExactName) {
  770. if (fastClassName.equals(exactname)) {
  771. return true;
  772. }
  773. }
  774. }
  775. for (int i = 0; i < includeStartsWith.size(); i++) {
  776. didSomeIncludeMatching = true;
  777. boolean fastaccept = fastClassName.startsWith(includeStartsWith.get(i));
  778. if (fastaccept) {
  779. return true;
  780. }
  781. }
  782. accept = !didSomeIncludeMatching; // only true if no includes at all
  783. for (TypePattern typePattern : includeTypePattern) {
  784. accept = typePattern.matchesStatically(classInfo);
  785. if (accept) {
  786. break;
  787. }
  788. // goes on if this include did not match ("OR"ed)
  789. }
  790. } finally {
  791. this.bcelWorld.demote();
  792. }
  793. return accept;
  794. }
  795. // FIXME we don't use include/exclude of others aop.xml
  796. // this can be nice but very dangerous as well to change that
  797. private boolean acceptAspect(String aspectClassName) {
  798. // avoid ResolvedType if not needed
  799. if (aspectExcludeTypePattern.isEmpty() && aspectIncludeTypePattern.isEmpty()) {
  800. return true;
  801. }
  802. // still try to avoid ResolvedType if we have simple patterns
  803. // EXCLUDE: if one match then reject
  804. String fastClassName = aspectClassName.replace('/', '.').replace('.', '$');
  805. for (int i = 0; i < aspectExcludeStartsWith.size(); i++) {
  806. if (fastClassName.startsWith(aspectExcludeStartsWith.get(i))) {
  807. return false;
  808. }
  809. }
  810. // INCLUDE: if one match then accept
  811. for (int i = 0; i < aspectIncludeStartsWith.size(); i++) {
  812. if (fastClassName.startsWith(aspectIncludeStartsWith.get(i))) {
  813. return true;
  814. }
  815. }
  816. // needs further analysis
  817. ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(aspectClassName), true);
  818. // exclude are "AND"ed
  819. for (TypePattern typePattern: aspectExcludeTypePattern) {
  820. if (typePattern.matchesStatically(classInfo)) {
  821. // exclude match - skip
  822. return false;
  823. }
  824. }
  825. // include are "OR"ed
  826. boolean accept = true;// defaults to true if no include
  827. for (TypePattern typePattern: aspectIncludeTypePattern) {
  828. accept = typePattern.matchesStatically(classInfo);
  829. if (accept) {
  830. break;
  831. }
  832. // goes on if this include did not match ("OR"ed)
  833. }
  834. return accept;
  835. }
  836. @Override
  837. protected boolean shouldDump(String className, boolean before) {
  838. // Don't dump before weaving unless asked to
  839. if (before && !dumpBefore) {
  840. return false;
  841. }
  842. // avoid ResolvedType if not needed
  843. if (dumpTypePattern.isEmpty()) {
  844. return false;
  845. }
  846. // TODO AV - optimize for className.startWith only
  847. ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(className), true);
  848. // dump
  849. for (Iterator<TypePattern> iterator = dumpTypePattern.iterator(); iterator.hasNext();) {
  850. TypePattern typePattern = iterator.next();
  851. if (typePattern.matchesStatically(classInfo)) {
  852. // dump match
  853. return true;
  854. }
  855. }
  856. return false;
  857. }
  858. @Override
  859. protected String getDumpDir() {
  860. if (dumpDirPerClassloader) {
  861. StringBuffer dir = new StringBuffer();
  862. dir.append("_ajdump").append(File.separator).append(weavingContext.getId());
  863. return dir.toString();
  864. } else {
  865. return super.getDumpDir();
  866. }
  867. }
  868. /*
  869. * shared classes methods
  870. */
  871. /**
  872. * @return Returns the key.
  873. */
  874. public String getNamespace() {
  875. // System.out.println("ClassLoaderWeavingAdaptor.getNamespace() classloader=" + weavingContext.getClassLoaderName() +
  876. // ", namespace=" + namespace);
  877. if (namespace == null) {
  878. return "";
  879. } else {
  880. return new String(namespace);
  881. }
  882. }
  883. /**
  884. * Check to see if any classes are stored in the generated classes cache. Then flush the cache if it is not empty
  885. *
  886. * @param className TODO
  887. * @return true if a class has been generated and is stored in the cache
  888. */
  889. public boolean generatedClassesExistFor(String className) {
  890. // System.err.println("? ClassLoaderWeavingAdaptor.generatedClassesExist() classname=" + className + ", size=" +
  891. // generatedClasses);
  892. if (className == null) {
  893. return !generatedClasses.isEmpty();
  894. } else {
  895. return generatedClasses.containsKey(className);
  896. }
  897. }
  898. /**
  899. * Flush the generated classes cache
  900. */
  901. public void flushGeneratedClasses() {
  902. // System.err.println("? ClassLoaderWeavingAdaptor.flushGeneratedClasses() generatedClasses=" + generatedClasses);
  903. generatedClasses = new HashMap<String, IUnwovenClassFile>();
  904. }
  905. private Unsafe unsafe;
  906. private Unsafe getUnsafe() throws NoSuchFieldException, IllegalAccessException {
  907. if (unsafe == null) {
  908. Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
  909. theUnsafeField.setAccessible(true);
  910. return (Unsafe) theUnsafeField.get(null);
  911. }
  912. return unsafe;
  913. }
  914. private void defineClass(ClassLoader loader, String name, byte[] bytes) {
  915. if (trace.isTraceEnabled()) {
  916. trace.enter("defineClass", this, new Object[] { loader, name, bytes });
  917. }
  918. Object clazz = null;
  919. debug("generating class '" + name + "'");
  920. try {
  921. clazz = getUnsafe().defineClass(name, bytes, 0, bytes.length, loader, null);
  922. } catch (LinkageError le) {
  923. // likely thrown due to defining something that already exists?
  924. // Old comments from before moving to Unsafe.defineClass():
  925. // is already defined (happens for X$ajcMightHaveAspect interfaces since aspects are reweaved)
  926. // TODO maw I don't think this is OK and
  927. } catch (Exception e) {
  928. e.printStackTrace(System.err);
  929. warn("define generated class failed", e);
  930. }
  931. if (trace.isTraceEnabled()) {
  932. trace.exit("defineClass", clazz);
  933. }
  934. }
  935. private void defineClass(ClassLoader loader, String name, byte[] bytes, ProtectionDomain protectionDomain) {
  936. if (trace.isTraceEnabled()) {
  937. trace.enter("defineClass", this, new Object[] { loader, name, bytes, protectionDomain });
  938. }
  939. Object clazz = null;
  940. debug("generating class '" + name + "'");
  941. try {
  942. getUnsafe().defineClass(name, bytes, 0, bytes.length, loader, protectionDomain);
  943. } catch (LinkageError le) {
  944. // likely thrown due to defining something that already exists?
  945. // Old comments from before moving to Unsafe.defineClass():
  946. // is already defined (happens for X$ajcMightHaveAspect interfaces since aspects are reweaved)
  947. // TODO maw I don't think this is OK and
  948. } catch (Exception e) {
  949. warn("define generated class failed", e);
  950. }
  951. if (trace.isTraceEnabled()) {
  952. trace.exit("defineClass", clazz);
  953. }
  954. }
  955. }