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.

PointcutParser.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /*******************************************************************************
  2. * Copyright (c) 2004, 2017 Contributors
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * IBM Corporation - initial API and implementation
  10. *******************************************************************************/
  11. package org.aspectj.weaver.tools;
  12. import java.io.File;
  13. import java.io.IOException;
  14. import java.io.InputStream;
  15. import java.net.URL;
  16. import java.util.HashSet;
  17. import java.util.Properties;
  18. import java.util.Set;
  19. import org.aspectj.bridge.IMessageHandler;
  20. import org.aspectj.bridge.ISourceLocation;
  21. import org.aspectj.bridge.SourceLocation;
  22. import org.aspectj.weaver.BindingScope;
  23. import org.aspectj.weaver.IHasPosition;
  24. import org.aspectj.weaver.ISourceContext;
  25. import org.aspectj.weaver.IntMap;
  26. import org.aspectj.weaver.ResolvedType;
  27. import org.aspectj.weaver.Shadow;
  28. import org.aspectj.weaver.UnresolvedType;
  29. import org.aspectj.weaver.WeakClassLoaderReference;
  30. import org.aspectj.weaver.World;
  31. import org.aspectj.weaver.internal.tools.PointcutExpressionImpl;
  32. import org.aspectj.weaver.internal.tools.TypePatternMatcherImpl;
  33. import org.aspectj.weaver.patterns.AndPointcut;
  34. import org.aspectj.weaver.patterns.CflowPointcut;
  35. import org.aspectj.weaver.patterns.FormalBinding;
  36. import org.aspectj.weaver.patterns.IScope;
  37. import org.aspectj.weaver.patterns.KindedPointcut;
  38. import org.aspectj.weaver.patterns.NotPointcut;
  39. import org.aspectj.weaver.patterns.OrPointcut;
  40. import org.aspectj.weaver.patterns.ParserException;
  41. import org.aspectj.weaver.patterns.PatternParser;
  42. import org.aspectj.weaver.patterns.Pointcut;
  43. import org.aspectj.weaver.patterns.SimpleScope;
  44. import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;
  45. import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
  46. import org.aspectj.weaver.patterns.TypePattern;
  47. import org.aspectj.weaver.reflect.PointcutParameterImpl;
  48. import org.aspectj.weaver.reflect.ReflectionWorld;
  49. /**
  50. * A PointcutParser can be used to build PointcutExpressions for a user-defined subset of AspectJ's pointcut language
  51. *
  52. * @author Adrian Colyer
  53. * @author Andy Clement
  54. */
  55. public class PointcutParser {
  56. private ReflectionWorld world;
  57. private WeakClassLoaderReference classLoaderReference;
  58. private final Set<PointcutPrimitive> supportedPrimitives;
  59. private final Set<PointcutDesignatorHandler> pointcutDesignators = new HashSet<PointcutDesignatorHandler>();
  60. /**
  61. * @return a Set containing every PointcutPrimitive except if, cflow, and cflowbelow (useful for passing to PointcutParser
  62. * constructor).
  63. */
  64. public static Set<PointcutPrimitive> getAllSupportedPointcutPrimitives() {
  65. Set<PointcutPrimitive> primitives = new HashSet<PointcutPrimitive>();
  66. primitives.add(PointcutPrimitive.ADVICE_EXECUTION);
  67. primitives.add(PointcutPrimitive.ARGS);
  68. primitives.add(PointcutPrimitive.CALL);
  69. primitives.add(PointcutPrimitive.EXECUTION);
  70. primitives.add(PointcutPrimitive.GET);
  71. primitives.add(PointcutPrimitive.HANDLER);
  72. primitives.add(PointcutPrimitive.INITIALIZATION);
  73. primitives.add(PointcutPrimitive.PRE_INITIALIZATION);
  74. primitives.add(PointcutPrimitive.SET);
  75. primitives.add(PointcutPrimitive.STATIC_INITIALIZATION);
  76. primitives.add(PointcutPrimitive.TARGET);
  77. primitives.add(PointcutPrimitive.THIS);
  78. primitives.add(PointcutPrimitive.WITHIN);
  79. primitives.add(PointcutPrimitive.WITHIN_CODE);
  80. primitives.add(PointcutPrimitive.AT_ANNOTATION);
  81. primitives.add(PointcutPrimitive.AT_THIS);
  82. primitives.add(PointcutPrimitive.AT_TARGET);
  83. primitives.add(PointcutPrimitive.AT_ARGS);
  84. primitives.add(PointcutPrimitive.AT_WITHIN);
  85. primitives.add(PointcutPrimitive.AT_WITHINCODE);
  86. primitives.add(PointcutPrimitive.REFERENCE);
  87. return primitives;
  88. }
  89. /**
  90. * Returns a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions:
  91. * <ul>
  92. * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
  93. * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
  94. * <li>The pointcut expression must be anonymous with no formals allowed.
  95. * </ul>
  96. * <p>
  97. * When resolving types in pointcut expressions, the context classloader is used to find types.
  98. * </p>
  99. */
  100. public static PointcutParser getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution() {
  101. PointcutParser p = new PointcutParser();
  102. p.setClassLoader(Thread.currentThread().getContextClassLoader());
  103. return p;
  104. }
  105. /**
  106. * Returns a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported
  107. * pointcut primitives. The following restrictions apply:
  108. * <ul>
  109. * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
  110. * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
  111. * <li>The pointcut expression must be anonymous with no formals allowed.
  112. * </ul>
  113. * <p>
  114. * When resolving types in pointcut expressions, the context classloader is used to find types.
  115. * </p>
  116. *
  117. * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support
  118. * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below
  119. */
  120. public static PointcutParser getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
  121. Set<PointcutPrimitive> supportedPointcutKinds) {
  122. PointcutParser p = new PointcutParser(supportedPointcutKinds);
  123. p.setClassLoader(Thread.currentThread().getContextClassLoader());
  124. return p;
  125. }
  126. /**
  127. * Returns a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions:
  128. * <ul>
  129. * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
  130. * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
  131. * <li>The pointcut expression must be anonymous with no formals allowed.
  132. * </ul>
  133. * <p>
  134. * When resolving types in pointcut expressions, the given classloader is used to find types.
  135. * </p>
  136. */
  137. public static PointcutParser getPointcutParserSupportingAllPrimitivesAndUsingSpecifiedClassloaderForResolution(
  138. ClassLoader classLoader) {
  139. PointcutParser p = new PointcutParser();
  140. p.setClassLoader(classLoader);
  141. return p;
  142. }
  143. /**
  144. * Returns a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported
  145. * pointcut primitives. The following restrictions apply:
  146. * <ul>
  147. * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
  148. * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
  149. * <li>The pointcut expression must be anonymous with no formals allowed.
  150. * </ul>
  151. * <p>
  152. * When resolving types in pointcut expressions, the given classloader is used to find types.
  153. * </p>
  154. *
  155. * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support
  156. * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below
  157. */
  158. public static PointcutParser getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
  159. Set<PointcutPrimitive> supportedPointcutKinds, ClassLoader classLoader) {
  160. PointcutParser p = new PointcutParser(supportedPointcutKinds);
  161. p.setClassLoader(classLoader);
  162. return p;
  163. }
  164. /**
  165. * Create a pointcut parser that can parse the full AspectJ pointcut language with the following exceptions:
  166. * <ul>
  167. * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
  168. * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
  169. * <li>The pointcut expression must be anonymous with no formals allowed.
  170. * </ul>
  171. */
  172. protected PointcutParser() {
  173. supportedPrimitives = getAllSupportedPointcutPrimitives();
  174. setClassLoader(PointcutParser.class.getClassLoader());
  175. }
  176. /**
  177. * Create a pointcut parser that can parse pointcut expressions built from a user-defined subset of AspectJ's supported pointcut
  178. * primitives. The following restrictions apply:
  179. * <ul>
  180. * <li>The <code>if, cflow, and cflowbelow</code> pointcut designators are not supported
  181. * <li>Pointcut expressions must be self-contained :- they cannot contain references to other named pointcuts
  182. * <li>The pointcut expression must be anonymous with no formals allowed.
  183. * </ul>
  184. *
  185. * @param supportedPointcutKinds a set of PointcutPrimitives this parser should support
  186. * @throws UnsupportedOperationException if the set contains if, cflow, or cflow below
  187. */
  188. private PointcutParser(Set<PointcutPrimitive> supportedPointcutKinds) {
  189. supportedPrimitives = supportedPointcutKinds;
  190. for (PointcutPrimitive pointcutPrimitive : supportedPointcutKinds) {
  191. if ((pointcutPrimitive == PointcutPrimitive.IF) || (pointcutPrimitive == PointcutPrimitive.CFLOW)
  192. || (pointcutPrimitive == PointcutPrimitive.CFLOW_BELOW)) {
  193. throw new UnsupportedOperationException("Cannot handle if, cflow, and cflowbelow primitives");
  194. }
  195. }
  196. setClassLoader(PointcutParser.class.getClassLoader());
  197. }
  198. protected void setWorld(ReflectionWorld aWorld) {
  199. this.world = aWorld;
  200. }
  201. /**
  202. * Set the classloader that this parser should use for type resolution.
  203. *
  204. * @param aLoader
  205. */
  206. protected void setClassLoader(ClassLoader aLoader) {
  207. this.classLoaderReference = new WeakClassLoaderReference(aLoader);
  208. world = ReflectionWorld.getReflectionWorldFor(this.classLoaderReference);
  209. }
  210. /**
  211. * Set the classloader that this parser should use for type resolution.
  212. *
  213. * @param aLoader
  214. * @param shareWorlds if true then two PointcutParsers operating using the same classloader will share a ReflectionWorld
  215. */
  216. protected void setClassLoader(ClassLoader aLoader, boolean shareWorlds) {
  217. this.classLoaderReference = new WeakClassLoaderReference(aLoader);
  218. if (shareWorlds) {
  219. world = ReflectionWorld.getReflectionWorldFor(this.classLoaderReference);
  220. } else {
  221. world = new ReflectionWorld(classLoaderReference);
  222. }
  223. }
  224. /**
  225. * Set the lint properties for this parser from the given resource on the classpath.
  226. *
  227. * @param resourcePath path to a file containing aspectj lint properties
  228. */
  229. public void setLintProperties(String resourcePath) throws IOException {
  230. URL url = this.classLoaderReference.getClassLoader().getResource(resourcePath);
  231. InputStream is = url.openStream();
  232. Properties p = new Properties();
  233. p.load(is);
  234. setLintProperties(p);
  235. }
  236. /**
  237. * Set the lint properties for this parser from the given properties set.
  238. *
  239. * @param properties
  240. */
  241. public void setLintProperties(Properties properties) {
  242. getWorld().getLint().setFromProperties(properties);
  243. }
  244. /**
  245. * Register a new pointcut designator handler with this parser. This provides an extension mechansim for the integration of
  246. * domain-specific pointcut designators with the AspectJ pointcut language.
  247. *
  248. * @param designatorHandler
  249. */
  250. public void registerPointcutDesignatorHandler(PointcutDesignatorHandler designatorHandler) {
  251. this.pointcutDesignators.add(designatorHandler);
  252. if (world != null) {
  253. world.registerPointcutHandler(designatorHandler);
  254. }
  255. }
  256. /**
  257. * Create a pointcut parameter of the given name and type.
  258. *
  259. * @param name
  260. * @param type
  261. * @return
  262. */
  263. public PointcutParameter createPointcutParameter(String name, Class<?> type) {
  264. return new PointcutParameterImpl(name, type);
  265. }
  266. /**
  267. * Parse the given pointcut expression. A global scope is assumed for resolving any type references, and the pointcut must
  268. * contain no formals (variables to be bound).
  269. *
  270. * @throws UnsupportedPointcutPrimitiveException if the parser encounters a primitive pointcut expression of a kind not
  271. * supported by this PointcutParser.
  272. * @throws IllegalArgumentException if the expression is not a well-formed pointcut expression
  273. */
  274. public PointcutExpression parsePointcutExpression(String expression) throws UnsupportedPointcutPrimitiveException,
  275. IllegalArgumentException {
  276. return parsePointcutExpression(expression, null, new PointcutParameter[0]);
  277. }
  278. /**
  279. * Parse the given pointcut expression. The pointcut is resolved as if it had been declared inside the inScope class (this
  280. * allows the pointcut to contain unqualified references to other pointcuts declared in the same type for example). The pointcut
  281. * may contain zero or more formal parameters to be bound at matched join points.
  282. *
  283. * @throws UnsupportedPointcutPrimitiveException if the parser encounters a primitive pointcut expression of a kind not
  284. * supported by this PointcutParser.
  285. * @throws IllegalArgumentException if the expression is not a well-formed pointcut expression
  286. */
  287. public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)
  288. throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
  289. PointcutExpressionImpl pcExpr = null;
  290. try {
  291. Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
  292. pc = concretizePointcutExpression(pc, inScope, formalParameters);
  293. validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
  294. pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
  295. } catch (ParserException pEx) {
  296. throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
  297. } catch (ReflectionWorld.ReflectionWorldException rwEx) {
  298. throw new IllegalArgumentException(rwEx.getMessage());
  299. }
  300. return pcExpr;
  301. }
  302. protected Pointcut resolvePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters) {
  303. try {
  304. PatternParser parser = new PatternParser(expression);
  305. parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
  306. Pointcut pc = parser.parsePointcut();
  307. validateAgainstSupportedPrimitives(pc, expression);
  308. IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope), formalParameters);
  309. pc = pc.resolve(resolutionScope);
  310. return pc;
  311. } catch (ParserException pEx) {
  312. throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
  313. }
  314. }
  315. protected Pointcut concretizePointcutExpression(Pointcut pc, Class<?> inScope, PointcutParameter[] formalParameters) {
  316. ResolvedType declaringTypeForResolution = null;
  317. if (inScope != null) {
  318. declaringTypeForResolution = getWorld().resolve(inScope.getName());
  319. } else {
  320. declaringTypeForResolution = ResolvedType.OBJECT.resolve(getWorld());
  321. }
  322. IntMap arity = new IntMap(formalParameters.length);
  323. for (int i = 0; i < formalParameters.length; i++) {
  324. arity.put(i, i);
  325. }
  326. return pc.concretize(declaringTypeForResolution, declaringTypeForResolution, arity);
  327. }
  328. /**
  329. * Parse the given aspectj type pattern, and return a matcher that can be used to match types using it.
  330. *
  331. * @param typePattern an aspectj type pattern
  332. * @return a type pattern matcher that matches using the given pattern
  333. * @throws IllegalArgumentException if the type pattern cannot be successfully parsed.
  334. */
  335. public TypePatternMatcher parseTypePattern(String typePattern) throws IllegalArgumentException {
  336. try {
  337. TypePattern tp = new PatternParser(typePattern).parseTypePattern();
  338. tp.resolve(world);
  339. return new TypePatternMatcherImpl(tp, world);
  340. } catch (ParserException pEx) {
  341. throw new IllegalArgumentException(buildUserMessageFromParserException(typePattern, pEx));
  342. } catch (ReflectionWorld.ReflectionWorldException rwEx) {
  343. throw new IllegalArgumentException(rwEx.getMessage());
  344. }
  345. }
  346. private World getWorld() {
  347. return world;
  348. }
  349. /* for testing */
  350. Set<PointcutPrimitive> getSupportedPrimitives() {
  351. return supportedPrimitives;
  352. }
  353. /* for testing */
  354. IMessageHandler setCustomMessageHandler(IMessageHandler aHandler) {
  355. IMessageHandler current = getWorld().getMessageHandler();
  356. getWorld().setMessageHandler(aHandler);
  357. return current;
  358. }
  359. private IScope buildResolutionScope(Class<?> inScope, PointcutParameter[] formalParameters) {
  360. if (formalParameters == null) {
  361. formalParameters = new PointcutParameter[0];
  362. }
  363. FormalBinding[] formalBindings = new FormalBinding[formalParameters.length];
  364. for (int i = 0; i < formalBindings.length; i++) {
  365. formalBindings[i] = new FormalBinding(toUnresolvedType(formalParameters[i].getType()), formalParameters[i].getName(), i);
  366. }
  367. if (inScope == null) {
  368. return new SimpleScope(getWorld(), formalBindings);
  369. } else {
  370. ResolvedType inType = getWorld().resolve(inScope.getName());
  371. ISourceContext sourceContext = new ISourceContext() {
  372. public ISourceLocation makeSourceLocation(IHasPosition position) {
  373. return new SourceLocation(new File(""), 0);
  374. }
  375. public ISourceLocation makeSourceLocation(int line, int offset) {
  376. return new SourceLocation(new File(""), line);
  377. }
  378. public int getOffset() {
  379. return 0;
  380. }
  381. public void tidy() {
  382. }
  383. };
  384. return new BindingScope(inType, sourceContext, formalBindings);
  385. }
  386. }
  387. private UnresolvedType toUnresolvedType(Class<?> clazz) {
  388. if (clazz.isArray()) {
  389. return UnresolvedType.forSignature(clazz.getName().replace('.', '/'));
  390. } else {
  391. return UnresolvedType.forName(clazz.getName());
  392. }
  393. }
  394. private void validateAgainstSupportedPrimitives(Pointcut pc, String expression) {
  395. switch (pc.getPointcutKind()) {
  396. case Pointcut.AND:
  397. validateAgainstSupportedPrimitives(((AndPointcut) pc).getLeft(), expression);
  398. validateAgainstSupportedPrimitives(((AndPointcut) pc).getRight(), expression);
  399. break;
  400. case Pointcut.ARGS:
  401. if (!supportedPrimitives.contains(PointcutPrimitive.ARGS)) {
  402. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ARGS);
  403. }
  404. break;
  405. case Pointcut.CFLOW:
  406. CflowPointcut cfp = (CflowPointcut) pc;
  407. if (cfp.isCflowBelow()) {
  408. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW_BELOW);
  409. } else {
  410. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CFLOW);
  411. }
  412. case Pointcut.HANDLER:
  413. if (!supportedPrimitives.contains(PointcutPrimitive.HANDLER)) {
  414. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.HANDLER);
  415. }
  416. break;
  417. case Pointcut.IF:
  418. case Pointcut.IF_FALSE:
  419. case Pointcut.IF_TRUE:
  420. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.IF);
  421. case Pointcut.KINDED:
  422. validateKindedPointcut(((KindedPointcut) pc), expression);
  423. break;
  424. case Pointcut.NOT:
  425. validateAgainstSupportedPrimitives(((NotPointcut) pc).getNegatedPointcut(), expression);
  426. break;
  427. case Pointcut.OR:
  428. validateAgainstSupportedPrimitives(((OrPointcut) pc).getLeft(), expression);
  429. validateAgainstSupportedPrimitives(((OrPointcut) pc).getRight(), expression);
  430. break;
  431. case Pointcut.THIS_OR_TARGET:
  432. boolean isThis = ((ThisOrTargetPointcut) pc).isThis();
  433. if (isThis && !supportedPrimitives.contains(PointcutPrimitive.THIS)) {
  434. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.THIS);
  435. } else if (!supportedPrimitives.contains(PointcutPrimitive.TARGET)) {
  436. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.TARGET);
  437. }
  438. break;
  439. case Pointcut.WITHIN:
  440. if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN)) {
  441. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN);
  442. }
  443. break;
  444. case Pointcut.WITHINCODE:
  445. if (!supportedPrimitives.contains(PointcutPrimitive.WITHIN_CODE)) {
  446. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.WITHIN_CODE);
  447. }
  448. break;
  449. case Pointcut.ATTHIS_OR_TARGET:
  450. isThis = ((ThisOrTargetAnnotationPointcut) pc).isThis();
  451. if (isThis && !supportedPrimitives.contains(PointcutPrimitive.AT_THIS)) {
  452. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_THIS);
  453. } else if (!supportedPrimitives.contains(PointcutPrimitive.AT_TARGET)) {
  454. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_TARGET);
  455. }
  456. break;
  457. case Pointcut.ATARGS:
  458. if (!supportedPrimitives.contains(PointcutPrimitive.AT_ARGS)) {
  459. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ARGS);
  460. }
  461. break;
  462. case Pointcut.ANNOTATION:
  463. if (!supportedPrimitives.contains(PointcutPrimitive.AT_ANNOTATION)) {
  464. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_ANNOTATION);
  465. }
  466. break;
  467. case Pointcut.ATWITHIN:
  468. if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHIN)) {
  469. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHIN);
  470. }
  471. break;
  472. case Pointcut.ATWITHINCODE:
  473. if (!supportedPrimitives.contains(PointcutPrimitive.AT_WITHINCODE)) {
  474. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.AT_WITHINCODE);
  475. }
  476. break;
  477. case Pointcut.REFERENCE:
  478. if (!supportedPrimitives.contains(PointcutPrimitive.REFERENCE)) {
  479. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.REFERENCE);
  480. }
  481. break;
  482. case Pointcut.USER_EXTENSION:
  483. // always ok...
  484. break;
  485. case Pointcut.NONE: // deliberate fall-through
  486. default:
  487. throw new IllegalArgumentException("Unknown pointcut kind: " + pc.getPointcutKind());
  488. }
  489. }
  490. private void validateKindedPointcut(KindedPointcut pc, String expression) {
  491. Shadow.Kind kind = pc.getKind();
  492. if ((kind == Shadow.MethodCall) || (kind == Shadow.ConstructorCall)) {
  493. if (!supportedPrimitives.contains(PointcutPrimitive.CALL)) {
  494. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.CALL);
  495. }
  496. } else if ((kind == Shadow.MethodExecution) || (kind == Shadow.ConstructorExecution)) {
  497. if (!supportedPrimitives.contains(PointcutPrimitive.EXECUTION)) {
  498. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.EXECUTION);
  499. }
  500. } else if (kind == Shadow.AdviceExecution) {
  501. if (!supportedPrimitives.contains(PointcutPrimitive.ADVICE_EXECUTION)) {
  502. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.ADVICE_EXECUTION);
  503. }
  504. } else if (kind == Shadow.FieldGet) {
  505. if (!supportedPrimitives.contains(PointcutPrimitive.GET)) {
  506. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.GET);
  507. }
  508. } else if (kind == Shadow.FieldSet) {
  509. if (!supportedPrimitives.contains(PointcutPrimitive.SET)) {
  510. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.SET);
  511. }
  512. } else if (kind == Shadow.Initialization) {
  513. if (!supportedPrimitives.contains(PointcutPrimitive.INITIALIZATION)) {
  514. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.INITIALIZATION);
  515. }
  516. } else if (kind == Shadow.PreInitialization) {
  517. if (!supportedPrimitives.contains(PointcutPrimitive.PRE_INITIALIZATION)) {
  518. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.PRE_INITIALIZATION);
  519. }
  520. } else if (kind == Shadow.StaticInitialization) {
  521. if (!supportedPrimitives.contains(PointcutPrimitive.STATIC_INITIALIZATION)) {
  522. throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.STATIC_INITIALIZATION);
  523. }
  524. }
  525. }
  526. private String buildUserMessageFromParserException(String pc, ParserException ex) {
  527. StringBuffer msg = new StringBuffer();
  528. msg.append("Pointcut is not well-formed: expecting '");
  529. msg.append(ex.getMessage());
  530. msg.append("'");
  531. IHasPosition location = ex.getLocation();
  532. msg.append(" at character position ");
  533. msg.append(location.getStart());
  534. msg.append("\n");
  535. msg.append(pc);
  536. msg.append("\n");
  537. for (int i = 0; i < location.getStart(); i++) {
  538. msg.append(" ");
  539. }
  540. for (int j = location.getStart(); j <= location.getEnd(); j++) {
  541. msg.append("^");
  542. }
  543. msg.append("\n");
  544. return msg.toString();
  545. }
  546. }