KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > annotation > AspectAnnotationParser


1 /************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.annotation;
9
10 import org.codehaus.aspectwerkz.definition.AspectDefinition;
11 import org.codehaus.aspectwerkz.definition.DefinitionParserHelper;
12 import org.codehaus.aspectwerkz.definition.AdviceDefinition;
13 import org.codehaus.aspectwerkz.definition.DeploymentScope;
14 import org.codehaus.aspectwerkz.exception.DefinitionException;
15 import org.codehaus.aspectwerkz.reflect.ClassInfo;
16 import org.codehaus.aspectwerkz.reflect.FieldInfo;
17 import org.codehaus.aspectwerkz.reflect.MethodInfo;
18 import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
19 import org.codehaus.aspectwerkz.annotation.instrumentation.asm.AsmAnnotations;
20 import org.codehaus.aspectwerkz.DeploymentModel;
21 import org.codehaus.aspectwerkz.util.Strings;
22 import org.codehaus.aspectwerkz.aspect.AdviceType;
23
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26
27 /**
28  * Extracts the aspects annotations from the class files and creates a meta-data representation of them.
29  * <br/>
30  * Note: we are not using reflection to loop over fields, etc, so that we do not trigger nested loading, which could be
31  * potential target classes.
32  *
33  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
34  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
35  */

36 public class AspectAnnotationParser {
37
38     /**
39      * The sole instance.
40      */

41     private final static AspectAnnotationParser INSTANCE = new AspectAnnotationParser();
42
43     /**
44      * Private constructor to prevent subclassing.
45      */

46     private AspectAnnotationParser() {
47     }
48
49     /**
50      * Parse the attributes and create and return a meta-data representation of them.
51      *
52      * @param classInfo the class to extract attributes from
53      * @param aspectDef the aspect definition
54      * @param loader
55      */

56     public static void parse(final ClassInfo classInfo, final AspectDefinition aspectDef, final ClassLoader JavaDoc loader) {
57         INSTANCE.doParse(classInfo, aspectDef, loader);
58     }
59
60     /**
61      * Parse the attributes and create and return a meta-data representation of them.
62      *
63      * @param classInfo the class to extract attributes from
64      * @param aspectDef the aspect definition
65      * @param loader
66      */

67     private void doParse(final ClassInfo classInfo, final AspectDefinition aspectDef, final ClassLoader JavaDoc loader) {
68         if (classInfo == null) {
69             throw new IllegalArgumentException JavaDoc("class to parse can not be null");
70         }
71
72         Aspect aspectAnnotation = (Aspect) AsmAnnotations.getAnnotation(
73                 AnnotationConstants.ASPECT,
74                 classInfo
75         );
76
77         String JavaDoc aspectName = classInfo.getName();
78         String JavaDoc deploymentModelAsString = null;
79
80         if (aspectAnnotation != null) {
81             if (aspectAnnotation.value() != null) {
82                 //@Aspect(perJVM)
83
deploymentModelAsString = aspectAnnotation.value();
84             } else {
85                 if (aspectAnnotation.name() != null) {
86                     //@Aspect(name=..)
87
aspectName = aspectAnnotation.name();
88                 }
89                 if (aspectAnnotation.deploymentModel() != null) {
90                     //@Aspect(deploymentModel=..)
91
deploymentModelAsString = aspectAnnotation.deploymentModel();
92                 }
93             }
94         }
95
96         // attribute settings override the xml settings
97
aspectDef.setDeploymentModel(DeploymentModel.getDeploymentModelFor(deploymentModelAsString));
98         String JavaDoc className = classInfo.getName();
99         parseFieldAttributes(classInfo, aspectDef);
100         parseMethodAttributes(classInfo, className, aspectName, aspectDef);
101     }
102
103     /**
104      * Parses the field attributes and creates a meta-data representation of them.
105      *
106      * @param classInfo the class to extract attributes from
107      * @param aspectDef the aspect definition
108      */

109     private void parseFieldAttributes(final ClassInfo classInfo, final AspectDefinition aspectDef) {
110         if (aspectDef == null) {
111             throw new IllegalArgumentException JavaDoc("aspect definition can not be null");
112         }
113         if (classInfo == null) {
114             return;
115         }
116
117         FieldInfo[] fieldList = classInfo.getFields();
118         for (int i = 0; i < fieldList.length; i++) {
119             FieldInfo field = fieldList[i];
120             for (Iterator JavaDoc iterator = field.getAnnotations().iterator(); iterator.hasNext();) {
121                 AnnotationInfo annotationInfo = (AnnotationInfo) iterator.next();
122                 if (annotationInfo.getAnnotation() == null) {
123                     continue;
124                 }
125                 if (AnnotationConstants.EXPRESSION.equals(annotationInfo.getName())) {
126                     if (field.getType().getName().equals(DeploymentScope.class.getName())) {
127                         DefinitionParserHelper.createAndAddDeploymentScopeDef(
128                                 field.getName(),
129                                 ((Expression) annotationInfo.getAnnotation()).value(),
130                                 aspectDef.getSystemDefinition()
131                         );
132                     } else {
133                         DefinitionParserHelper.createAndAddPointcutDefToAspectDef(
134                                 field.getName(),
135                                 ((Expression) annotationInfo.getAnnotation()).value(),
136                                 aspectDef
137                         );
138                     }
139                 } else if (AnnotationConstants.INTRODUCE.equals(annotationInfo.getName())) {
140                     DefinitionParserHelper.createAndAddInterfaceIntroductionDefToAspectDef(
141                             ((Introduce) annotationInfo.getAnnotation()).value(),
142                             field.getName(),
143                             field.getType().getName(),
144                             aspectDef
145                     );
146                 }
147             }
148         }
149
150         // recursive call, next iteration based on super class
151
parseFieldAttributes(classInfo.getSuperclass(), aspectDef);
152     }
153
154     /**
155      * Parses the method attributes and creates a meta-data representation of them.
156      *
157      * @param classInfo the class
158      * @param aspectClassName the aspect class name
159      * @param aspectName the aspect name
160      * @param aspectDef the aspect definition
161      */

162     private void parseMethodAttributes(final ClassInfo classInfo,
163                                        final String JavaDoc aspectClassName,
164                                        final String JavaDoc aspectName,
165                                        final AspectDefinition aspectDef) {
166         if (classInfo == null) {
167             throw new IllegalArgumentException JavaDoc("class can not be null");
168         }
169         if (aspectClassName == null) {
170             throw new IllegalArgumentException JavaDoc("aspect class name can not be null");
171         }
172         if (aspectName == null) {
173             throw new IllegalArgumentException JavaDoc("aspect name can not be null " + aspectClassName);
174         }
175         if (aspectDef == null) {
176             throw new IllegalArgumentException JavaDoc("aspect definition can not be null");
177         }
178         // get complete method list (includes inherited ones)
179
List JavaDoc methodList = ClassInfoHelper.createMethodList(classInfo);
180
181         // iterate first on all method to lookup @Expression Pointcut annotations so that they can be resolved
182
parsePointcutAttributes(methodList, aspectDef);
183
184         // iterate on the advice annotations
185
for (Iterator JavaDoc it = methodList.iterator(); it.hasNext();) {
186             MethodInfo method = (MethodInfo) it.next();
187             try {
188                 // create the advice name out of the class and method name, <classname>.<methodname>
189
parseAroundAttributes(method, aspectName, aspectClassName, aspectDef);
190                 parseBeforeAttributes(method, aspectName, aspectClassName, aspectDef);
191                 parseAfterAttributes(method, aspectName, aspectClassName, aspectDef);
192             } catch (DefinitionException e) {
193                 System.err.println("AW::WARNING - unable to register advice: " + e.toString());
194                 // TODO AV - better handling of reg issue (f.e. skip the whole aspect, in DocumentParser, based on DefinitionE
195
}
196         }
197     }
198
199     /**
200      * Parses the method pointcut attributes.
201      *
202      * @param methodList
203      * @param aspectDef
204      */

205     private void parsePointcutAttributes(final List JavaDoc methodList, final AspectDefinition aspectDef) {
206         for (Iterator JavaDoc it = methodList.iterator(); it.hasNext();) {
207             MethodInfo method = (MethodInfo) it.next();
208
209             // Pointcut with signature
210
List JavaDoc expressionAnnotations = AsmAnnotations.getAnnotations(AnnotationConstants.EXPRESSION, method);
211             for (Iterator JavaDoc iterator = expressionAnnotations.iterator(); iterator.hasNext();) {
212                 Expression annotation = (Expression) iterator.next();
213                 if (annotation != null) {
214                     DefinitionParserHelper.createAndAddPointcutDefToAspectDef(
215                             getAdviceNameAsInSource(method),
216                             annotation.value(), aspectDef
217                     );
218                 }
219             }
220         }
221     }
222
223     /**
224      * Parses the around attributes.
225      *
226      * @param method
227      * @param aspectName
228      * @param aspectClassName
229      * @param aspectDef
230      */

231     private void parseAroundAttributes(final MethodInfo method,
232                                        final String JavaDoc aspectName,
233                                        final String JavaDoc aspectClassName,
234                                        final AspectDefinition aspectDef) {
235         List JavaDoc aroundAnnotations = AsmAnnotations.getAnnotations(AnnotationConstants.AROUND, method);
236         for (Iterator JavaDoc iterator = aroundAnnotations.iterator(); iterator.hasNext();) {
237             Around aroundAnnotation = (Around) iterator.next();
238             if (aroundAnnotation != null) {
239                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
240                         getAdviceNameAsInSource(method),
241                         AdviceType.AROUND,
242                         aroundAnnotation.value(),
243                         null,
244                         aspectName,
245                         aspectClassName,
246                         method,
247                         aspectDef
248                 );
249                 aspectDef.addAroundAdviceDefinition(adviceDef);
250             }
251         }
252     }
253
254     /**
255      * Parses the before attributes.
256      *
257      * @param method
258      * @param aspectName
259      * @param aspectClassName
260      * @param aspectDef
261      */

262     private void parseBeforeAttributes(final MethodInfo method,
263                                        final String JavaDoc aspectName,
264                                        final String JavaDoc aspectClassName,
265                                        final AspectDefinition aspectDef) {
266         List JavaDoc beforeAnnotations = AsmAnnotations.getAnnotations(AnnotationConstants.BEFORE, method);
267         for (Iterator JavaDoc iterator = beforeAnnotations.iterator(); iterator.hasNext();) {
268             Before beforeAnnotation = (Before) iterator.next();
269             if (beforeAnnotation != null) {
270                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
271                         getAdviceNameAsInSource(method),
272                         AdviceType.BEFORE,
273                         beforeAnnotation.value(),
274                         null,
275                         aspectName,
276                         aspectClassName,
277                         method,
278                         aspectDef
279                 );
280                 aspectDef.addBeforeAdviceDefinition(adviceDef);
281             }
282         }
283     }
284
285     /**
286      * Parses the after attributes.
287      *
288      * @param method
289      * @param aspectName
290      * @param aspectClassName
291      * @param aspectDef
292      */

293     private void parseAfterAttributes(final MethodInfo method,
294                                       final String JavaDoc aspectName,
295                                       final String JavaDoc aspectClassName,
296                                       final AspectDefinition aspectDef) {
297         List JavaDoc afterAnnotations = AsmAnnotations.getAnnotations(AnnotationConstants.AFTER, method);
298         for (Iterator JavaDoc iterator = afterAnnotations.iterator(); iterator.hasNext();) {
299             After annotation = (After) iterator.next();
300             if (annotation != null) {
301                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
302                         getAdviceNameAsInSource(method),
303                         AdviceType.AFTER,
304                         annotation.value(),
305                         null,
306                         aspectName,
307                         aspectClassName,
308                         method,
309                         aspectDef
310                 );
311                 aspectDef.addAfterAdviceDefinition(adviceDef);
312             }
313         }
314         afterAnnotations = AsmAnnotations.getAnnotations(AnnotationConstants.AFTER_RETURNING, method);
315         for (Iterator JavaDoc iterator = afterAnnotations.iterator(); iterator.hasNext();) {
316             AfterReturning annotation = (AfterReturning) iterator.next();
317             if (annotation != null) {
318                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
319                         getAdviceNameAsInSource(method),
320                         AdviceType.AFTER_RETURNING,
321                         getExpressionElseValue(annotation.value(), annotation.pointcut()),
322                         annotation.type(),
323                         aspectName,
324                         aspectClassName,
325                         method,
326                         aspectDef
327                 );
328                 aspectDef.addAfterAdviceDefinition(adviceDef);
329             }
330         }
331         afterAnnotations = AsmAnnotations.getAnnotations(AnnotationConstants.AFTER_THROWING, method);
332         for (Iterator JavaDoc iterator = afterAnnotations.iterator(); iterator.hasNext();) {
333             AfterThrowing annotation = (AfterThrowing) iterator.next();
334             if (annotation != null) {
335                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
336                         getAdviceNameAsInSource(method),
337                         AdviceType.AFTER_THROWING,
338                         getExpressionElseValue(annotation.value(), annotation.pointcut()),
339                         annotation.type(),
340                         aspectName,
341                         aspectClassName,
342                         method,
343                         aspectDef
344                 );
345                 aspectDef.addAfterAdviceDefinition(adviceDef);
346             }
347         }
348         afterAnnotations = AsmAnnotations.getAnnotations(AnnotationConstants.AFTER_FINALLY, method);
349         for (Iterator JavaDoc iterator = afterAnnotations.iterator(); iterator.hasNext();) {
350             AfterFinally annotation = (AfterFinally) iterator.next();
351             if (annotation != null) {
352                 AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
353                         getAdviceNameAsInSource(method),
354                         AdviceType.AFTER_FINALLY,
355                         annotation.value(),
356                         null,
357                         aspectName,
358                         aspectClassName,
359                         method,
360                         aspectDef
361                 );
362                 aspectDef.addAfterAdviceDefinition(adviceDef);
363             }
364         }
365     }
366
367     /**
368      * Returns the call signature of a Pointcut or advice with signature methodName(paramType paramName, ...) [we ignore
369      * the return type] If there is no parameters, the call signature is not "name()" but just "name"
370      *
371      * @param methodInfo
372      * @return string representation (see javavadoc)
373      */

374     private static String JavaDoc getAdviceNameAsInSource(final MethodInfo methodInfo) {
375         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(methodInfo.getName());
376         if (methodInfo.getParameterNames() == null
377             || methodInfo.getParameterNames().length != methodInfo.getParameterTypes().length
378             || (methodInfo.getParameterNames().length > 0 && methodInfo.getParameterNames()[0] == null)) {
379             return methodInfo.getName();
380 // throw new DefinitionException(
381
// "Could not access source information for method " + methodInfo.getDeclaringType().getName() + "." +
382
// methodInfo.getName() +
383
// methodInfo.getSignature() +
384
// ". Compile aspects with javac -g."
385
// );
386
}
387         if (methodInfo.getParameterNames().length > 0) {
388             buffer.append('(');
389             for (int i = 0; i < methodInfo.getParameterNames().length; i++) {
390                 if (i > 0) {
391                     buffer.append(", ");
392                 }
393                 String JavaDoc parameterName = methodInfo.getParameterNames()[i];
394                 buffer.append(methodInfo.getParameterTypes()[i].getName());
395                 buffer.append(' ').append(parameterName);
396             }
397             buffer.append(')');
398         }
399         return buffer.toString();
400     }
401
402     /**
403      * Handles specific syntax for @AfterXXX annotation, where we can write it using the default "value" element
404      * or instead specify the pointcut using "pointcut", and optionally a "type" element.
405      *
406      * @param value
407      * @param pointcut
408      * @return the one of value or expression which is not null. Both cannot be specified at the same time
409      */

410     public static String JavaDoc getExpressionElseValue(String JavaDoc value, String JavaDoc pointcut) {
411         if (!Strings.isNullOrEmpty(pointcut)) {
412             return pointcut;
413         } else if (!Strings.isNullOrEmpty(value)) {
414             return value;
415         } else {
416             throw new DefinitionException("neither expression nor value had a valid value");
417         }
418     }
419
420 }
Popular Tags