KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > annotation > AspectAnnotationParser


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

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

32 public class AspectAnnotationParser {
33
34   /**
35    * The sole instance.
36    */

37   private final static AspectAnnotationParser INSTANCE = new AspectAnnotationParser();
38
39   /**
40    * Private constructor to prevent subclassing.
41    */

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

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

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

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

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

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

225   private void parseAroundAttributes(final MethodInfo method,
226                                      final String JavaDoc aspectName,
227                                      final String JavaDoc aspectClassName,
228                                      final AspectDefinition aspectDef) {
229     Around aroundAnnotation = (Around) AsmAnnotations.getAnnotation(AnnotationConstants.AROUND, method);
230     if (aroundAnnotation != null) {
231       AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
232               getAdviceNameAsInSource(method),
233               AdviceType.AROUND,
234               aroundAnnotation.value(),
235               null,
236               aspectName,
237               aspectClassName,
238               method,
239               aspectDef
240       );
241       aspectDef.addAroundAdviceDefinition(adviceDef);
242     }
243   }
244
245   /**
246    * Parses the before attributes.
247    *
248    * @param method
249    * @param aspectName
250    * @param aspectClassName
251    * @param aspectDef
252    */

253   private void parseBeforeAttributes(final MethodInfo method,
254                                      final String JavaDoc aspectName,
255                                      final String JavaDoc aspectClassName,
256                                      final AspectDefinition aspectDef) {
257     Before beforeAnnotation = (Before) AsmAnnotations.getAnnotation(AnnotationConstants.BEFORE, method);
258     if (beforeAnnotation != null) {
259       AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
260               getAdviceNameAsInSource(method),
261               AdviceType.BEFORE,
262               beforeAnnotation.value(),
263               null,
264               aspectName,
265               aspectClassName,
266               method,
267               aspectDef
268       );
269       aspectDef.addBeforeAdviceDefinition(adviceDef);
270     }
271   }
272
273   /**
274    * Parses the after attributes.
275    *
276    * @param method
277    * @param aspectName
278    * @param aspectClassName
279    * @param aspectDef
280    */

281   private void parseAfterAttributes(final MethodInfo method,
282                                     final String JavaDoc aspectName,
283                                     final String JavaDoc aspectClassName,
284                                     final AspectDefinition aspectDef) {
285     After annotationAft = (After) AsmAnnotations.getAnnotation(AnnotationConstants.AFTER, method);
286     if (annotationAft != null) {
287       AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
288               getAdviceNameAsInSource(method),
289               AdviceType.AFTER,
290               annotationAft.value(),
291               null,
292               aspectName,
293               aspectClassName,
294               method,
295               aspectDef
296       );
297       aspectDef.addAfterAdviceDefinition(adviceDef);
298     }
299
300     AfterReturning annotationRet = (AfterReturning) AsmAnnotations.getAnnotation(AnnotationConstants.AFTER_RETURNING, method);
301     if (annotationRet != null) {
302       AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
303               getAdviceNameAsInSource(method),
304               AdviceType.AFTER_RETURNING,
305               getExpressionElseValue(annotationRet.value(), annotationRet.pointcut()),
306               annotationRet.type(),
307               aspectName,
308               aspectClassName,
309               method,
310               aspectDef
311       );
312       aspectDef.addAfterAdviceDefinition(adviceDef);
313     }
314
315     AfterThrowing annotationThr = (AfterThrowing) AsmAnnotations.getAnnotation(AnnotationConstants.AFTER_THROWING, method);
316     if (annotationThr != null) {
317       AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
318               getAdviceNameAsInSource(method),
319               AdviceType.AFTER_THROWING,
320               getExpressionElseValue(annotationThr.value(), annotationThr.pointcut()),
321               annotationThr.type(),
322               aspectName,
323               aspectClassName,
324               method,
325               aspectDef
326       );
327       aspectDef.addAfterAdviceDefinition(adviceDef);
328     }
329
330     AfterFinally annotationFin = (AfterFinally) AsmAnnotations.getAnnotation(AnnotationConstants.AFTER_FINALLY, method);
331     if (annotationFin != null) {
332       AdviceDefinition adviceDef = DefinitionParserHelper.createAdviceDefinition(
333               getAdviceNameAsInSource(method),
334               AdviceType.AFTER_FINALLY,
335               annotationFin.value(),
336               null,
337               aspectName,
338               aspectClassName,
339               method,
340               aspectDef
341       );
342       aspectDef.addAfterAdviceDefinition(adviceDef);
343     }
344   }
345
346   /**
347    * Returns the call signature of a Pointcut or advice with signature methodName(paramType paramName, ...) [we ignore
348    * the return type] If there is no parameters, the call signature is not "name()" but just "name"
349    *
350    * @param methodInfo
351    * @return string representation (see javavadoc)
352    */

353   public static String JavaDoc getAdviceNameAsInSource(final MethodInfo methodInfo) {
354     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(methodInfo.getName());
355     if (methodInfo.getParameterNames() == null
356             || methodInfo.getParameterNames().length != methodInfo.getParameterTypes().length
357             || (methodInfo.getParameterNames().length > 0 && methodInfo.getParameterNames()[0] == null)) {
358       return methodInfo.getName();
359     }
360     if (methodInfo.getParameterNames().length > 0) {
361       buffer.append('(');
362       for (int i = 0; i < methodInfo.getParameterNames().length; i++) {
363         if (i > 0) {
364           buffer.append(", ");
365         }
366         String JavaDoc parameterName = methodInfo.getParameterNames()[i];
367         buffer.append(methodInfo.getParameterTypes()[i].getName());
368         buffer.append(' ').append(parameterName);
369       }
370       buffer.append(')');
371     }
372     return buffer.toString();
373   }
374
375   /**
376    * Handles specific syntax for @AfterXXX annotation, where we can write it using the default "value" element
377    * or instead specify the pointcut using "pointcut", and optionally a "type" element.
378    *
379    * @param value
380    * @param pointcut
381    * @return the one of value or expression which is not null. Both cannot be specified at the same time
382    */

383   public static String JavaDoc getExpressionElseValue(String JavaDoc value, String JavaDoc pointcut) {
384     if (!Strings.isNullOrEmpty(pointcut)) {
385       return pointcut;
386     } else if (!Strings.isNullOrEmpty(value)) {
387       return value;
388     } else {
389       throw new DefinitionException("neither expression nor value had a valid value");
390     }
391   }
392
393 }
Popular Tags