KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > definition > DocumentParser


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 JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Set JavaDoc;
36 import java.util.HashSet JavaDoc;
37 import java.util.StringTokenizer JavaDoc;
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 JavaDoc parseAspectClassNames(final Document document) {
54         final List JavaDoc aspectClassNames = new ArrayList JavaDoc();
55         for (Iterator JavaDoc it1 = document.getRootElement().elementIterator("system"); it1.hasNext();) {
56             Element system = (Element) it1.next();
57             final String JavaDoc basePackage = getBasePackage(system);
58             for (Iterator JavaDoc it11 = system.elementIterator("aspect"); it11.hasNext();) {
59                 String JavaDoc className = null;
60                 Element aspect = (Element) it11.next();
61                 for (Iterator JavaDoc it2 = aspect.attributeIterator(); it2.hasNext();) {
62                     Attribute attribute = (Attribute) it2.next();
63                     final String JavaDoc name = attribute.getName().trim();
64                     final String JavaDoc value = attribute.getValue().trim();
65                     if (name.equalsIgnoreCase("class")) {
66                         className = value;
67                     }
68                 }
69                 aspectClassNames.add(basePackage + className);
70             }
71             for (Iterator JavaDoc it11 = system.elementIterator("package"); it11.hasNext();) {
72                 final Element packageElement = ((Element) it11.next());
73                 final String JavaDoc packageName = getPackage(packageElement);
74                 for (Iterator JavaDoc it12 = packageElement.elementIterator("aspect"); it12.hasNext();) {
75                     String JavaDoc className = null;
76                     Element aspect = (Element) it12.next();
77                     for (Iterator JavaDoc it2 = aspect.attributeIterator(); it2.hasNext();) {
78                         Attribute attribute = (Attribute) it2.next();
79                         final String JavaDoc name = attribute.getName().trim();
80                         final String JavaDoc 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 JavaDoc 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 JavaDoc specialAspectName = null;
112         String JavaDoc className = null;
113         String JavaDoc deploymentModelAsString = null;
114         String JavaDoc containerClassName = null;
115         for (Iterator JavaDoc it2 = aspect.attributeIterator(); it2.hasNext();) {
116             Attribute attribute = (Attribute) it2.next();
117             final String JavaDoc name = attribute.getName().trim();
118             final String JavaDoc 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 JavaDoc 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 JavaDoc parse(final ClassLoader JavaDoc 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 JavaDoc parseSystemElements(final ClassLoader JavaDoc loader, final Element root) {
178         final Set JavaDoc systemDefs = new HashSet JavaDoc();
179         for (Iterator JavaDoc 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 JavaDoc loader,
198                                                        final Element systemElement,
199                                                        final String JavaDoc basePackage) {
200         String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc parseGlobalPointcutDefs(final Element systemElement) {
253         final List JavaDoc globalPointcuts = new ArrayList JavaDoc();
254         for (Iterator JavaDoc it11 = systemElement.elementIterator("pointcut"); it11.hasNext();) {
255             PointcutInfo pointcutInfo = new PointcutInfo();
256             Element globalPointcut = (Element) it11.next();
257             for (Iterator JavaDoc it2 = globalPointcut.attributeIterator(); it2.hasNext();) {
258                 Attribute attribute = (Attribute) it2.next();
259                 final String JavaDoc name = attribute.getName().trim();
260                 final String JavaDoc 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 JavaDoc it11 = systemElement.elementIterator("deployment-scope"); it11.hasNext();) {
285             String JavaDoc expression = null;
286             String JavaDoc name = null;
287             Element globalPointcut = (Element) it11.next();
288             for (Iterator JavaDoc it2 = globalPointcut.attributeIterator(); it2.hasNext();) {
289                 Attribute attribute = (Attribute) it2.next();
290                 final String JavaDoc attrName = attribute.getName().trim();
291                 final String JavaDoc 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 JavaDoc it11 = systemElement.elementIterator("advisable"); it11.hasNext();) {
315             Element advisableElement = (Element) it11.next();
316             String JavaDoc expression = "";
317             String JavaDoc pointcutTypes = "all";
318             for (Iterator JavaDoc it2 = advisableElement.attributeIterator(); it2.hasNext();) {
319                 Attribute attribute = (Attribute) it2.next();
320                 final String JavaDoc name = attribute.getName().trim();
321                 final String JavaDoc 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 JavaDoc loader,
346                                              final Element systemElement,
347                                              final SystemDefinition definition,
348                                              final String JavaDoc basePackage,
349                                              final List JavaDoc globalPointcuts) {
350         for (Iterator JavaDoc it1 = systemElement.elementIterator("package"); it1.hasNext();) {
351             final Element packageElement = ((Element) it1.next());
352             final String JavaDoc 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 JavaDoc loader,
369                                             final Element systemElement,
370                                             final SystemDefinition definition,
371                                             final String JavaDoc packageName,
372                                             final List JavaDoc globalPointcuts) {
373
374         for (Iterator JavaDoc it1 = systemElement.elementIterator("aspect"); it1.hasNext();) {
375             String JavaDoc aspectName = null;
376             String JavaDoc className = null;
377             String JavaDoc deploymentModel = null;
378             String JavaDoc containerClassName = null;
379             Element aspect = (Element) it1.next();
380             for (Iterator JavaDoc it2 = aspect.attributeIterator(); it2.hasNext();) {
381                 Attribute attribute = (Attribute) it2.next();
382                 final String JavaDoc name = attribute.getName().trim();
383                 final String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc loader,
466                                            final Element systemElement,
467                                            final SystemDefinition systemDefinition,
468                                            final String JavaDoc packageName) {
469
470         for (Iterator JavaDoc it1 = systemElement.elementIterator("mixin"); it1.hasNext();) {
471             String JavaDoc className = null;
472             String JavaDoc deploymentModelAsString = null;
473             boolean isTransient = false;
474             boolean isTransientSetInXML = false;
475             String JavaDoc factoryClassName = null;
476             String JavaDoc expression = null;
477             Element mixin = (Element) it1.next();
478             for (Iterator JavaDoc it2 = mixin.attributeIterator(); it2.hasNext();) {
479                 Attribute attribute = (Attribute) it2.next();
480                 final String JavaDoc name = attribute.getName().trim();
481                 final String JavaDoc 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 JavaDoc mixinClassName = packageName + className;
498
499             // create the mixin definition
500
ClassInfo mixinClassInfo;
501             try {
502                 mixinClassInfo = AsmClassInfo.getClassInfo(mixinClassName, loader);
503             } catch (Exception JavaDoc 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 JavaDoc clazz = Virtual.class;
554         final String JavaDoc 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 JavaDoc[]{}));
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 JavaDoc e) {
572             throw new Error JavaDoc("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 JavaDoc 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 JavaDoc 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 JavaDoc it2 = aspectElement.elementIterator(); it2.hasNext();) {
623             Element pointcutElement = (Element) it2.next();
624             if (pointcutElement.getName().trim().equals("pointcut")) {
625                 String JavaDoc name = pointcutElement.attributeValue("name");
626                 String JavaDoc 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 JavaDoc name = pointcutElement.attributeValue("name");
634                 String JavaDoc 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 JavaDoc expression = pointcutElement.attributeValue("expression");
644                 String JavaDoc 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 JavaDoc methodList = ClassInfoHelper.createMethodList(aspectClassInfo);
664         for (Iterator JavaDoc it2 = aspectElement.elementIterator(); it2.hasNext();) {
665             Element adviceElement = (Element) it2.next();
666             if (adviceElement.getName().trim().equals("advice")) {
667                 String JavaDoc name = adviceElement.attributeValue("name");
668                 String JavaDoc type = adviceElement.attributeValue("type");
669                 String JavaDoc bindTo = adviceElement.attributeValue("bind-to");
670
671                 String JavaDoc adviceName = name;
672                 MethodInfo method = null;
673                 for (Iterator JavaDoc 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 JavaDoc it1 = adviceElement.elementIterator("bind-to"); it1.hasNext();) {
703                     Element bindToElement = (Element) it1.next();
704                     String JavaDoc 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 JavaDoc packageName,
722                                                final ClassLoader JavaDoc loader) {
723         for (Iterator JavaDoc it2 = aspectElement.elementIterator(); it2.hasNext();) {
724             Element introduceElement = (Element) it2.next();
725             if (introduceElement.getName().trim().equals("introduce")) {
726                 String JavaDoc klass = introduceElement.attributeValue("class");
727                 String JavaDoc name = introduceElement.attributeValue("name");
728                 String JavaDoc bindTo = introduceElement.attributeValue("bind-to");
729
730                 // default name = FQN
731
final String JavaDoc 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 JavaDoc 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 JavaDoc it1 = introduceElement.elementIterator("bind-to"); it1.hasNext();) {
761                         Element bindToElement = (Element) it1.next();
762                         String JavaDoc 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 JavaDoc type,
785                                                           final String JavaDoc bindTo,
786                                                           final String JavaDoc name,
787                                                           final MethodInfo method,
788                                                           final AspectDefinition aspectDef) {
789         try {
790             if (type.equalsIgnoreCase("around")) {
791                 final String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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     private static String JavaDoc getPackage(final Element packageElement) {
877         String JavaDoc packageName = "";
878         for (Iterator JavaDoc it2 = packageElement.attributeIterator(); it2.hasNext();) {
879             Attribute attribute = (Attribute) it2.next();
880             if (attribute.getName().trim().equalsIgnoreCase("name")) {
881                 packageName = attribute.getValue().trim();
882                 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 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 JavaDoc packageName) {
907         for (Iterator JavaDoc it1 = root.elementIterator("include"); it1.hasNext();) {
908             String JavaDoc includePackage = "";
909             Element includeElement = (Element) it1.next();
910             for (Iterator JavaDoc 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 JavaDoc packageName) {
948         for (Iterator JavaDoc it1 = root.elementIterator("exclude"); it1.hasNext();) {
949             String JavaDoc excludePackage = "";
950             Element excludeElement = (Element) it1.next();
951             for (Iterator JavaDoc 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 JavaDoc packageName) {
989         for (Iterator JavaDoc it1 = root.elementIterator("prepare"); it1.hasNext();) {
990             String JavaDoc preparePackage = "";
991             Element prepareElement = (Element) it1.next();
992             for (Iterator JavaDoc 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 JavaDoc getBasePackage(final Element system) {
1027        String JavaDoc basePackage = "";
1028        for (Iterator JavaDoc 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 JavaDoc name;
1052        public String JavaDoc 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 JavaDoc adviceSignature) {
1066        // grab components from adviceSignature
1067
//TODO catch AOOBE for better syntax error reporting
1068
String JavaDoc[] 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 JavaDoc paramType = signatureElements[i++];
1090            String JavaDoc methodParamType = method.getParameterTypes()[argIndex++].getName();
1091            // handle shortcuts for java.lang.* and JoinPoint, StaticJoinPoint and Rtti
1092
String JavaDoc paramTypeResolved = (String JavaDoc) 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 JavaDoc withinPointcut,
1111                                                  final String JavaDoc 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 JavaDoc tokenizer = new StringTokenizer JavaDoc(pointcutTypes, "|");
1135            while (tokenizer.hasMoreTokens()) {
1136                String JavaDoc 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}
Popular Tags