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.DeploymentModel;
11  import org.codehaus.aspectwerkz.util.Strings;
12  import org.codehaus.aspectwerkz.aspect.AdviceType;
13  import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo;
14  import org.codehaus.aspectwerkz.expression.regexp.Pattern;
15  import org.codehaus.aspectwerkz.joinpoint.JoinPoint;
16  import org.codehaus.aspectwerkz.annotation.AspectAnnotationParser;
17  import org.codehaus.aspectwerkz.exception.DefinitionException;
18  import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
19  import org.codehaus.aspectwerkz.transform.ReflectHelper;
20  import org.dom4j.Attribute;
21  import org.dom4j.Document;
22  import org.dom4j.Element;
23  
24  import java.lang.reflect.Method;
25  import java.util.ArrayList;
26  import java.util.Iterator;
27  import java.util.List;
28  
29  /***
30   * Parses the XML definition using <tt>dom4j</tt>.
31   *
32   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
33   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
34   */
35  public class DocumentParser {
36  
37      /***
38       * Parses aspect class names.
39       *
40       * @param document the defintion as a document
41       * @return the aspect class names
42       */
43      public static List parseAspectClassNames(final Document document) {
44          final List aspectClassNames = new ArrayList();
45          for (Iterator it1 = document.getRootElement().elementIterator("system"); it1.hasNext();) {
46              Element system = (Element) it1.next();
47              final String packageName = getBasePackage(system);
48              for (Iterator it11 = system.elementIterator("aspect"); it11.hasNext();) {
49                  String className = null;
50                  Element aspect = (Element) it11.next();
51                  for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
52                      Attribute attribute = (Attribute) it2.next();
53                      final String name = attribute.getName().trim();
54                      final String value = attribute.getValue().trim();
55                      if (name.equalsIgnoreCase("class")) {
56                          className = value;
57                      }
58                  }
59                  String aspectClassName = packageName + className;
60                  aspectClassNames.add(aspectClassName);
61              }
62              for (Iterator it11 = system.elementIterator("package"); it11.hasNext();) {
63                  g>final Element packageElement = ((Element) it11.next());
64                  g>final String packageName1 = getPackage(packageElement);
65                  ong>for (Iterator it12 = packageElement.elementIterator("aspect"); it12.hasNext();) {
66                      String className = null;
67                      Element aspect = (Element) it12.next();
68                      for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
69                          Attribute attribute = (Attribute) it2.next();
70                          final String name = attribute.getName().trim();
71                          final String value = attribute.getValue().trim();
72                          if (name.equalsIgnoreCase("class")) {
73                              className = value;
74                          }
75                      }
76                      String aspectClassName = packageName1 + className;
77                      aspectClassNames.add(aspectClassName);
78                  }
79              }
80          }
81          return aspectClassNames;
82      }
83  
84      /***
85       * Parses the definition DOM document.
86       *
87       * @param loader   the current class loader
88       * @param document the defintion as a document
89       * @return the definitions
90       */
91      public static List parse(final ClassLoader loader, final Document document) {
92          final Element root = document.getRootElement();
93  
94          // parse the transformation scopes
95          return parseSystemElements(loader, root);
96      }
97  
98      /***
99       * Parses the <tt>system</tt> elements.
100      *
101      * @param loader the current class loader
102      * @param root   the root element
103      */
104     private static List parseSystemElements(final ClassLoader loader, final Element root) {
105         final List systemDefs = new ArrayList();
106         for (Iterator it1 = root.elementIterator("system"); it1.hasNext();) {
107             Element system = (Element) it1.next();
108             SystemDefinition definition = parseSystemElement(loader, system, getBasePackage(system));
109             if (definition != null) {
110                 systemDefs.add(definition);
111             }
112         }
113         return systemDefs;
114     }
115 
116     /***
117      * Parses the <tt>system</tt> elements.
118      *
119      * @param loader        the current class loader
120      * @param systemElement the system element
121      * @param basePackage   the base package
122      * @return the definition for the system
123      */
124     private static SystemDefinition parseSystemElement(final ClassLoader loader,
125                                                        final Element systemElement,
126                                                        final String basePackage) {
127         String uuid = systemElement.attributeValue("id");
128         if ((uuid == null) || uuid.equals("")) {
129             throw new DefinitionException("system UUID must be specified");
130         }
131         final SystemDefinition definition = new SystemDefinition(uuid);
132 
133         // parse the global pointcuts
134         List globalPointcuts = parseGlobalPointcuts(systemElement);
135 
136         // parse the include, exclude and prepare elements
137         parseIncludePackageElements(systemElement, definition, basePackage);
138         parseExcludePackageElements(systemElement, definition, basePackage);
139         parsePrepareElements(systemElement, definition, basePackage);
140 
141         // parse without package elements
142         parseAspectElements(loader, systemElement, definition, basePackage, globalPointcuts);
143 
144         // parse with package elements
145         parsePackageElements(loader, systemElement, definition, basePackage, globalPointcuts);
146         return definition;
147     }
148 
149     /***
150      * Parses the global pointcuts.
151      *
152      * @param systemElement the system element
153      * @return a list with the pointcuts
154      */
155     private static List parseGlobalPointcuts(final Element systemElement) {
156         final List globalPointcuts = new ArrayList();
157         for (Iterator it11 = systemElement.elementIterator("pointcut"); it11.hasNext();) {
158             PointcutInfo pointcutInfo = new PointcutInfo();
159             Element globalPointcut = (Element) it11.next();
160             for (Iterator it2 = globalPointcut.attributeIterator(); it2.hasNext();) {
161                 Attribute attribute = (Attribute) it2.next();
162                 final String name = attribute.getName().trim();
163                 final String value = attribute.getValue().trim();
164                 if (name.equalsIgnoreCase("name")) {
165                     pointcutInfo.name = value;
166                 } else if (name.equalsIgnoreCase("expression")) {
167                     pointcutInfo.expression = value;
168                 }
169             }
170             // pointcut CDATA is expression unless already specified as an attribute
171             if (pointcutInfo.expression == null) {
172                 pointcutInfo.expression = globalPointcut.getTextTrim();
173             }
174             globalPointcuts.add(pointcutInfo);
175         }
176         return globalPointcuts;
177     }
178 
179     /***
180      * Parses the definition DOM document.
181      *
182      * @param loader          the current class loader
183      * @param systemElement   the system element
184      * @param definition      the definition
185      * @param basePackage     the base package
186      * @param globalPointcuts the global pointcuts
187      */
188     private static void parsePackageElements(final ClassLoader loader,
189                                              final Element systemElement,
190                                              final SystemDefinition definition,
191                                              final String basePackage,
192                                              final List globalPointcuts) {
193         for (Iterator it1 = systemElement.elementIterator("package"); it1.hasNext();) {
194             final Element packageElement = ((Element) it1.next());
195             final String packageName = basePackage + getPackage(packageElement);
196             parseAspectElements(loader, packageElement, definition, packageName, globalPointcuts);
197         }
198     }
199 
200     /***
201      * Parses the <tt>aspect</tt> elements.
202      *
203      * @param loader          the current class loader
204      * @param systemElement   the system element
205      * @param definition      the definition object
206      * @param packageName     the package name
207      * @param globalPointcuts the global pointcuts
208      */
209     private static void parseAspectElements(final ClassLoader loader,
210                                             final Element systemElement,
211                                             final SystemDefinition definition,
212                                             final String packageName,
213                                             final List globalPointcuts) {
214         for (Iterator it1 = systemElement.elementIterator("aspect"); it1.hasNext();) {
215             String aspectName = null;
216             String className = null;
217             String deploymentModel = null;
218             String containerClassName = null;
219             Element aspect = (Element) it1.next();
220             for (Iterator it2 = aspect.attributeIterator(); it2.hasNext();) {
221                 Attribute attribute = (Attribute) it2.next();
222                 final String name = attribute.getName().trim();
223                 final String value = attribute.getValue().trim();
224                 if (name.equalsIgnoreCase("class")) {
225                     className = value;
226                 } else if (name.equalsIgnoreCase("deployment-model")) {
227                     deploymentModel = value;
228                 } else if (name.equalsIgnoreCase("name")) {
229                     aspectName = value;
230                 } else if (name.equalsIgnoreCase("container")) {
231                     containerClassName = value;
232                 }
233             }
234             String aspectClassName = packageName + className;
235             if (aspectName == null) {
236                 aspectName = aspectClassName;
237             }
238 
239             // create the aspect definition
240             AspectDefinition aspectDef = new AspectDefinition(aspectName, aspectClassName, definition.getUuid());
241             Class aspectClass;
242             try {
243                 aspectClass = loadAspectClass(loader, aspectClassName);
244             } catch (Exception e) {
245                 System.out.println("loader: " + loader);
246                 System.out.println("aspectClassName: " + aspectClassName);
247                 System.err.println(
248                         "Warning: could not load aspect "
249                         + aspectClassName
250                         + " from "
251                         + loader
252                         + "due to: "
253                         + e.toString()
254                 );
255                 e.printStackTrace();
256                 continue;
257             }
258 
259             // add the global pointcuts to the aspect
260             for (Iterator it = globalPointcuts.iterator(); it.hasNext();) {
261                 PointcutInfo pointcutInfo = (PointcutInfo) it.next();
262                 DefinitionParserHelper.createAndAddPointcutDefToAspectDef(
263                         pointcutInfo.name,
264                         pointcutInfo.expression,
265                         aspectDef
266                 );
267             }
268             parsePointcutElements(aspect, aspectDef); //needed to support undefined named pointcut
269             // in Attributes AW-152
270             AspectAnnotationParser.parse(aspectClass, aspectDef, definition);
271 
272             // XML definition settings always overrides attribute definition settings
273             aspectDef.setDeploymentModel(deploymentModel);
274             aspectDef.setName(aspectName);
275             aspectDef.setContainerClassName(containerClassName);
276 
277             // parse the aspect info
278             parseParameterElements(aspect, definition, aspectDef);
279             parsePointcutElements(aspect, aspectDef); //reparse pc for XML override (AW-152)
280             parseAdviceElements(aspect, aspectDef, aspectClass);
281             parseIntroductionElements(aspect, aspectDef, aspectClass, packageName);
282 
283             // register introduction of aspect into the system
284             for (Iterator mixins = aspectDef.getInterfaceIntroductions().iterator(); mixins.hasNext();) {
285                 definition.addInterfaceIntroductionDefinition((InterfaceIntroductionDefinition) mixins.next());
286             }
287             for (Iterator mixins = aspectDef.getIntroductions().iterator(); mixins.hasNext();) {
288                 definition.addIntroductionDefinition((IntroductionDefinition) mixins.next());
289             }
290             definition.addAspect(aspectDef);
291         }
292     }
293 
294     /***
295      * Loads the aspect class.
296      *
297      * @param loader          the class loader
298      * @param aspectClassName the name of the class implementing the aspect
299      * @return the class
300      */
301     private static Class loadAspectClass(final ClassLoader loader, final String aspectClassName) {
302         Class aspectClass;
303         try {
304             aspectClass = loader.loadClass(aspectClassName);
305         } catch (Exception e) {
306             e.printStackTrace();
307             throw new WrappedRuntimeException(e);
308         }
309         return aspectClass;
310     }
311 
312     /***
313      * Parses the aspectElement parameters. <p/>TODO: should perhaps move the parameters to the aspect def instead of
314      * the system def
315      *
316      * @param aspectElement the aspect element
317      * @param def           the system definition
318      * @param aspectDef     the aspect def
319      */
320     private static void parseParameterElements(final Element aspectElement,
321                                                final SystemDefinition def,
322                                                final AspectDefinition aspectDef) {
323         for (Iterator it2 = aspectElement.elementIterator(); it2.hasNext();) {
324             Element parameterElement = (Element) it2.next();
325             if (parameterElement.getName().trim().equals("param")) {
326                 def.addParameter(
327                         aspectDef.getName(), parameterElement.attributeValue("name"), parameterElement
328                                                                                       .attributeValue("value")
329                 );
330             }
331         }
332     }
333 
334     /***
335      * Parses the pointcuts.
336      *
337      * @param aspectElement the aspect element
338      * @param aspectDef     the system definition
339      */
340     private static void parsePointcutElements(final Element aspectElement, final AspectDefinition aspectDef) {
341         for (Iterator it2 = aspectElement.elementIterator(); it2.hasNext();) {
342             Element pointcutElement = (Element) it2.next();
343             if (pointcutElement.getName().trim().equals("pointcut")) {
344                 String name = pointcutElement.attributeValue("name");
345                 String expression = pointcutElement.attributeValue("expression");
346                 // pointcut CDATA is expression unless already specified as an attribute
347                 if (expression == null) {
348                     expression = pointcutElement.getTextTrim();
349                 }
350                 DefinitionParserHelper.createAndAddPointcutDefToAspectDef(name, expression, aspectDef);
351             }
352         }
353     }
354 
355     /***
356      * Parses the advices.
357      *
358      * @param aspectElement the aspect element
359      * @param aspectDef     the system definition
360      * @param aspectClass   the aspect class
361      */
362     private static void parseAdviceElements(final Element aspectElement,
363                                             final AspectDefinition aspectDef,
364                                             final Class aspectClass) {
365         List methodList = ReflectHelper.createCompleteSortedMethodList(aspectClass);
366         for (Iterator it2 = aspectElement.elementIterator(); it2.hasNext();) {
367             Element adviceElement = (Element) it2.next();
368             if (adviceElement.getName().trim().equals("advice")) {
369                 String name = adviceElement.attributeValue("name");
370                 String type = adviceElement.attributeValue("type");
371                 String bindTo = adviceElement.attributeValue("bind-to");
372                 String adviceName = /*aspectClass.getName() + '.' +*/ name;
373                 int methodIndex = 0;
374                 Method method = null;
375                 for (Iterator it3 = methodList.iterator(); it3.hasNext(); methodIndex++) {
376                     Method methodCurrent = (Method) it3.next();
377                     //if (methodCurrent.getName().equals(name)) {
378                     if (matchMethodAsAdvice(methodCurrent, name)) {
379                         method = methodCurrent;
380                         break;
381                     }
382                 }
383                 if (method == null) {
384                     throw new DefinitionException(
385                             "Could not find advice method " + name + " in " + aspectClass.getName()
386                     );
387                 }
388                 createAndAddAdviceDefsToAspectDef(type, bindTo, adviceName, method, methodIndex, aspectDef);
389                 for (Iterator it1 = adviceElement.elementIterator("bind-to"); it1.hasNext();) {
390                     Element bindToElement = (Element) it1.next();
391                     String pointcut = bindToElement.attributeValue("pointcut");
392                     createAndAddAdviceDefsToAspectDef(type, pointcut, adviceName, method, methodIndex, aspectDef);
393                 }
394             }
395         }
396     }
397 
398     /***
399      * Parses the introduction.
400      *
401      * @param aspectElement the aspect element
402      * @param aspectDef     the system definition
403      * @param aspectClass   the aspect class
404      * @param packageName
405      */
406     private static void parseIntroductionElements(final Element aspectElement,
407                                                   final AspectDefinition aspectDef,
408                                                   final Class aspectClass,
409                                                   final String packageName) {
410         for (Iterator it2 = aspectElement.elementIterator(); it2.hasNext();) {
411             Element introduceElement = (Element) it2.next();
412             if (introduceElement.getName().trim().equals("introduce")) {
413                 String klass = introduceElement.attributeValue("class");
414                 String name = introduceElement.attributeValue("name");
415                 String bindTo = introduceElement.attributeValue("bind-to");
416                 String deploymentModel = introduceElement.attributeValue("deployment-model");
417 
418                 // deployment-model defaults to perJVM
419                 if ((deploymentModel == null) || (deploymentModel.length() <= 0)) {
420                     deploymentModel = DeploymentModel.getDeploymentModelAsString(DeploymentModel.PER_JVM);
421                 }
422 
423                 // default name = FQN
424                 if ((name == null) || (name.length() <= 0)) {
425                     name = packageName + klass;
426                 }
427 
428                 // load the mixin to determine if it is a pure interface introduction
429                 Class mixin;
430                 try {
431                     mixin = aspectClass.getClassLoader().loadClass(packageName + klass);
432                 } catch (ClassNotFoundException e) {
433                     throw new DefinitionException(
434                             "could not find mixin implementation: "
435                             + packageName
436                             + klass
437                             + " "
438                             + e.getMessage()
439                     );
440                 }
441 
442                 // pure interface introduction
443                 if (mixin.isInterface()) {
444                     DefinitionParserHelper.createAndAddInterfaceIntroductionDefToAspectDef(
445                             bindTo, name, packageName
446                                           + klass, aspectDef
447                     );
448 
449                     // handles nested "bind-to" elements
450                     for (Iterator it1 = introduceElement.elementIterator("bind-to"); it1.hasNext();) {
451                         Element bindToElement = (Element) it1.next();
452                         String pointcut = bindToElement.attributeValue("pointcut");
453                         DefinitionParserHelper.createAndAddInterfaceIntroductionDefToAspectDef(
454                                 pointcut,
455                                 name,
456                                 packageName + klass,
457                                 aspectDef
458                         );
459                     }
460                 } else {
461                     // mixin introduction
462                     Class[] introduced = mixin.getInterfaces();
463                     String[] introducedInterfaceNames = new String[introduced.length];
464                     for (int i = 0; i < introduced.length; i++) {
465                         introducedInterfaceNames[i] = introduced[i].getName();
466                     }
467                     DefinitionParserHelper.createAndAddIntroductionDefToAspectDef(
468                             mixin,
469                             bindTo,
470                             deploymentModel,
471                             aspectDef
472                     );
473 
474                     // handles nested "bind-to" elements
475                     for (Iterator it1 = introduceElement.elementIterator("bind-to"); it1.hasNext();) {
476                         Element bindToElement = (Element) it1.next();
477                         String pointcut = bindToElement.attributeValue("pointcut");
478                         DefinitionParserHelper.createAndAddIntroductionDefToAspectDef(
479                                 mixin,
480                                 pointcut,
481                                 deploymentModel,
482                                 aspectDef
483                         );
484                     }
485                 }
486             }
487         }
488     }
489 
490     /***
491      * Creates the advice definitions and adds them to the aspect definition.
492      *
493      * @param type        the type of advice
494      * @param bindTo      the pointcut expresion
495      * @param name        the name of the advice
496      * @param method      the method implementing the advice
497      * @param methodIndex the method index
498      * @param aspectDef   the aspect definition
499      */
500     private static void createAndAddAdviceDefsToAspectDef(final String type,
501                                                           final String bindTo,
502                                                           final String name,
503                                                           final Method method,
504                                                           final int methodIndex,
505                                                           final AspectDefinition aspectDef) {
506         try {
507             if (type.equalsIgnoreCase("around")) {
508                 final String aspectName = aspectDef.getName();
509                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
510                         name,
511                         AdviceType.AROUND,
512                         bindTo,
513                         null,
514                         aspectName,
515                         aspectDef.getClassName(),
516                         method,
517                         methodIndex,
518                         aspectDef
519                 );
520                 aspectDef.addAroundAdvice(adviceDef);
521 
522             } else if (type.equalsIgnoreCase("before")) {
523                 final String aspectName = aspectDef.getName();
524                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
525                         name,
526                         AdviceType.BEFORE,
527                         bindTo,
528                         null,
529                         aspectName,
530                         aspectDef.getClassName(),
531                         method,
532                         methodIndex,
533                         aspectDef
534                 );
535                 aspectDef.addBeforeAdvice(adviceDef);
536 
537             } else if (type.startsWith("after")) {
538                 String specialArgumentType = null;
539                 AdviceType adviceType = AdviceType.AFTER;
540                 if (type.startsWith("after returning(")) {
541                     adviceType = AdviceType.AFTER_RETURNING;
542                     int start = type.indexOf('(');
543                     int end = type.indexOf(')');
544                     specialArgumentType = type.substring(start + 1, end).trim();
545                 } else if (type.startsWith("after throwing(")) {
546                     adviceType = AdviceType.AFTER_THROWING;
547                     int start = type.indexOf('(');
548                     int end = type.indexOf(')');
549                     specialArgumentType = type.substring(start + 1, end).trim();
550                 } else if (type.startsWith("after finally")) {
551                     adviceType = AdviceType.AFTER_FINALLY;
552                 }
553                 if (specialArgumentType != null && specialArgumentType.indexOf(' ') > 0) {
554                     throw new DefinitionException(
555                             "argument to after (returning/throwing) can only be a type (parameter name binding should be done using args(..))"
556                     );
557                 }
558                 final String aspectName = aspectDef.getName();
559                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
560                         name,
561                         adviceType,
562                         bindTo,
563                         specialArgumentType,
564                         aspectName,
565                         aspectDef.getClassName(),
566                         method,
567                         methodIndex,
568                         aspectDef
569                 );
570 
571                 aspectDef.addAfterAdvice(adviceDef);
572             }
573         } catch (DefinitionException e) {
574             System.err.println(
575                     "WARNING: unable to register advice "
576                     + aspectDef.getName()
577                     + "."
578                     + name
579                     + " at pointcut \""
580                     + bindTo
581                     + "\" due to: "
582                     + e.getMessage()
583             );
584             // TODO ALEX - better handling of reg issue (f.e. skip the whole aspect, in DocumentParser, based on DefinitionE
585         }
586     }
587 
588     /***
589      * Retrieves and returns the package.
590      *
591      * @param packageElement the package element
592      * @return the package as a string ending with DOT, or empty string
593      */
594     privateong> static String getPackage(final Element packageElement) {
595         String packageName = "";
596         for (Iterator it2 = packageElement.attributeIterator(); it2.hasNext();) {
597             Attribute attribute = (Attribute) it2.next();
598             if (attribute.getName().trim().equalsIgnoreCase("name")) {
599                 packageName = attribute.getValue().trim();
600                 rong>if (packageName.endsWith(".*")) {
601                     packageName = packageName.substring(0, packageName.length() - 1);
602                 } else if (packageName.endsWith(".")) {
603                     ; // skip
604                 } else {
605                     packageName += ".";
606                 }
607                 break;
608             } else {
609                 continue;
610             }
611         }
612         return</strong> packageName;
613     }
614 
615     /***
616      * Parses the <tt>include</tt> elements.
617      *
618      * @param root        the root element
619      * @param definition  the definition object
620      * @param packageName the package name
621      */
622     private static void parseIncludePackageElements(final Element root,
623                                                     final SystemDefinition definition,
624                                                     final String packageName) {
625         for (Iterator it1 = root.elementIterator("include"); it1.hasNext();) {
626             String includePackage = "";
627             Element includeElement = (Element) it1.next();
628             for (Iterator it2 = includeElement.attributeIterator(); it2.hasNext();) {
629                 Attribute attribute = (Attribute) it2.next();
630                 if (attribute.getName().trim().equalsIgnoreCase("package")) {
631                     // handle base package
632                     if (packageName.endsWith(".*")) {
633                         includePackage = packageName.substring(0, packageName.length() - 2);
634                     } else if (packageName.endsWith(".")) {
635                         includePackage = packageName.substring(0, packageName.length() - 1);
636                     }
637 
638                     // handle exclude package
639                     includePackage = packageName + attribute.getValue().trim();
640                     if (includePackage.endsWith(".*")) {
641                         includePackage = includePackage.substring(0, includePackage.length() - 2);
642                     } else if (includePackage.endsWith(".")) {
643                         includePackage = includePackage.substring(0, includePackage.length() - 1);
644                     }
645                     break;
646                 } else {
647                     continue;
648                 }
649             }
650             if (includePackage.length() != 0) {
651                 definition.addIncludePackage(includePackage);
652             }
653         }
654     }
655 
656     /***
657      * Parses the <tt>exclude</tt> elements.
658      *
659      * @param root        the root element
660      * @param definition  the definition object
661      * @param packageName the package name
662      */
663     private static void parseExcludePackageElements(final Element root,
664                                                     final SystemDefinition definition,
665                                                     final String packageName) {
666         for (Iterator it1 = root.elementIterator("exclude"); it1.hasNext();) {
667             String excludePackage = "";
668             Element excludeElement = (Element) it1.next();
669             for (Iterator it2 = excludeElement.attributeIterator(); it2.hasNext();) {
670                 Attribute attribute = (Attribute) it2.next();
671                 if (attribute.getName().trim().equalsIgnoreCase("package")) {
672                     // handle base package
673                     if (packageName.endsWith(".*")) {
674                         excludePackage = packageName.substring(0, packageName.length() - 2);
675                     } else if (packageName.endsWith(".")) {
676                         excludePackage = packageName.substring(0, packageName.length() - 1);
677                     }
678 
679                     // handle exclude package
680                     excludePackage = packageName + attribute.getValue().trim();
681                     if (excludePackage.endsWith(".*")) {
682                         excludePackage = excludePackage.substring(0, excludePackage.length() - 2);
683                     } else if (excludePackage.endsWith(".")) {
684                         excludePackage = excludePackage.substring(0, excludePackage.length() - 1);
685                     }
686                     break;
687                 } else {
688                     continue;
689                 }
690             }
691             if (excludePackage.length() != 0) {
692                 definition.addExcludePackage(excludePackage);
693             }
694         }
695     }
696 
697     /***
698      * Parses the <tt>prepare</tt> elements.
699      *
700      * @param root        the root element
701      * @param definition  the definition object
702      * @param packageName the base package name
703      */
704     public static void parsePrepareElements(final Element root,
705                                             final SystemDefinition definition,
706                                             final String packageName) {
707         for (Iterator it1 = root.elementIterator("prepare"); it1.hasNext();) {
708             String preparePackage = "";
709             Element prepareElement = (Element) it1.next();
710             for (Iterator it2 = prepareElement.attributeIterator(); it2.hasNext();) {
711                 Attribute attribute = (Attribute) it2.next();
712                 if (attribute.getName().trim().equals("package")) {
713                     // handle base package
714                     if (packageName.endsWith(".*")) {
715                         preparePackage = packageName.substring(0, packageName.length() - 2);
716                     } else if (packageName.endsWith(".")) {
717                         preparePackage = packageName.substring(0, packageName.length() - 1);
718                     }
719 
720                     // handle prepare package
721                     preparePackage = packageName + attribute.getValue().trim();
722                     if (preparePackage.endsWith(".*")) {
723                         preparePackage = preparePackage.substring(0, preparePackage.length() - 2);
724                     } else if (preparePackage.endsWith(".")) {
725                         preparePackage = preparePackage.substring(0, preparePackage.length() - 1);
726                     }
727                     break;
728                 } else {
729                     continue;
730                 }
731             }
732             if (preparePackage.length() != 0) {
733                 definition.addPreparePackage(preparePackage);
734             }
735         }
736     }
737 
738     /***
739      * Retrieves and returns the base package for a system element
740      *
741      * @param system a system element
742      * @return the base package
743      */
744     private static String getBasePackage(final Element system) {
745         String basePackage = "";
746         for (Iterator it2 = system.attributeIterator(); it2.hasNext();) {
747             Attribute attribute = (Attribute) it2.next();
748             if (attribute.getName().trim().equalsIgnoreCase("base-package")) {
749                 basePackage = attribute.getValue().trim();
750                 if (basePackage.endsWith(".*")) {
751                     basePackage = basePackage.substring(0, basePackage.length() - 1);
752                 } else if (basePackage.endsWith(".")) {
753                     ; // skip
754                 } else {
755                     basePackage += ".";
756                 }
757                 break;
758             } else {
759                 continue;
760             }
761         }
762         return basePackage;
763     }
764 
765     /***
766      * Struct with pointcut info.
767      */
768     private static class PointcutInfo {
769         public String name;
770 
771         public String expression;
772     }
773 
774     /***
775      * Check if a method from an aspect class match a given advice signature.
776      * <br/>
777      * If the signature is just a method name, then we have a match even if JoinPoint is sole method parameter.
778      * Else we match both method name and parameters type, with abbreviation support (java.lang.* and JoinPoint)
779      *
780      * @param method
781      * @param adviceSignature
782      * @return
783      */
784     private static boolean matchMethodAsAdvice(Method method, String adviceSignature) {
785         // grab components from adviceSignature
786         //TODO catch AOOBE for better syntax error reporting
787         String[] signatureElements = Strings.extractMethodSignature(adviceSignature);
788         // check method name
789         if (!method.getName().equals(signatureElements[0])) {
790             return false;
791         }
792         // check number of args
793         if (method.getParameterTypes().length * 2 != signatureElements.length - 1) {
794             // we still match if method has JoinPoint has sole parameter
795             // and adviceSignature has none
796             if (signatureElements.length == 1
797                 && method.getParameterTypes().length == 1
798                 && method.getParameterTypes()[0].getName().equals(JoinPoint.class.getName())) {
799                 return true;
800             } else {
801                 return false;
802             }
803         }
804         int argIndex = 0;
805         for (int i = 1; i < signatureElements.length; i++) {
806             String paramType = signatureElements[i++];
807             String paramName = signatureElements[i];
808             String methodParamType = JavaClassInfo.convertJavaArrayTypeNameToHumanTypeName(
809                     method.getParameterTypes()[argIndex++].getName().replace('/', '.')
810             );
811             // handle shortcuts for java.lang.* and JoinPoint
812             String paramTypeResolved = (String) Pattern.ABBREVIATIONS.get(paramType);
813             if (methodParamType.equals(paramType) || methodParamType.equals(paramTypeResolved)) {
814                 continue;
815             } else {
816                 return false;
817             }
818         }
819         return true;
820     }
821 }