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