KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > deployment > annotation > impl > AnnotationProcessorImpl


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.enterprise.deployment.annotation.impl;
24
25 import java.util.EmptyStackException JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.Stack JavaDoc;
33 import java.lang.annotation.Annotation JavaDoc;
34 import java.lang.annotation.ElementType JavaDoc;
35 import java.lang.reflect.AnnotatedElement JavaDoc;
36 import java.lang.reflect.Field JavaDoc;
37 import java.lang.reflect.Method JavaDoc;
38 import java.lang.reflect.Constructor JavaDoc;
39 import java.util.logging.Logger JavaDoc;
40
41 import com.sun.enterprise.deployment.annotation.ProcessingContext;
42 import com.sun.enterprise.deployment.annotation.AnnotationProcessor;
43 import com.sun.enterprise.deployment.annotation.AnnotationInfo;
44 import com.sun.enterprise.deployment.annotation.AnnotationProcessorException;
45 import com.sun.enterprise.deployment.annotation.AnnotationHandler;
46 import com.sun.enterprise.deployment.annotation.AnnotatedElementHandler;
47 import com.sun.enterprise.deployment.annotation.ComponentInfo;
48 import com.sun.enterprise.deployment.annotation.ResultType;
49 import com.sun.enterprise.deployment.annotation.HandlerProcessingResult;
50 import com.sun.enterprise.deployment.annotation.ProcessingResult;
51 import com.sun.enterprise.deployment.annotation.Scanner;
52 import java.util.logging.Level JavaDoc;
53
54
55 /**
56  *
57  * @author dochez
58  */

59 public class AnnotationProcessorImpl implements AnnotationProcessor {
60     
61     AnnotationProcessorImpl delegate;
62     Map JavaDoc<Class JavaDoc<? extends Annotation JavaDoc>, List JavaDoc<AnnotationHandler>> handlers =
63             new HashMap JavaDoc<Class JavaDoc<? extends Annotation JavaDoc>, List JavaDoc<AnnotationHandler>>();
64     
65     int errorCount;
66     Logger JavaDoc logger;
67     Stack JavaDoc<StackElement> annotatedElements = new Stack JavaDoc<StackElement>();
68     Set JavaDoc<Package JavaDoc> visitedPackages = new HashSet JavaDoc<Package JavaDoc>();
69     
70     /** Creates a new instance of AnnotationProcessorImpl */
71     public AnnotationProcessorImpl() {
72         logger = AnnotationUtils.getLogger();
73     }
74     
75     public void setDelegate(AnnotationProcessorImpl delegate) {
76         this.delegate = delegate;
77     }
78     public ProcessingContext createContext() {
79         ProcessingContext ctx = new ProcessingContextImpl(this);
80         ctx.setErrorHandler(new DefaultErrorHandler());
81         return ctx;
82     }
83     
84     /**
85      * Log a message on the default logger
86      */

87     public void log(Level JavaDoc level, AnnotationInfo locator, String JavaDoc localizedMessage){
88         if (logger!=null && logger.isLoggable(level)){
89             if (locator!=null){
90                 logger.log(level, AnnotationUtils.getLocalString(
91                     "enterprise.deployment.annotation.error",
92                     "{2}\n symbol: {0}\n location: {1}",
93                     new Object JavaDoc[] { locator.getAnnotation().annotationType().getName(), locator.getAnnotatedElement(), localizedMessage}));
94             } else{
95                 logger.log(level, localizedMessage);
96             }
97         }
98     }
99     
100     /**
101      * Starts the annotation processing tool passing the processing context which
102      * encapuslate all information necessary for the configuration of the tool.
103      * @param ctx is the initialized processing context
104      * @return the result of the annoations processing
105      */

106     public ProcessingResult process(ProcessingContext ctx)
107         throws AnnotationProcessorException
108     {
109         
110         Scanner scanner = ctx.getProcessingInput();
111         ProcessingResultImpl result = new ProcessingResultImpl();
112         errorCount=0;
113         
114         for (Class JavaDoc c : scanner.getElements()) {
115             
116             result.add(process(ctx, c));
117         }
118         return result;
119     }
120     
121     /**
122      * Process a set of classes from the parameter list rather than from the
123      * processing context. This allow the annotation handlers to call be the
124      * annotation processing tool when classes need to be processed in a
125      * particular context rather than when they are picked up by the scanner.
126      *
127      * @param the processing context
128      * @param the list of classes to process
129      * @return the processing result for such classes
130      * @throws AnnotationProcessorException if handlers fail to process
131      * an annotation
132      */

133     public ProcessingResult process(ProcessingContext ctx, Class JavaDoc[] classes)
134         throws AnnotationProcessorException {
135         
136         ProcessingResultImpl result = new ProcessingResultImpl();
137         for (Class JavaDoc c : classes) {
138             result.add(process(ctx, c));
139         }
140         return result;
141     }
142     
143     private ProcessingResult process(ProcessingContext ctx, Class JavaDoc c)
144         throws AnnotationProcessorException {
145         
146         Scanner scanner = ctx.getProcessingInput();
147         ProcessingResultImpl result = new ProcessingResultImpl();
148         
149         // let's see first if this package is new to us and annotated.
150
Package JavaDoc classPackage = c.getPackage();
151         if (classPackage != null && visitedPackages.add(classPackage)) {
152             // new package
153
result.add(classPackage,
154                     processAnnotations(ctx, ElementType.PACKAGE, classPackage));
155         }
156
157         ComponentInfo info = null;
158         try {
159             info = scanner.getComponentInfo(c);
160         } catch (NoClassDefFoundError JavaDoc err) {
161             // issue 456: allow verifier to report this issue
162
AnnotationProcessorException ape =
163                     new AnnotationProcessorException(
164                             AnnotationUtils.getLocalString(
165                                     "enterprise.deployment.annotation.classnotfounderror",
166                                     "Class [ {0} ] not found. Error while loading [ {1} ]",
167                                     new Object JavaDoc[]{err.getMessage(), c}));
168             ctx.getErrorHandler().error(ape);
169             throw err;
170         }
171
172         // process the class itself.
173
AnnotatedElementHandler handler= ctx.getHandler();
174         logStart(handler, ElementType.TYPE,c);
175         result.add(c, processAnnotations(ctx, c));
176         
177         // now dive into the fields.
178
for (Field JavaDoc field : info.getFields()) {
179             result.add(field,processAnnotations(ctx, ElementType.FIELD, field));
180         }
181         
182         // constructors...
183
for (Constructor JavaDoc constructor : info.getConstructors()) {
184             logStart(ctx.getHandler(), ElementType.CONSTRUCTOR, constructor);
185             result.add(constructor, processAnnotations(ctx, constructor));
186             
187             // parameters
188
processParameters(ctx, constructor.getParameterAnnotations());
189             
190             logEnd(ctx.getHandler(), ElementType.CONSTRUCTOR, constructor);
191             
192         }
193         
194         // methods...
195
for (Method JavaDoc method : info.getMethods()) {
196             logStart(ctx.getHandler(), ElementType.METHOD, method);
197             result.add(method, processAnnotations(ctx, method));
198             
199             // parameters
200
processParameters(ctx, method.getParameterAnnotations());
201             
202             logEnd(ctx.getHandler(), ElementType.METHOD, method);
203         }
204         
205         // Because of annotation inheritance, we need to to travel to
206
// the superclasses to ensure that annotations defined at the
207
// TYPE level are processed at this component level.
208
// Note : so far, I am ignoring the implemented interfaces
209
Class JavaDoc currentClass = c.getSuperclass();
210         while (currentClass!=null && !currentClass.equals(Object JavaDoc.class)) {
211             // the trick is to add the results for this class, not
212
// for the ones they are defined in...
213
result.add(c, processAnnotations(ctx, currentClass));
214             currentClass = currentClass.getSuperclass();
215         }
216         
217         // end of class processing, we need to get the top handler
218
// since it may have changed during the annotation processing
219
logEnd(ctx.getHandler(), ElementType.TYPE, c);
220         
221         return result;
222     }
223     
224     private HandlerProcessingResult processParameters(ProcessingContext ctx, Annotation JavaDoc[][] parametersAnnotations)
225     throws AnnotationProcessorException
226     {
227
228         HandlerProcessingResultImpl result = new HandlerProcessingResultImpl();
229         
230         // process the method parameters...
231
for (Annotation JavaDoc[] parameterAnnotations : parametersAnnotations) {
232             logStart(ctx.getHandler(), ElementType.PARAMETER, null);
233             if (parameterAnnotations!=null) {
234                 for (Annotation JavaDoc annotation : parameterAnnotations) {
235                     AnnotationInfo info = new AnnotationInfo(ctx, null, annotation, ElementType.PARAMETER);
236                     process(ctx, info, result);
237                     dumpProcessingResult(result);
238                 }
239             }
240             logEnd(ctx.getHandler(), ElementType.PARAMETER, null);
241         }
242         return result;
243     }
244     
245     private HandlerProcessingResult processAnnotations(ProcessingContext ctx, ElementType JavaDoc type, AnnotatedElement JavaDoc element)
246         throws AnnotationProcessorException
247     {
248         
249         AnnotatedElementHandler handler = ctx.getHandler();
250         logStart(handler, type, element);
251         HandlerProcessingResult result = processAnnotations(ctx, element);
252         logEnd(handler, type, element);
253
254         dumpProcessingResult(result);
255         
256         return result;
257     }
258     
259     private HandlerProcessingResult processAnnotations(ProcessingContext ctx, AnnotatedElement JavaDoc element)
260         throws AnnotationProcessorException
261     {
262     
263         HandlerProcessingResultImpl result= new HandlerProcessingResultImpl();
264         
265         for (Annotation JavaDoc annotation : element.getAnnotations()) {
266             // initialize the result...
267
AnnotationInfo subElement = new AnnotationInfo(ctx, element, annotation, getTopElementType());
268             if (!result.processedAnnotations().containsKey(annotation.annotationType())) {
269                 process(ctx, subElement, result);
270             } else {
271                 if (AnnotationUtils.shouldLog("annotation")) {
272                     logger.finer("Annotation " + annotation.annotationType() + " already processed");
273                 }
274             }
275         }
276         return result;
277     }
278     
279     private void process(ProcessingContext ctx, AnnotationInfo element, HandlerProcessingResultImpl result)
280         throws AnnotationProcessorException
281     {
282         
283         
284         Annotation JavaDoc annotation = element.getAnnotation();
285         if (AnnotationUtils.shouldLog("annotation")) {
286             logger.finer("Annotation : " + annotation.annotationType().getName() + " delegate = " + delegate);
287         }
288         result.addResult(annotation.annotationType(), ResultType.UNPROCESSED);
289         
290         // we ignore all java.* annotations
291
Package JavaDoc annPackage = annotation.annotationType().getPackage();
292         if (annPackage != null && annPackage.getName().startsWith("java.lang"))
293             return;
294         
295         List JavaDoc<AnnotationHandler> annotationHandlers = handlers.get(annotation.annotationType());
296         if (annotationHandlers!=null) {
297             for (AnnotationHandler handler : annotationHandlers) {
298                 
299                 // here we need to be careful, we are ready to invoke a handler
300
// to process a particular annotation type. However, this handler
301
// may have defined a list of annotations that should be processed
302
// (if present on the annotated element) before itself.
303
// do this check and process those annotations first.
304
Class JavaDoc<? extends Annotation JavaDoc>[] dependencies = handler.getTypeDependencies();
305                 if (dependencies!=null) {
306                     AnnotatedElement JavaDoc ae = element.getAnnotatedElement();
307                     for (Class JavaDoc<? extends Annotation JavaDoc> annotationType : dependencies) {
308                         Annotation JavaDoc depAnnotation = ae.getAnnotation(annotationType);
309                         if (depAnnotation!=null) {
310                             ResultType resultType = result.processedAnnotations().get(annotationType);
311                             if (resultType==null || resultType==ResultType.UNPROCESSED){
312                                 // annotation is present, process it.
313
AnnotationInfo info = new AnnotationInfo(ctx, ae, depAnnotation, getTopElementType());
314                                 process(ctx, info, result);
315                             }
316                         }
317                     }
318                 }
319                 
320                 // at this point, all annotation that I declared depending on
321
// are processed
322
HandlerProcessingResult processingResult = null;
323                 try {
324                     processingResult = handler.processAnnotation(element);
325                 } catch(AnnotationProcessorException ape) {
326                     // I am logging this exception
327
log(Level.SEVERE, ape.getLocator(), ape.getMessage());
328                     
329                     // I am not throwing the exception unless it is fatal so annotation
330
// processing can continue and we have a chance to report all
331
// errors.
332
if (ape.isFatal()) {
333                         throw ape;
334                     }
335                     
336                     if (++errorCount>100){
337                         throw new AnnotationProcessorException(
338                                 AnnotationUtils.getLocalString(
339                                     "enterprise.deployment.annotation.toomanyerror",
340                                     "Too many errors, annotation processing abandoned."));
341                     }
342                     
343                     processingResult =
344                         HandlerProcessingResultImpl.getDefaultResult(
345                         annotation.annotationType(), ResultType.FAILED);
346                 } catch(Throwable JavaDoc e){
347                     AnnotationProcessorException ape = new AnnotationProcessorException(e.getMessage(), element);
348                     ape.initCause(e);
349                     throw ape;
350                 }
351                 result.addAll(processingResult);
352             }
353         } else {
354             if (delegate!=null) {
355                 delegate.process(ctx, element, result);
356             } else {
357                 ctx.getErrorHandler().fine(
358                         new AnnotationProcessorException("No handler defined for "
359                             + annotation.annotationType()));
360             }
361         }
362     }
363     
364     private void dumpProcessingResult(HandlerProcessingResult result) {
365
366         if (result==null || !AnnotationUtils.shouldLog("annotation")) {
367             return;
368         }
369    
370         Map JavaDoc<Class JavaDoc<? extends Annotation JavaDoc>, ResultType> annotationResults =
371                 result.processedAnnotations();
372         for (Class JavaDoc annotationType : annotationResults.keySet()) {
373             logger.finer("Annotation " + annotationType + " : " +
374                     annotationResults.get(annotationType));
375         }
376     }
377     public void pushAnnotationHandler(AnnotationHandler handler) {
378         
379         Class JavaDoc<? extends Annotation JavaDoc> type = handler.getAnnotationType();
380         List JavaDoc<AnnotationHandler> currentHandlers = handlers.get(type);
381         if (currentHandlers==null) {
382             currentHandlers = new ArrayList JavaDoc<AnnotationHandler>();
383             handlers.put(type, currentHandlers);
384         }
385         currentHandlers.add(handler);
386     }
387     
388     public void popAnnotationHandler(Class JavaDoc<? extends Annotation JavaDoc> type) {
389         List JavaDoc<AnnotationHandler> currentHandlers = handlers.get(type);
390         if (currentHandlers!=null) {
391             currentHandlers.remove(currentHandlers.size());
392         }
393     }
394
395     public AnnotationHandler getAnnotationHandler(Class JavaDoc<? extends Annotation JavaDoc> type) {
396         List JavaDoc<AnnotationHandler> currentHandlers = handlers.get(type);
397         if (currentHandlers!=null && currentHandlers.size()>0) {
398             return currentHandlers.get(0);
399         }
400         return null;
401     }
402     
403     /**
404      * @return the last element pushed on the stack which ElementType was
405      * the one passed or null if no stack element is of the given type.
406      */

407     public AnnotatedElement JavaDoc getLastAnnotatedElement(ElementType JavaDoc type) {
408         for (int i=annotatedElements.size();i!=0;i--) {
409             StackElement e = annotatedElements.get(i - 1);
410             if (e.getElementType().equals(type))
411                 return e.getAnnotatedElement();
412         }
413         return null;
414     }
415     
416     public Stack JavaDoc<StackElement> getStack() {
417         return annotatedElements;
418     }
419     
420     private void logStart(AnnotatedElementHandler handler, ElementType JavaDoc type, AnnotatedElement JavaDoc c) throws AnnotationProcessorException {
421         
422         if (AnnotationUtils.shouldLog("types")) {
423             AnnotationUtils.getLogger().finer(type + " START : " + c);
424         }
425         
426         // push it to our annotated element stack
427
annotatedElements.push(new StackElement(type, c));
428         if(delegate!=null) {
429             delegate.getStack().push(new StackElement(type, c));
430         }
431         
432         if (handler!=null) {
433             handler.startElement(type, c);
434         }
435     }
436     
437     private void logEnd(AnnotatedElementHandler handler, ElementType JavaDoc type, AnnotatedElement JavaDoc c) throws AnnotationProcessorException {
438         
439         if (AnnotationUtils.shouldLog("types")) {
440             AnnotationUtils.getLogger().finer(type + " END : " + c);
441         }
442         
443         // pop it from our annotated element stack
444
annotatedElements.pop();
445         if(delegate!=null) {
446             delegate.getStack().pop();
447         }
448         
449         if (handler!=null) {
450             handler.endElement(type, c);
451         }
452     }
453     
454     /**
455      * @return the top annotated elements stack element type
456      */

457     private ElementType JavaDoc getTopElementType() {
458         try {
459             StackElement top = annotatedElements.peek();
460             return top.getElementType();
461         } catch(EmptyStackException JavaDoc ex) {
462             return null;
463         }
464     }
465 }
466
Popular Tags