KickJava   Java API By Example, From Geeks To Geeks.

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


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 com.thoughtworks.qdox.JavaDocBuilder;
11 import com.thoughtworks.qdox.model.DocletTag;
12 import com.thoughtworks.qdox.model.JavaClass;
13 import com.thoughtworks.qdox.model.JavaField;
14 import com.thoughtworks.qdox.model.JavaMethod;
15
16 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
17 import org.codehaus.aspectwerkz.exception.DefinitionException;
18 import org.codehaus.aspectwerkz.util.Strings;
19 import org.codehaus.aspectwerkz.annotation.expression.AnnotationVisitor;
20 import org.codehaus.aspectwerkz.annotation.expression.ast.ParseException;
21
22 import java.io.File JavaDoc;
23 import java.io.FileNotFoundException JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.ObjectInputStream JavaDoc;
26 import java.io.Serializable JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Collection JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.lang.reflect.Proxy JavaDoc;
34 import java.lang.reflect.InvocationHandler JavaDoc;
35 import java.lang.reflect.Method JavaDoc;
36
37 /**
38  * Parses and retrieves annotations.
39  *
40  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
41  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
42  */

43 public class AnnotationManager {
44
45     private static final String JavaDoc JAVA_LANG_OBJECT_CLASS_NAME = "java.lang.Object";
46
47     /**
48      * The JavaDoc parser.
49      */

50     private final JavaDocBuilder m_parser = new JavaDocBuilder();
51
52     /**
53      * Map with the registered annotations mapped to their interface implementation classes.
54      */

55     private final Map JavaDoc m_registeredAnnotations = new HashMap JavaDoc();
56
57     /**
58      * Constructs a new annotation manager and had the given ClassLoader to the
59      * search path
60      *
61      * @param loader
62      */

63     public AnnotationManager(ClassLoader JavaDoc loader) {
64         m_parser.getClassLibrary().addClassLoader(loader);
65     }
66
67     /**
68      * Adds a source tree to the builder.
69      *
70      * @param srcDirs the source trees
71      */

72     public void addSourceTrees(final String JavaDoc[] srcDirs) {
73         for (int i = 0; i < srcDirs.length; i++) {
74             m_parser.addSourceTree(new File JavaDoc(srcDirs[i]));
75         }
76     }
77
78     /**
79      * Adds a source file.
80      *
81      * @param srcFile the source file
82      */

83     public void addSource(final String JavaDoc srcFile) {
84         try {
85             m_parser.addSource(new File JavaDoc(srcFile));
86         } catch (Exception JavaDoc e) {
87             throw new WrappedRuntimeException(e);
88         }
89     }
90
91     /**
92      * Register an annotation together with its proxy implementation under
93      * a doclet name
94      *
95      * @param proxyClass the proxy class
96      * @param docletName the name of the doclet. The annotation name is the proxy FQN.
97      */

98     public void registerAnnotationProxy(final Class JavaDoc proxyClass, final String JavaDoc docletName) {
99         m_registeredAnnotations.put(docletName, proxyClass);
100     }
101
102     /**
103      * Returns all classes.
104      *
105      * @return an array with all classes
106      */

107     public JavaClass[] getAllClasses() {
108         Collection JavaDoc classes = m_parser.getClassLibrary().all();
109         Collection JavaDoc javaClasses = new ArrayList JavaDoc();
110         String JavaDoc className;
111         for (Iterator JavaDoc it = classes.iterator(); it.hasNext();) {
112             className = (String JavaDoc) it.next();
113             if (JAVA_LANG_OBJECT_CLASS_NAME.equals(className)) {
114                 continue;
115             }
116             JavaClass clazz = m_parser.getClassByName(className);
117             javaClasses.add(clazz);
118         }
119         return (JavaClass[]) javaClasses.toArray(new JavaClass[]{});
120     }
121
122     /**
123      * Returns the annotations with a specific name for a specific class.
124      *
125      * @param name
126      * @param clazz
127      * @return an array with the annotations
128      */

129     public Annotation[] getAnnotations(final String JavaDoc name, final JavaClass clazz) {
130         DocletTag[] tags = clazz.getTags();
131         List JavaDoc annotations = new ArrayList JavaDoc();
132         for (int i = 0; i < tags.length; i++) {
133             DocletTag tag = tags[i];
134             RawAnnotation rawAnnotation = getRawAnnotation(name, tag);
135             if (rawAnnotation != null) {
136                 annotations.add(instantiateAnnotation(rawAnnotation));
137             }
138         }
139         return (Annotation[]) annotations.toArray(new Annotation[]{});
140     }
141
142     /**
143      * Returns the annotations with a specific name for a specific method.
144      *
145      * @param name
146      * @param method
147      * @return an array with the annotations
148      */

149     public Annotation[] getAnnotations(final String JavaDoc name, final JavaMethod method) {
150         DocletTag[] tags = method.getTags();
151         List JavaDoc annotations = new ArrayList JavaDoc();
152         for (int i = 0; i < tags.length; i++) {
153             DocletTag tag = tags[i];
154             RawAnnotation rawAnnotation = getRawAnnotation(name, tag);
155             if (rawAnnotation != null) {
156                 annotations.add(instantiateAnnotation(rawAnnotation));
157             }
158         }
159         return (Annotation[]) annotations.toArray(new Annotation[]{});
160     }
161
162     /**
163      * Returns the annotations with a specific name for a specific field.
164      *
165      * @param name
166      * @param field
167      * @return an array with the annotations
168      */

169     public Annotation[] getAnnotations(final String JavaDoc name, final JavaField field) {
170         DocletTag[] tags = field.getTags();
171         List JavaDoc annotations = new ArrayList JavaDoc();
172         for (int i = 0; i < tags.length; i++) {
173             DocletTag tag = tags[i];
174             RawAnnotation rawAnnotation = getRawAnnotation(name, tag);
175             if (rawAnnotation != null) {
176                 annotations.add(instantiateAnnotation(rawAnnotation));
177             }
178         }
179         return (Annotation[]) annotations.toArray(new Annotation[]{});
180     }
181
182
183     /**
184      * Instantiate the given annotation based on its name, and initialize it by passing the given value (may be parsed
185      * or not, depends on type/untyped)
186      *
187      * @param rawAnnotation
188      * @return
189      */

190     private Annotation instantiateAnnotation(final RawAnnotation rawAnnotation) {
191         final Class JavaDoc proxyClass = (Class JavaDoc) m_registeredAnnotations.get(rawAnnotation.name);
192
193         if (!proxyClass.isInterface()) {
194             throw new RuntimeException JavaDoc("Annotation class is not defined as an interface for " + rawAnnotation.name
195                 + ". Use of AspectWerkz 1.x Annotation proxies is not anymore supported.");
196         }
197
198         try {
199             InvocationHandler JavaDoc handler = new Java14AnnotationInvocationHander(
200                     proxyClass, rawAnnotation.name, rawAnnotation.value
201             );
202             Object JavaDoc annotationProxy = Proxy.newProxyInstance(
203                     proxyClass.getClassLoader(), new Class JavaDoc[]{Annotation.class, proxyClass}, handler
204             );
205             return (Annotation) annotationProxy;
206         } catch (Throwable JavaDoc e) {
207             throw new DefinitionException(
208                     "Unable to parse annotation @" + rawAnnotation.name + '(' +
209                     " " + rawAnnotation.value + ')', e
210             );
211         }
212     }
213
214     /**
215      * Instantiate an annotation given its interface and elements
216      * It is used only for nested annotation hence requires typed annotation
217      * without nicknames.
218      *
219      * TODO: Note: should we support nicked name nested ?
220      * If so grammar needs to track annotation name
221      *
222      * @return
223      */

224     public static Annotation instantiateNestedAnnotation(final Class JavaDoc annotationClass, final Map JavaDoc elements) {
225         if (!annotationClass.isInterface()) {
226             throw new RuntimeException JavaDoc("Annotation class is not defined as an interface for " + annotationClass.getName()
227                 + ". Use of AspectWerkz 1.x Annotation proxies is not anymore supported.");
228         }
229
230         try {
231             InvocationHandler JavaDoc handler = new Java14AnnotationInvocationHander(
232                     annotationClass, elements
233             );
234             Object JavaDoc annotationProxy = Proxy.newProxyInstance(
235                     annotationClass.getClassLoader(), new Class JavaDoc[]{Annotation.class, annotationClass}, handler
236             );
237             return (Annotation) annotationProxy;
238         } catch (Throwable JavaDoc e) {
239             throw new DefinitionException(
240                     "Unable to parse nested annotation @" + annotationClass.getName(), e
241             );
242         }
243     }
244
245     /**
246      * Extract the raw information (name + unparsed value without optional parenthesis) from a Qdox doclet Note:
247      * StringBuffer.append(null<string>) sucks and produce "null" string..
248      * Note: when using untyped annotation, then the first space character(s) in the value part will be
249      * resumed to only one space (untyped type -> untyped type), due to QDox doclet handling.
250      *
251      * @param annotationName
252      * @param tag
253      * @return RawAnnotation or null if not found
254      */

255     private RawAnnotation getRawAnnotation(String JavaDoc annotationName, DocletTag tag) {
256         String JavaDoc asIs = tag.getName() + " " + tag.getValue();
257         asIs = asIs.trim();
258         Strings.removeFormattingCharacters(asIs);
259
260         // filter out if annotationName cannot be found
261
if (!asIs.startsWith(annotationName)) {
262             return null;
263         }
264
265         String JavaDoc name = null;
266         String JavaDoc value = null;
267
268         // try untyped split
269
if (asIs.indexOf(' ') > 0) {
270             name = asIs.substring(0, asIs.indexOf(' '));
271         }
272         if (annotationName.equals(name)) {
273             // untyped
274
value = asIs.substring(asIs.indexOf(' ') + 1, asIs.length());
275             if (value.startsWith("(") && value.endsWith(")")) {
276                 if (value.length() > 2) {
277                     value = value.substring(1, value.length()-1);
278                 } else {
279                     value = "";
280                 }
281             }
282         } else {
283             // try typed split
284
if (asIs.indexOf('(') > 0) {
285                 name = asIs.substring(0, asIs.indexOf('('));
286             }
287             if (annotationName.equals(name)) {
288                 value = asIs.substring(asIs.indexOf('(') + 1, asIs.length());
289                 if (value.endsWith(")")) {
290                     if (value.length() > 1) {
291                         value = value.substring(0, value.length() - 1);
292                     } else {
293                         value = "";
294                     }
295                 }
296             } else if (annotationName.equals(asIs)) {
297                 value = "";
298             }
299         }
300
301         // found one
302
if (value != null) {
303             RawAnnotation annotation = new RawAnnotation();
304             annotation.name = annotationName;
305             annotation.value = value;
306             return annotation;
307         } else {
308             return null;
309         }
310     }
311
312     /**
313      * Raw info about an annotation: Do(foo) ==> Do + foo [unless untyped then ==> Do(foo) + null Do foo ==> Do + foo
314      * etc
315      */

316     private static class RawAnnotation implements Serializable JavaDoc {
317         String JavaDoc name;
318         String JavaDoc value;
319     }
320 }
Popular Tags