View Javadoc

1   /***************************************************************************************
2    * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved.                 *
3    * http://aspectwerkz.codehaus.org                                                    *
4    * ---------------------------------------------------------------------------------- *
5    * The software in this package is published under the terms of the LGPL license      *
6    * a copy of which has been included with this distribution in the license.txt file.  *
7    **************************************************************************************/
8   package org.codehaus.aspectwerkz.definition;
9   
10  import org.codehaus.aspectwerkz.util.Strings;
11  import org.codehaus.aspectwerkz.aspect.AdviceType;
12  import org.codehaus.aspectwerkz.DeploymentModel;
13  import org.codehaus.aspectwerkz.intercept.AdvisableImpl;
14  import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
15  import org.codehaus.aspectwerkz.reflect.impl.java.JavaMethodInfo;
16  import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo;
17  import org.codehaus.aspectwerkz.reflect.ClassInfo;
18  import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
19  import org.codehaus.aspectwerkz.reflect.MethodInfo;
20  import org.codehaus.aspectwerkz.expression.regexp.Pattern;
21  import org.codehaus.aspectwerkz.expression.ExpressionNamespace;
22  import org.codehaus.aspectwerkz.expression.ExpressionInfo;
23  import org.codehaus.aspectwerkz.annotation.AspectAnnotationParser;
24  import org.codehaus.aspectwerkz.annotation.MixinAnnotationParser;
25  import org.codehaus.aspectwerkz.exception.DefinitionException;
26  import org.codehaus.aspectwerkz.transform.TransformationConstants;
27  import org.codehaus.aspectwerkz.transform.inlining.AspectModelManager;
28  import org.dom4j.Attribute;
29  import org.dom4j.Document;
30  import org.dom4j.Element;
31  
32  import java.util.ArrayList;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.Set;
36  import java.util.HashSet;
37  import java.util.StringTokenizer;
38  
39  /***
40   * Parses the XML definition using <tt>dom4j</tt>.
41   *
42   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
43   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
44   */
45  public class DocumentParser {
46  
47      /***
48       * Parses aspect class names.
49       *
50       * @param document the defintion as a document
51       * @return the aspect class names
52       */
53      public static List parseAspectClassNames(final Document document) {
54          final List aspectClassNames = new ArrayList();
55          for (Iterator it1 = document.getRootElement().elementIterator("system"); it1.hasNext();) {
56              Element system = (Element) it1.next();
57              final String basePackage = getBasePackage(system);
58              for (Iterator it11 = system.elementIterator("aspect"); it11.hasNext();) {
59                  String className = null;
60                  Element aspect = (Element) it11.next();
61                  for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
62                      Attribute attribute = (Attribute) it2.next();
63                      final String name = attribute.getName().trim();
64                      final String value = attribute.getValue().trim();
65                      if (name.equalsIgnoreCase("class")) {
66                          className = value;
67                      }
68                  }
69                  aspectClassNames.add(basePackage + className);
70              }
71              for (Iterator it11 = system.elementIterator("package"); it11.hasNext();) {
72                  g>final Element packageElement = ((Element) it11.next());
73                  g>final String packageName = getPackage(packageElement);
74                  ong>for (Iterator it12 = packageElement.elementIterator("aspect"); it12.hasNext();) {
75                      String className = null;
76                      Element aspect = (Element) it12.next();
77                      for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
78                          Attribute attribute = (Attribute) it2.next();
79                          final String name = attribute.getName().trim();
80                          final String value = attribute.getValue().trim();
81                          if (name.equalsIgnoreCase("class")) {
82                              className = value;
83                          }
84                      }
85                      aspectClassNames.add(packageName + className);
86                  }
87              }
88          }
89          aspectClassNames.add(Virtual.class.getName());
90  
91          return aspectClassNames;
92      }
93  
94      /***
95       * Parses the definition DOM document.
96       *
97       * @param document    the defintion as a document
98       * @param systemDef   the system definition
99       * @param aspectClass the aspect class
100      * @return the definition
101      */
102     public static AspectDefinition parseAspectDefinition(final Document document,
103                                                          final SystemDefinition systemDef,
104                                                          final Class aspectClass) {
105 
106         final Element aspect = document.getRootElement();
107 
108         if (!aspect.getName().equals("aspect")) {
109             throw new DefinitionException("XML definition for aspect is not well-formed: " + document.asXML());
110         }
111         String specialAspectName = null;
112         String className = null;
113         String deploymentModelAsString = null;
114         String containerClassName = null;
115         for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
116             Attribute attribute = (Attribute) it2.next();
117             final String name = attribute.getName().trim();
118             final String value = attribute.getValue().trim();
119             if (name.equalsIgnoreCase("class")) {
120                 className = value;
121             } else if (name.equalsIgnoreCase("deployment-model")) {
122                 deploymentModelAsString = value;
123             } else if (name.equalsIgnoreCase("name")) {
124                 specialAspectName = value;
125             } else if (name.equalsIgnoreCase("container")) {
126                 containerClassName = value;
127             }
128         }
129         if (specialAspectName == null) {
130             specialAspectName = className;
131         }
132 
133         final ClassInfo classInfo = JavaClassInfo.getClassInfo(aspectClass);
134         final ClassLoader loader = aspectClass.getClassLoader();
135 
136         // create the aspect definition
137         final AspectDefinition aspectDef = new AspectDefinition(specialAspectName, classInfo, systemDef);
138         //TODO: if this XML centric deployment is supposed to PRESERVE @Aspect values, then it is broken
139         aspectDef.setContainerClassName(containerClassName);
140         aspectDef.setDeploymentModel(DeploymentModel.getDeploymentModelFor(deploymentModelAsString));
141 
142         parsePointcutElements(aspect, aspectDef); //needed to support undefined named pointcut in Attributes AW-152
143 
144         // load the different aspect model and let them define their aspects
145         AspectModelManager.defineAspect(classInfo, aspectDef, loader);
146 
147         // parse the aspect info
148         parseParameterElements(aspect, aspectDef);
149         parsePointcutElements(aspect, aspectDef); //reparse pc for XML override (AW-152)
150         parseAdviceElements(aspect, aspectDef, JavaClassInfo.getClassInfo(aspectClass));
151         parseIntroduceElements(aspect, aspectDef, "", aspectClass.getClassLoader());
152 
153         systemDef.addAspect(aspectDef);
154         return aspectDef;
155     }
156 
157     /***
158      * Parses the definition DOM document.
159      *
160      * @param loader   the current class loader
161      * @param document the defintion as a document
162      * @return the definitions
163      */
164     public static Set parse(final ClassLoader loader, final Document document) {
165         final Element root = document.getRootElement();
166 
167         // parse the transformation scopes
168         return parseSystemElements(loader, root);
169     }
170 
171     /***
172      * Parses the <tt>system</tt> elements.
173      *
174      * @param loader the current class loader
175      * @param root   the root element
176      */
177     private static Set parseSystemElements(final ClassLoader loader, final Element root) {
178         final Set systemDefs = new HashSet();
179         for (Iterator it1 = root.elementIterator("system"); it1.hasNext();) {
180             Element system = (Element) it1.next();
181             SystemDefinition definition = parseSystemElement(loader, system, getBasePackage(system));
182             if (definition != null) {
183                 systemDefs.add(definition);
184             }
185         }
186         return systemDefs;
187     }
188 
189     /***
190      * Parses the <tt>system</tt> elements.
191      *
192      * @param loader        the current class loader
193      * @param systemElement the system element
194      * @param basePackage   the base package
195      * @return the definition for the system
196      */
197     private static SystemDefinition parseSystemElement(final ClassLoader loader,
198                                                        final Element systemElement,
199                                                        final String basePackage) {
200         String uuid = systemElement.attributeValue("id");
201         if ((uuid == null) || uuid.equals("")) {
202             throw new DefinitionException("system UUID must be specified");
203         }
204         final SystemDefinition definition = new SystemDefinition(uuid);
205 
206         // add the virtual aspect
207         addVirtualAspect(definition);
208 
209         // parse the global pointcuts
210         List globalPointcuts = parseGlobalPointcutDefs(systemElement);
211         //FIXME: systemDef should link a namespace, + remove static hashmap in Namespace (uuid clash in parallel CL)
212         ExpressionNamespace systemNamespace = ExpressionNamespace.getNamespace(definition.getUuid());
213         for (Iterator iterator = globalPointcuts.iterator(); iterator.hasNext();) {
214             PointcutInfo pointcutInfo = (PointcutInfo) iterator.next();
215             systemNamespace.addExpressionInfo(
216                     pointcutInfo.name, new ExpressionInfo(pointcutInfo.expression, systemNamespace.getName())
217             );
218         }
219 
220         // parse the global deployment scopes definitions
221         parseDeploymentScopeDefs(systemElement, definition);
222 
223         // parse the global advisable definitions
224         parseAdvisableDefs(systemElement, definition);
225 
226         // parse the include, exclude and prepare elements
227         parseIncludePackageElements(systemElement, definition, basePackage);
228         parseExcludePackageElements(systemElement, definition, basePackage);
229         parsePrepareElements(systemElement, definition, basePackage);
230 
231         // parse without package elements
232         parseAspectElements(loader, systemElement, definition, basePackage, globalPointcuts);
233 
234         // parse without package elements
235         parseMixinElements(loader, systemElement, definition, basePackage);
236 
237         // parse with package elements
238         parsePackageElements(loader, systemElement, definition, basePackage, globalPointcuts);
239 
240         // add all deployment scopes to the virtual advice
241         DefinitionParserHelper.attachDeploymentScopeDefsToVirtualAdvice(definition);
242 
243         return definition;
244     }
245 
246     /***
247      * Parses the global pointcuts.
248      *
249      * @param systemElement the system element
250      * @return a list with the pointcuts
251      */
252     private static List parseGlobalPointcutDefs(final Element systemElement) {
253         final List globalPointcuts = new ArrayList();
254         for (Iterator it11 = systemElement.elementIterator("pointcut"); it11.hasNext();) {
255             PointcutInfo pointcutInfo = new PointcutInfo();
256             Element globalPointcut = (Element) it11.next();
257             for (Iterator it2 = globalPointcut.attributeIterator(); it2.hasNext();) {
258                 Attribute attribute = (Attribute) it2.next();
259                 final String name = attribute.getName().trim();
260                 final String value = attribute.getValue().trim();
261                 if (name.equalsIgnoreCase("name")) {
262                     pointcutInfo.name = value;
263                 } else if (name.equalsIgnoreCase("expression")) {
264                     pointcutInfo.expression = value;
265                 }
266             }
267             // pointcut CDATA is expression unless already specified as an attribute
268             if (pointcutInfo.expression == null) {
269                 pointcutInfo.expression = globalPointcut.getTextTrim();
270             }
271             globalPointcuts.add(pointcutInfo);
272         }
273         return globalPointcuts;
274     }
275 
276     /***
277      * Parses the global deployment-scope elements.
278      *
279      * @param systemElement the system element
280      * @param definition
281      */
282     private static void parseDeploymentScopeDefs(final Element systemElement,
283                                                  final SystemDefinition definition) {
284         for (Iterator it11 = systemElement.elementIterator("deployment-scope"); it11.hasNext();) {
285             String expression = null;
286             String name = null;
287             Element globalPointcut = (Element) it11.next();
288             for (Iterator it2 = globalPointcut.attributeIterator(); it2.hasNext();) {
289                 Attribute attribute = (Attribute) it2.next();
290                 final String attrName = attribute.getName().trim();
291                 final String attrValue = attribute.getValue().trim();
292                 if (attrName.equalsIgnoreCase("name")) {
293                     name = attrValue;
294                 } else if (attrName.equalsIgnoreCase("expression")) {
295                     expression = attrValue;
296                 }
297             }
298             // pointcut CDATA is expression unless already specified as an attribute
299             if (expression == null) {
300                 expression = globalPointcut.getTextTrim();
301             }
302             DefinitionParserHelper.createAndAddDeploymentScopeDef(name, expression, definition);
303         }
304     }
305 
306     /***
307      * Parses the global advisable elements.
308      *
309      * @param systemElement the system element
310      * @param definition
311      */
312     private static void parseAdvisableDefs(final Element systemElement,
313                                            final SystemDefinition definition) {
314         for (Iterator it11 = systemElement.elementIterator("advisable"); it11.hasNext();) {
315             Element advisableElement = (Element) it11.next();
316             String expression = "";
317             String pointcutTypes = "all";
318             for (Iterator it2 = advisableElement.attributeIterator(); it2.hasNext();) {
319                 Attribute attribute = (Attribute) it2.next();
320                 final String name = attribute.getName().trim();
321                 final String value = attribute.getValue().trim();
322                 if (name.equalsIgnoreCase("expression")) {
323                     expression = value;
324                 } else if (name.equalsIgnoreCase("pointcut-type")) {
325                     pointcutTypes = value;
326                 }
327             }
328             // pointcut CDATA is expression unless already specified as an attribute
329             if (expression == null) {
330                 expression = advisableElement.getTextTrim();
331             }
332             handleAdvisableDefinition(definition, expression, pointcutTypes);
333         }
334     }
335 
336     /***
337      * Parses the definition DOM document.
338      *
339      * @param loader          the current class loader
340      * @param systemElement   the system element
341      * @param definition      the definition
342      * @param basePackage     the base package
343      * @param globalPointcuts the global pointcuts
344      */
345     private static void parsePackageElements(final ClassLoader loader,
346                                              final Element systemElement,
347                                              final SystemDefinition definition,
348                                              final String basePackage,
349                                              final List globalPointcuts) {
350         for (Iterator it1 = systemElement.elementIterator("package"); it1.hasNext();) {
351             final Element packageElement = ((Element) it1.next());
352             final String packageName = basePackage + getPackage(packageElement);
353             parseAspectElements(loader, packageElement, definition, packageName, globalPointcuts);
354             parseMixinElements(loader, packageElement, definition, packageName);
355             parseAdvisableDefs(packageElement, definition);
356         }
357     }
358 
359     /***
360      * Parses the <tt>aspect</tt> elements.
361      *
362      * @param loader          the current class loader
363      * @param systemElement   the system element
364      * @param definition      the definition object
365      * @param packageName     the package name
366      * @param globalPointcuts the global pointcuts
367      */
368     private static void parseAspectElements(final ClassLoader loader,
369                                             final Element systemElement,
370                                             final SystemDefinition definition,
371                                             final String packageName,
372                                             final List globalPointcuts) {
373 
374         for (Iterator it1 = systemElement.elementIterator("aspect"); it1.hasNext();) {
375             String aspectName = null;
376             String className = null;
377             String deploymentModel = null;
378             String containerClassName = null;
379             Element aspect = (Element) it1.next();
380             for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
381                 Attribute attribute = (Attribute) it2.next();
382                 final String name = attribute.getName().trim();
383                 final String value = attribute.getValue().trim();
384                 if (name.equalsIgnoreCase("class")) {
385                     className = value;
386                 } else if (name.equalsIgnoreCase("deployment-model")) {
387                     deploymentModel = value;
388                 } else if (name.equalsIgnoreCase("name")) {
389                     aspectName = value;
390                 } else if (name.equalsIgnoreCase("container")) {
391                     containerClassName = value;
392                 }
393             }
394             String aspectClassName = packageName + className;
395             if (aspectName == null) {
396                 aspectName = aspectClassName;
397             }
398 
399             // create the aspect definition
400             ClassInfo aspectClassInfo;
401             try {
402                 aspectClassInfo = AsmClassInfo.getClassInfo(aspectClassName, loader);
403             } catch (Exception e) {
404                 System.err.println(
405                         "Warning: could not load aspect "
406                         + aspectClassName
407                         + " from "
408                         + loader
409                         + "due to: "
410                         + e.toString()
411                 );
412                 e.printStackTrace();
413                 continue;
414             }
415 
416             final AspectDefinition aspectDef = new AspectDefinition(aspectName, aspectClassInfo, definition);
417 
418             // add the global pointcuts to the aspect
419             for (Iterator it = globalPointcuts.iterator(); it.hasNext();) {
420                 PointcutInfo pointcutInfo = (PointcutInfo) it.next();
421                 DefinitionParserHelper.createAndAddPointcutDefToAspectDef(
422                         pointcutInfo.name,
423                         pointcutInfo.expression,
424                         aspectDef
425                 );
426             }
427             parsePointcutElements(aspect, aspectDef); //needed to support undefined named pointcut in Attributes AW-152
428 
429             // load the different aspect model and let them define their aspects
430             AspectModelManager.defineAspect(aspectClassInfo, aspectDef, loader);
431 
432             // parse the class bytecode annotations
433             AspectAnnotationParser.parse(aspectClassInfo, aspectDef, loader);
434 
435             // XML definition settings always overrides attribute definition settings
436             // AW-357
437             if (!Strings.isNullOrEmpty(deploymentModel)) {
438                 aspectDef.setDeploymentModel(DeploymentModel.getDeploymentModelFor(deploymentModel));
439             }
440             if (!Strings.isNullOrEmpty(aspectName)) {
441                 aspectDef.setName(aspectName);
442             }
443             if (!Strings.isNullOrEmpty(containerClassName)) {
444                 aspectDef.setContainerClassName(containerClassName);
445             }
446 
447             // parse the aspect info
448             parseParameterElements(aspect, aspectDef);
449             parsePointcutElements(aspect, aspectDef); //reparse pc for XML override (AW-152)
450             parseAdviceElements(aspect, aspectDef, aspectClassInfo);
451             parseIntroduceElements(aspect, aspectDef, packageName, loader);
452 
453             definition.addAspect(aspectDef);
454         }
455     }
456 
457     /***
458      * Parses the <tt>mixin</tt> elements.
459      *
460      * @param loader           the current class loader
461      * @param systemElement    the system element
462      * @param systemDefinition the system definition
463      * @param packageName      the package name
464      */
465     private static void parseMixinElements(final ClassLoader loader,
466                                            final Element systemElement,
467                                            final SystemDefinition systemDefinition,
468                                            final String packageName) {
469 
470         for (Iterator it1 = systemElement.elementIterator("mixin"); it1.hasNext();) {
471             String className = null;
472             String deploymentModelAsString = null;
473             boolean isTransient = false;
474             boolean isTransientSetInXML = false;
475             String factoryClassName = null;
476             String expression = null;
477             Element mixin = (Element) it1.next();
478             for (Iterator it2 = mixin.attributeIterator(); it2.hasNext();) {
479                 Attribute attribute = (Attribute) it2.next();
480                 final String name = attribute.getName().trim();
481                 final String value = attribute.getValue().trim();
482                 if (name.equalsIgnoreCase("class")) {
483                     className = value;
484                 } else if (name.equalsIgnoreCase("deployment-model") && value != null) {
485                     deploymentModelAsString = value;
486                 } else if (name.equalsIgnoreCase("transient")) {
487                     if (value != null && value.equalsIgnoreCase("true")) {
488                         isTransient = true;
489                         isTransientSetInXML = true;
490                     }
491                 } else if (name.equalsIgnoreCase("factory")) {
492                     factoryClassName = value;
493                 } else if (name.equalsIgnoreCase("bind-to")) {
494                     expression = value;
495                 }
496             }
497             String mixinClassName = packageName + className;
498 
499             // create the mixin definition
500             ClassInfo mixinClassInfo;
501             try {
502                 mixinClassInfo = AsmClassInfo.getClassInfo(mixinClassName, loader);
503             } catch (Exception e) {
504                 System.err.println(
505                         "Warning: could not load mixin "
506                         + mixinClassName
507                         + " from "
508                         + loader
509                         + "due to: "
510                         + e.toString()
511                 );
512                 e.printStackTrace();
513                 continue;
514             }
515 
516             final DeploymentModel deploymentModel =
517                     (deploymentModelAsString != null) ? DeploymentModel.getDeploymentModelFor(deploymentModelAsString)
518                     : DeploymentModel.PER_INSTANCE;
519 
520             final MixinDefinition mixinDefinition =
521                     DefinitionParserHelper.createAndAddMixinDefToSystemDef(
522                             mixinClassInfo,
523                             expression,
524                             deploymentModel,
525                             isTransient,
526                             systemDefinition
527                     );
528 
529             // parse the class bytecode annotations
530             MixinAnnotationParser.parse(mixinClassInfo, mixinDefinition);
531 
532             // XML definition settings always overrides attribute definition settings if present
533             if (!Strings.isNullOrEmpty(deploymentModelAsString)) {
534                 mixinDefinition.setDeploymentModel(DeploymentModel.getDeploymentModelFor(deploymentModelAsString));
535             }
536             if (!Strings.isNullOrEmpty(factoryClassName)) {
537                 mixinDefinition.setFactoryClassName(factoryClassName);
538             }
539             if (isTransientSetInXML) {
540                 mixinDefinition.setTransient(isTransient);
541             }
542 
543             parseParameterElements(mixin, mixinDefinition);
544         }
545     }
546 
547     /***
548      * Adds a virtual system aspect to the definition. Needed to do various tricks.
549      *
550      * @param definition
551      */
552     public static void addVirtualAspect(final SystemDefinition definition) {
553         final Class clazz = Virtual.class;
554         final String aspectName = clazz.getName();
555         ClassInfo aspectClassInfo = JavaClassInfo.getClassInfo(clazz);
556         final AspectDefinition aspectDef = new AspectDefinition(aspectName, aspectClassInfo, definition);
557         try {
558             MethodInfo methodInfo = JavaMethodInfo.getMethodInfo(clazz.getDeclaredMethod("virtual", new Class[]{}));
559             aspectDef.addBeforeAdviceDefinition(
560                     new AdviceDefinition(
561                             methodInfo.getName(),
562                             AdviceType.BEFORE,
563                             null,
564                             aspectName,
565                             aspectName,
566                             null,
567                             methodInfo,
568                             aspectDef
569                     )
570             );
571         } catch (NoSuchMethodException e) {
572             throw new Error("virtual aspect [" + aspectName + "] does not have expected method: " + e.toString());
573         }
574         definition.addAspect(aspectDef);
575     }
576 
577     /***
578      * Parses the aspectElement parameters.
579      *
580      * @param aspectElement the aspect element
581      * @param aspectDef     the aspect def
582      */
583     private static void parseParameterElements(final Element aspectElement,
584                                                final AspectDefinition aspectDef) {
585         for (Iterator it2 = aspectElement.elementIterator(); it2.hasNext();) {
586             Element parameterElement = (Element) it2.next();
587             if (parameterElement.getName().trim().equals("param")) {
588                 aspectDef.addParameter(
589                         parameterElement.attributeValue("name"),
590                         parameterElement.attributeValue("value")
591                 );
592             }
593         }
594     }
595 
596     /***
597      * Parses the mixinElement parameters.
598      *
599      * @param mixinElement the mixin element
600      * @param mixinDef     the mixin def
601      */
602     private static void parseParameterElements(final Element mixinElement,
603                                                final MixinDefinition mixinDef) {
604         for (Iterator it2 = mixinElement.elementIterator(); it2.hasNext();) {
605             Element parameterElement = (Element) it2.next();
606             if (parameterElement.getName().trim().equals("param")) {
607                 mixinDef.addParameter(
608                         parameterElement.attributeValue("name"),
609                         parameterElement.attributeValue("value")
610                 );
611             }
612         }
613     }
614 
615     /***
616      * Parses the pointcuts.
617      *
618      * @param aspectElement the aspect element
619      * @param aspectDef     the system definition
620      */
621     private static void parsePointcutElements(final Element aspectElement, final AspectDefinition aspectDef) {
622         for (Iterator it2 = aspectElement.elementIterator(); it2.hasNext();) {
623             Element pointcutElement = (Element) it2.next();
624             if (pointcutElement.getName().trim().equals("pointcut")) {
625                 String name = pointcutElement.attributeValue("name");
626                 String expression = pointcutElement.attributeValue("expression");
627                 // pointcut CDATA is expression unless already specified as an attribute
628                 if (expression == null) {
629                     expression = pointcutElement.getTextTrim();
630                 }
631                 DefinitionParserHelper.createAndAddPointcutDefToAspectDef(name, expression, aspectDef);
632             } else if (pointcutElement.getName().trim().equals("deployment-scope")) {
633                 String name = pointcutElement.attributeValue("name");
634                 String expression = pointcutElement.attributeValue("expression");
635                 // pointcut CDATA is expression unless already specified as an attribute
636                 if (expression == null) {
637                     expression = pointcutElement.getTextTrim();
638                 }
639                 DefinitionParserHelper.createAndAddDeploymentScopeDef(
640                         name, expression, aspectDef.getSystemDefinition()
641                 );
642             } else if (pointcutElement.getName().trim().equals("advisable")) {
643                 String expression = pointcutElement.attributeValue("expression");
644                 String pointcutTypes = pointcutElement.attributeValue("pointcut-type");
645                 if (expression == null) {
646                     expression = pointcutElement.getTextTrim();
647                 }
648                 handleAdvisableDefinition(aspectDef.getSystemDefinition(), expression, pointcutTypes);
649             }
650         }
651     }
652 
653     /***
654      * Parses the advices.
655      *
656      * @param aspectElement   the aspect element
657      * @param aspectDef       the system definition
658      * @param aspectClassInfo the aspect class
659      */
660     private static void parseAdviceElements(final Element aspectElement,
661                                             final AspectDefinition aspectDef,
662                                             final ClassInfo aspectClassInfo) {
663         List methodList = ClassInfoHelper.createMethodList(aspectClassInfo);
664         for (Iterator it2 = aspectElement.elementIterator(); it2.hasNext();) {
665             Element adviceElement = (Element) it2.next();
666             if (adviceElement.getName().trim().equals("advice")) {
667                 String name = adviceElement.attributeValue("name");
668                 String type = adviceElement.attributeValue("type");
669                 String bindTo = adviceElement.attributeValue("bind-to");
670 
671                 String adviceName = name;
672                 MethodInfo method = null;
673                 for (Iterator it3 = methodList.iterator(); it3.hasNext();) {
674                     MethodInfo methodCurrent = (MethodInfo) it3.next();
675                     if (aspectDef.isAspectWerkzAspect()) {
676                         if (matchMethodAsAdvice(methodCurrent, name)) {
677                             method = methodCurrent;
678                             break;
679                         }
680                     } else {
681                         // TODO support matchMethodAsAdvice(..) for all aspect models? if so use stuff below
682 //                        AspectModel aspectModel = AspectModelManager.getModelFor(aspectDef.getAspectModel());
683 //                        if (aspectModel.matchMethodAsAdvice(methodCurrent, name)) {
684 //                            method = methodCurrent;
685 //                            break;
686 //                        }
687                         if (methodCurrent.getName().equals(name)) {
688                             method = methodCurrent;
689                             break;
690                         }
691                     }
692                 }
693                 if (method == null) {
694                     throw new DefinitionException(
695                             "could not find advice method [" + name + "] in [" + aspectClassInfo.getName() +
696                             "] (are you using a compiler extension that you have not registered?)"+
697                             " (are you using XML defined advice, with StaticJoinPoint bindings without specifying the full" +
698                             "source like signature?)"
699                     );
700                 }
701                 createAndAddAdviceDefsToAspectDef(type, bindTo, adviceName, method, aspectDef);
702                 for (Iterator it1 = adviceElement.elementIterator("bind-to"); it1.hasNext();) {
703                     Element bindToElement = (Element) it1.next();
704                     String pointcut = bindToElement.attributeValue("pointcut");
705                     createAndAddAdviceDefsToAspectDef(type, pointcut, adviceName, method, aspectDef);
706                 }
707             }
708         }
709     }
710 
711     /***
712      * Parses the interface introductions.
713      *
714      * @param aspectElement the aspect element
715      * @param aspectDef     the system definition
716      * @param packageName
717      * @param loader
718      */
719     private static void parseIntroduceElements(final Element aspectElement,
720                                                final AspectDefinition aspectDef,
721                                                final String packageName,
722                                                final ClassLoader loader) {
723         for (Iterator it2 = aspectElement.elementIterator(); it2.hasNext();) {
724             Element introduceElement = (Element) it2.next();
725             if (introduceElement.getName().trim().equals("introduce")) {
726                 String klass = introduceElement.attributeValue("class");
727                 String name = introduceElement.attributeValue("name");
728                 String bindTo = introduceElement.attributeValue("bind-to");
729 
730                 // default name = FQN
731                 g>final String fullClassName = packageName + klass;
732                 if ((name == null) || (name.length() <= 0)) {
733                     name = fullClassName;
734                 }
735 
736                 // load the class info to determine if it is a pure interface introduction
737                 ClassInfo introductionClassInfo;
738                 try {
739                     introductionClassInfo = AsmClassInfo.getClassInfo(fullClassName, loader);
740                 } catch (Exception e) {
741                     throw new DefinitionException(
742                             "could not find interface introduction: "
743                             + packageName
744                             + klass
745                             + " "
746                             + e.getMessage()
747                     );
748                 }
749 
750                 // pure interface introduction
751                 if (introductionClassInfo.isInterface()) {
752                     DefinitionParserHelper.createAndAddInterfaceIntroductionDefToAspectDef(
753                             bindTo,
754                             name,
755                             fullClassName,
756                             aspectDef
757                     );
758 
759                     // handles nested "bind-to" elements
760                     for (Iterator it1 = introduceElement.elementIterator("bind-to"); it1.hasNext();) {
761                         Element bindToElement = (Element) it1.next();
762                         String pointcut = bindToElement.attributeValue("pointcut");
763                         DefinitionParserHelper.createAndAddInterfaceIntroductionDefToAspectDef(
764                                 pointcut,
765                                 name,
766                                 fullClassName,
767                                 aspectDef
768                         );
769                     }
770                 }
771             }
772         }
773     }
774 
775     /***
776      * Creates the advice definitions and adds them to the aspect definition.
777      *
778      * @param type      the type of advice
779      * @param bindTo    the pointcut expresion
780      * @param name      the name of the advice
781      * @param method    the method implementing the advice
782      * @param aspectDef the aspect definition
783      */
784     private static void createAndAddAdviceDefsToAspectDef(final String type,
785                                                           final String bindTo,
786                                                           final String name,
787                                                           final MethodInfo method,
788                                                           final AspectDefinition aspectDef) {
789         try {
790             if (type.equalsIgnoreCase("around")) {
791                 final String aspectName = aspectDef.getName();
792                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
793                         name,
794                         AdviceType.AROUND,
795                         bindTo,
796                         null,
797                         aspectName,
798                         aspectDef.getClassName(),
799                         method,
800                         aspectDef
801                 );
802                 aspectDef.addAroundAdviceDefinition(adviceDef);
803 
804             } else if (type.equalsIgnoreCase("before")) {
805                 final String aspectName = aspectDef.getName();
806                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
807                         name,
808                         AdviceType.BEFORE,
809                         bindTo,
810                         null,
811                         aspectName,
812                         aspectDef.getClassName(),
813                         method,
814                         aspectDef
815                 );
816                 aspectDef.addBeforeAdviceDefinition(adviceDef);
817 
818             } else if (type.startsWith("after")) {
819                 String specialArgumentType = null;
820                 AdviceType adviceType = AdviceType.AFTER;
821                 if (type.startsWith("after returning(")) {
822                     adviceType = AdviceType.AFTER_RETURNING;
823                     int start = type.indexOf('(');
824                     int end = type.indexOf(')');
825                     specialArgumentType = type.substring(start + 1, end).trim();
826                 } else if (type.startsWith("after throwing(")) {
827                     adviceType = AdviceType.AFTER_THROWING;
828                     int start = type.indexOf('(');
829                     int end = type.indexOf(')');
830                     specialArgumentType = type.substring(start + 1, end).trim();
831                 } else if (type.startsWith("after returning")) {
832                     adviceType = AdviceType.AFTER_RETURNING;
833                 } else if (type.startsWith("after throwing")) {
834                     adviceType = AdviceType.AFTER_THROWING;
835                 } else if (type.startsWith("after")) {
836                     adviceType = AdviceType.AFTER_FINALLY;
837                 } else if (type.startsWith("after finally")) {
838                     adviceType = AdviceType.AFTER_FINALLY;
839                 }
840                 if (specialArgumentType != null && specialArgumentType.indexOf(' ') > 0) {
841                     throw new DefinitionException(
842                             "argument to after (returning/throwing) can only be a type (parameter name binding should be done using args(..))"
843                     );
844                 }
845                 final String aspectName = aspectDef.getName();
846                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
847                         name,
848                         adviceType,
849                         bindTo,
850                         specialArgumentType,
851                         aspectName,
852                         aspectDef.getClassName(),
853                         method,
854                         aspectDef
855                 );
856 
857                 aspectDef.addAfterAdviceDefinition(adviceDef);
858             } else {
859                 throw new DefinitionException("Unkonw type for advice : " + type);
860             }
861         } catch (DefinitionException e) {
862             System.err.println(
863                     "WARNING: unable to register advice " + aspectDef.getName() + "." + name +
864                     " at pointcut [" + bindTo + "] due to: " + e.getMessage()
865             );
866             // TODO ALEX - better handling of reg issue (f.e. skip the whole aspect, in DocumentParser, based on DefinitionE
867         }
868     }
869 
870     /***
871      * Retrieves and returns the package.
872      *
873      * @param packageElement the package element
874      * @return the package as a string ending with DOT, or empty string
875      */
876     privateong> static String getPackage(final Element packageElement) {
877         String packageName = "";
878         for (Iterator it2 = packageElement.attributeIterator(); it2.hasNext();) {
879             Attribute attribute = (Attribute) it2.next();
880             if (attribute.getName().trim().equalsIgnoreCase("name")) {
881                 packageName = attribute.getValue().trim();
882                 rong>if (packageName.endsWith(".*")) {
883                     packageName = packageName.substring(0, packageName.length() - 1);
884                 } else if (packageName.endsWith(".")) {
885                     ; // skip
886                 } else {
887                     packageName += ".";
888                 }
889                 break;
890             } else {
891                 continue;
892             }
893         }
894         return</strong> packageName;
895     }
896 
897     /***
898      * Parses the <tt>include</tt> elements.
899      *
900      * @param root        the root element
901      * @param definition  the definition object
902      * @param packageName the package name
903      */
904     private static void parseIncludePackageElements(final Element root,
905                                                     final SystemDefinition definition,
906                                                     final String packageName) {
907         for (Iterator it1 = root.elementIterator("include"); it1.hasNext();) {
908             String includePackage = "";
909             Element includeElement = (Element) it1.next();
910             for (Iterator it2 = includeElement.attributeIterator(); it2.hasNext();) {
911                 Attribute attribute = (Attribute) it2.next();
912                 if (attribute.getName().trim().equalsIgnoreCase("package")) {
913                     // handle base package
914                     if (packageName.endsWith(".*")) {
915                         includePackage = packageName.substring(0, packageName.length() - 2);
916                     } else if (packageName.endsWith(".")) {
917                         includePackage = packageName.substring(0, packageName.length() - 1);
918                     }
919 
920                     // handle exclude package
921                     includePackage = packageName + attribute.getValue().trim();
922                     if (includePackage.endsWith(".*")) {
923                         includePackage = includePackage.substring(0, includePackage.length() - 2);
924                     } else if (includePackage.endsWith(".")) {
925                         includePackage = includePackage.substring(0, includePackage.length() - 1);
926                     }
927                     break;
928                 } else {
929                     continue;
930                 }
931             }
932             if (includePackage.length() != 0) {
933                 definition.addIncludePackage(includePackage);
934             }
935         }
936     }
937 
938     /***
939      * Parses the <tt>exclude</tt> elements.
940      *
941      * @param root        the root element
942      * @param definition  the definition object
943      * @param packageName the package name
944      */
945     private static void parseExcludePackageElements(final Element root,
946                                                     final SystemDefinition definition,
947                                                     final String packageName) {
948         for (Iterator it1 = root.elementIterator("exclude"); it1.hasNext();) {
949             String excludePackage = "";
950             Element excludeElement = (Element) it1.next();
951             for (Iterator it2 = excludeElement.attributeIterator(); it2.hasNext();) {
952                 Attribute attribute = (Attribute) it2.next();
953                 if (attribute.getName().trim().equalsIgnoreCase("package")) {
954                     // handle base package
955                     if (packageName.endsWith(".*")) {
956                         excludePackage = packageName.substring(0, packageName.length() - 2);
957                     } else if (packageName.endsWith(".")) {
958                         excludePackage = packageName.substring(0, packageName.length() - 1);
959                     }
960 
961                     // handle exclude package
962                     excludePackage = packageName + attribute.getValue().trim();
963                     if (excludePackage.endsWith(".*")) {
964                         excludePackage = excludePackage.substring(0, excludePackage.length() - 2);
965                     } else if (excludePackage.endsWith(".")) {
966                         excludePackage = excludePackage.substring(0, excludePackage.length() - 1);
967                     }
968                     break;
969                 } else {
970                     continue;
971                 }
972             }
973             if (excludePackage.length() != 0) {
974                 definition.addExcludePackage(excludePackage);
975             }
976         }
977     }
978 
979     /***
980      * Parses the <tt>prepare</tt> elements.
981      *
982      * @param root        the root element
983      * @param definition  the definition object
984      * @param packageName the base package name
985      */
986     public static void parsePrepareElements(final Element root,
987                                             final SystemDefinition definition,
988                                             final String packageName) {
989         for (Iterator it1 = root.elementIterator("prepare"); it1.hasNext();) {
990             String preparePackage = "";
991             Element prepareElement = (Element) it1.next();
992             for (Iterator it2 = prepareElement.attributeIterator(); it2.hasNext();) {
993                 Attribute attribute = (Attribute) it2.next();
994                 if (attribute.getName().trim().equals("package")) {
995                     // handle base package
996                     if (packageName.endsWith(".*")) {
997                         preparePackage = packageName.substring(0, packageName.length() - 2);
998                     } else if (packageName.endsWith(".")) {
999                         preparePackage = packageName.substring(0, packageName.length() - 1);
1000                     }
1001 
1002                     // handle prepare package
1003                     preparePackage = packageName + attribute.getValue().trim();
1004                     if (preparePackage.endsWith(".*")) {
1005                         preparePackage = preparePackage.substring(0, preparePackage.length() - 2);
1006                     } else if (preparePackage.endsWith(".")) {
1007                         preparePackage = preparePackage.substring(0, preparePackage.length() - 1);
1008                     }
1009                     break;
1010                 } else {
1011                     continue;
1012                 }
1013             }
1014             if (preparePackage.length() != 0) {
1015                 definition.addPreparePackage(preparePackage);
1016             }
1017         }
1018     }
1019 
1020     /***
1021      * Retrieves and returns the base package for a system element
1022      *
1023      * @param system a system element
1024      * @return the base package
1025      */
1026     private static String getBasePackage(final Element system) {
1027         String basePackage = "";
1028         for (Iterator it2 = system.attributeIterator(); it2.hasNext();) {
1029             Attribute attribute = (Attribute) it2.next();
1030             if (attribute.getName().trim().equalsIgnoreCase("base-package")) {
1031                 basePackage = attribute.getValue().trim();
1032                 if (basePackage.endsWith(".*")) {
1033                     basePackage = basePackage.substring(0, basePackage.length() - 1);
1034                 } else if (basePackage.endsWith(".")) {
1035                     ; // skip
1036                 } else {
1037                     basePackage += ".";
1038                 }
1039                 break;
1040             } else {
1041                 continue;
1042             }
1043         }
1044         return basePackage;
1045     }
1046 
1047     /***
1048      * Struct with pointcut info.
1049      */
1050     private static class PointcutInfo {
1051         public String name;
1052         public String expression;
1053     }
1054 
1055     /***
1056      * Check if a method from an aspect class match a given advice signature.
1057      * <br/>
1058      * If the signature is just a method name, then we have a match even if JoinPoint is sole method parameter.
1059      * Else we match both method name and parameters type, with abbreviation support (java.lang.* and JoinPoint)
1060      *
1061      * @param method
1062      * @param adviceSignature
1063      * @return
1064      */
1065     private static boolean matchMethodAsAdvice(MethodInfo method, String adviceSignature) {
1066         // grab components from adviceSignature
1067         //TODO catch AOOBE for better syntax error reporting
1068         String[] signatureElements = Strings.extractMethodSignature(adviceSignature);
1069 
1070         // check method name
1071         if (!method.getName().equals(signatureElements[0])) {
1072             return false;
1073         }
1074         // check number of args
1075         if (method.getParameterTypes().length * 2 != signatureElements.length - 1) {
1076             // we still match if method has "JoinPoint" has sole parameter
1077             // and adviceSignature has none
1078             if (signatureElements.length == 1 &&
1079                 method.getParameterTypes().length == 1 &&
1080                 (method.getParameterTypes()[0].getName().equals(TransformationConstants.JOIN_POINT_JAVA_CLASS_NAME)
1081                  || method.getParameterTypes()[0].getName().equals(TransformationConstants.STATIC_JOIN_POINT_JAVA_CLASS_NAME))) {
1082                 return true;
1083             } else {
1084                 return false;
1085             }
1086         }
1087         int argIndex = 0;
1088         for (int i = 1; i < signatureElements.length; i++) {
1089             String paramType = signatureElements[i++];
1090             String methodParamType = method.getParameterTypes()[argIndex++].getName();
1091             // handle shortcuts for java.lang.* and JoinPoint, StaticJoinPoint and Rtti
1092             String paramTypeResolved = (String) Pattern.ABBREVIATIONS.get(paramType);
1093             if (methodParamType.equals(paramType) || methodParamType.equals(paramTypeResolved)) {
1094                 continue;
1095             } else {
1096                 return false;
1097             }
1098         }
1099         return true;
1100     }
1101 
1102     /***
1103      * Handles the advisable definition.
1104      *
1105      * @param definition
1106      * @param withinPointcut
1107      * @param pointcutTypes
1108      */
1109     private static void handleAdvisableDefinition(final SystemDefinition definition,
1110                                                   final String withinPointcut,
1111                                                   final String pointcutTypes) {
1112         // add the Advisable Mixin with the expression defined to the system definitions
1113         definition.addMixinDefinition(
1114                 DefinitionParserHelper.createAndAddMixinDefToSystemDef(
1115                         AdvisableImpl.CLASS_INFO,
1116                         withinPointcut,
1117                         DeploymentModel.PER_INSTANCE,
1118                         false, // advisble mixin is NOT transient
1119                         definition
1120                 )
1121         );
1122 
1123         boolean hasAllPointcuts = false;
1124         boolean hasExecutionPointcut = false;
1125         boolean hasCallPointcut = false;
1126         boolean hasSetPointcut = false;
1127         boolean hasGetPointcut = false;
1128         boolean hasHandlerPointcut = false;
1129         if (pointcutTypes == null ||
1130             pointcutTypes.equals("") ||
1131             pointcutTypes.equalsIgnoreCase("all")) {
1132             hasAllPointcuts = true;
1133         } else {
1134             StringTokenizer tokenizer = new StringTokenizer(pointcutTypes, "|");
1135             while (tokenizer.hasMoreTokens()) {
1136                 String token = tokenizer.nextToken();
1137                 if (token.trim().equalsIgnoreCase("all")) {
1138                     hasAllPointcuts = true;
1139                     break;
1140                 } else if (token.trim().equalsIgnoreCase("execution")) {
1141                     hasExecutionPointcut = true;
1142                 } else if (token.trim().equalsIgnoreCase("call")) {
1143                     hasCallPointcut = true;
1144                 } else if (token.trim().equalsIgnoreCase("set")) {
1145                     hasSetPointcut = true;
1146                 } else if (token.trim().equalsIgnoreCase("get")) {
1147                     hasGetPointcut = true;
1148                 } else if (token.trim().equalsIgnoreCase("handler")) {
1149                     hasHandlerPointcut = true;
1150                 }
1151             }
1152         }
1153         if (hasAllPointcuts || hasExecutionPointcut) {
1154             DefinitionParserHelper.createAndAddAdvisableDef(
1155                     // TODO add ctor to expression - BUT: problem with mixin and ctor, ordering issue, Jp.invoke() calls field instance that has not been init yet in ctor (since body not invoked)
1156                     //"(( execution(!static * *.*(..)) || execution(*.new(..)) ) && " + withinPointcut + ')',
1157                     // we exclude static method execution since we need the advisable instance
1158                     "(execution(!static * *.*(..)) && " + withinPointcut + ')',
1159                     definition
1160             );
1161         }
1162         if (hasAllPointcuts || hasCallPointcut) {
1163             DefinitionParserHelper.createAndAddAdvisableDef(
1164                     // TODO add ctor to expression - BUT: problem with mixin and ctor, ordering issue, Jp.invoke() calls field instance that has not been init yet in ctor (since body not invoked)                    //"(call(!static * " + typePattern + ".*(..)) || call(" + typePattern + ".new(..)))",
1165                     // we exclude static method withincode since we need the advisable instance
1166                     // as a consequence, withincode(staticinitialization(..)) is also excluded
1167                     "(call(* *.*(..)) && withincode(!static * *.*(..)) && " + withinPointcut + ')',
1168                     definition
1169             );
1170         }
1171         if (hasAllPointcuts || hasSetPointcut) {
1172             DefinitionParserHelper.createAndAddAdvisableDef(
1173                     // we exclude static method withincode since we need the advisable instance
1174                     // as a consequence, withincode(staticinitialization(..)) is also excluded
1175                     "(set(* *.*) && withincode(!static * *.*(..)) && " + withinPointcut + ')',
1176                     definition
1177             );
1178         }
1179         if (hasAllPointcuts || hasGetPointcut) {
1180             DefinitionParserHelper.createAndAddAdvisableDef(
1181                     // we exclude static method withincode since we need the advisable instance
1182                     // as a consequence, withincode(staticinitialization(..)) is also excluded
1183                     "(get(* *.*) && withincode(!static * *.*(..))  && " + withinPointcut + ')',
1184                     definition
1185             );
1186         }
1187         if (hasAllPointcuts || hasHandlerPointcut) {
1188             DefinitionParserHelper.createAndAddAdvisableDef(
1189                     // we exclude static method withincode since we need the advisable instance
1190                     // as a consequence, withincode(staticinitialization(..)) is also excluded
1191                     "(handler(*..*) && withincode(!static * *.*(..))  && " + withinPointcut + ')',
1192                     definition
1193             );
1194         }
1195     }
1196 }