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
11 import com.thoughtworks.qdox.model.JavaClass;
12 import com.thoughtworks.qdox.model.JavaField;
13 import com.thoughtworks.qdox.model.JavaMethod;
14 import com.thoughtworks.qdox.model.JavaParameter;
15
16 import org.apache.tools.ant.BuildException;
17 import org.codehaus.aspectwerkz.annotation.instrumentation.AttributeEnhancer;
18 import org.codehaus.aspectwerkz.annotation.instrumentation.asm.AsmAttributeEnhancer;
19 import org.codehaus.aspectwerkz.exception.DefinitionException;
20 import org.codehaus.aspectwerkz.joinpoint.JoinPoint;
21 import org.codehaus.aspectwerkz.joinpoint.StaticJoinPoint;
22 import org.codehaus.aspectwerkz.DeploymentModel;
23
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileReader;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.net.MalformedURLException;
31 import java.net.URL;
32 import java.net.URLClassLoader;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Properties;
39 import java.util.StringTokenizer;
40
41 /***
42 * <p/>Annotation compiler. <p/>Extracts the annotations from JavaDoc tags and inserts them into the bytecode of the
43 * class.
44 *
45 * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
46 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
47 */
48 public class AnnotationC {
49 private static final String COMMAND_LINE_OPTION_DASH = "-";
50 private static final String COMMAND_LINE_OPTION_VERBOSE = "-verbose";
51 private static final String COMMAND_LINE_OPTION_CUSTOM = "-custom";
52 private static final String COMMAND_LINE_OPTION_SRC = "-src";
53 private static final String COMMAND_LINE_OPTION_SRCFILES = "-srcfiles";
54 private static final String COMMAND_LINE_OPTION_SRCINCLUDES = "-srcincludes";
55 private static final String COMMAND_LINE_OPTION_CLASSES = "-classes";
56 private static final String COMMAND_LINE_OPTION_DEST = "-dest";
57
58 static final String[] SYSTEM_ANNOTATIONS = new String[]{
59 AnnotationConstants.ASPECT, AnnotationConstants.AROUND, AnnotationConstants.BEFORE,
60 AnnotationConstants.AFTER, AnnotationConstants.AFTER_FINALLY,
61 AnnotationConstants.AFTER_RETURNING, AnnotationConstants.AFTER_THROWING,
62 AnnotationConstants.EXPRESSION, AnnotationConstants.INTRODUCE, AnnotationConstants.MIXIN
63 };
64
65 /***
66 * The annotations properties file define by the user.
67 */
68 public static final Properties ANNOTATION_DEFINITION = new Properties();
69
70 /***
71 * Verbose logging.
72 */
73 private static boolean s_verbose = false;
74
75 /***
76 * The class loader.
77 */
78 private static URLClassLoader s_loader;
79
80 /***
81 * The custom annotations.
82 */
83 private static Map s_customAnnotations = new HashMap();
84 private static final String FILE_SEPARATOR = File.separator;
85
86 /***
87 * Runs the compiler from the command line.
88 *
89 * @param args
90 */
91 public static void main(String[] args) {
92 if (args.length < 4) {
93 printUsage();
94 }
95 Map commandLineOptions = parseCommandLineOptions(args);
96
97 String propertiesFilesPath = (String) commandLineOptions.get(COMMAND_LINE_OPTION_CUSTOM);
98 List propertiesFilesList = new ArrayList();
99 if (propertiesFilesPath != null) {
100 StringTokenizer st = new StringTokenizer(propertiesFilesPath, File.pathSeparator);
101 while (st.hasMoreTokens()) {
102 propertiesFilesList.add(st.nextToken());
103 }
104 }
105 String[] propertiesFiles = (String[]) propertiesFilesList.toArray(new String[0]);
106
107 compile(
108 (String) commandLineOptions.get(COMMAND_LINE_OPTION_SRC),
109 (String) commandLineOptions.get(COMMAND_LINE_OPTION_SRCFILES),
110 (String) commandLineOptions.get(COMMAND_LINE_OPTION_SRCINCLUDES),
111 (String) commandLineOptions.get(COMMAND_LINE_OPTION_CLASSES),
112 (String) commandLineOptions.get(COMMAND_LINE_OPTION_DEST),
113 propertiesFiles
114 );
115 }
116
117 /***
118 * Compiles the annotations.
119 *
120 * @param srcDirList
121 * @param srcFileList
122 * @param classPath
123 * @param destDir
124 * @param annotationPropetiesFiles
125 */
126 private static void compile(final String srcDirList,
127 final String srcFileList,
128 final String srcFileIncludes,
129 final String classPath,
130 String destDir,
131 final String[] annotationPropetiesFiles) {
132 if (srcDirList == null && srcFileList == null && srcFileIncludes == null) {
133 throw new IllegalArgumentException("one of src or srcfiles or srcincludes must be not null");
134 }
135 if ((srcDirList != null && srcFileList != null) ||
136 (srcDirList != null && srcFileIncludes != null) ||
137 (srcFileList != null && srcFileIncludes != null)) {
138 throw new IllegalArgumentException("maximum one of src, srcfiles or srcincludes must be not null");
139 }
140 if (classPath == null) {
141 throw new IllegalArgumentException("class path can not be null");
142 }
143 if (destDir == null) {
144 destDir = classPath;
145 }
146
147 String[] srcDirs = new String[0];
148 String[] srcFiles = new String[0];
149 if (srcDirList != null) {
150 srcDirs = split(srcDirList, File.pathSeparator);
151 } else if (srcFileList != null) {
152 srcFiles = split(srcFileList, FILE_SEPARATOR);
153 } else {
154 srcFiles = loadSourceList(srcFileIncludes);
155 }
156
157 compile(s_verbose, srcDirs, srcFiles, split(classPath, File.pathSeparator), destDir, annotationPropetiesFiles);
158 }
159
160 /***
161 * Compiles the annotations.
162 *
163 * @param verbose
164 * @param srcDirs
165 * @param srcFiles
166 * @param classpath
167 * @param destDir
168 * @param annotationPropertiesFiles
169 */
170 public static void compile(final boolean verbose,
171 final String[] srcDirs,
172 final String[] srcFiles,
173 final String[] classpath,
174 final String destDir,
175 final String[] annotationPropertiesFiles) {
176
177 s_verbose = verbose;
178 URL[] classPath = new URL[classpath.length];
179 try {
180 for (int i = 0; i < classpath.length; i++) {
181 classPath[i] = new File(classpath[i]).toURL();
182 }
183 s_loader = new URLClassLoader(classPath, AnnotationC.class.getClassLoader());
184 } catch (MalformedURLException e) {
185 String message = "URL [" + classPath + "] is not valid: " + e.toString();
186 logError(message);
187 throw new DefinitionException(message, e);
188 }
189
190 String destDirToUse = destDir;
191 if (destDir == null) {
192 if (classpath.length != 1) {
193 throw new DefinitionException("destDir must be specified since classpath is composite");
194 }
195 destDirToUse = classpath[0];
196 }
197
198 final AnnotationManager manager = new AnnotationManager(s_loader);
199
200 logInfo("parsing source dirs:");
201 for (int i = 0; i < srcDirs.length; i++) {
202 logInfo(" " + srcDirs[i]);
203 }
204 manager.addSourceTrees(srcDirs);
205
206 for (int i = 0; i < srcFiles.length; i++) {
207 logInfo(" " + srcFiles[i]);
208 manager.addSource(srcFiles[i]);
209 }
210
211 doCompile(annotationPropertiesFiles, classPath, manager, destDirToUse);
212 }
213
214 /***
215 * Compiles the annotations.
216 *
217 * @param annotationPropetiesFiles
218 * @param classPath
219 * @param manager
220 * @param destDir
221 */
222 private static void doCompile(final String[] annotationPropetiesFiles,
223 final URL[] classPath,
224 final AnnotationManager manager,
225 final String destDir) {
226
227 logInfo("compiling annotations...");
228 logInfo("note: if no output is seen, then nothing is compiled");
229
230
231 registerSystemAnnotations(manager);
232 registerUserDefinedAnnotations(manager, annotationPropetiesFiles);
233
234
235 JavaClass[] classes = manager.getAllClasses();
236 for (int i = 0; i < classes.length; i++) {
237 JavaClass clazz = classes[i];
238 logInfo("class [" + clazz.getFullyQualifiedName() + ']');
239 try {
240 AttributeEnhancer enhancer = new AsmAttributeEnhancer();
241 if (enhancer.initialize(clazz.getFullyQualifiedName(), classPath)) {
242 handleClassAnnotations(manager, enhancer, clazz);
243 handleInnerClassAnnotations(manager, enhancer, clazz);
244 JavaMethod[] methods = clazz.getMethods();
245 for (int j = 0; j < methods.length; j++) {
246 JavaMethod method = methods[j];
247 if (method.isConstructor()) {
248 handleConstructorAnnotations(manager, enhancer, method);
249 } else {
250 handleMethodAnnotations(manager, enhancer, method);
251 }
252 }
253 JavaField[] fields = clazz.getFields();
254 for (int j = 0; j < fields.length; j++) {
255 handleFieldAnnotations(manager, enhancer, fields[j]);
256 }
257
258
259 enhancer.write(destDir);
260 }
261 } catch (Throwable e) {
262 e.printStackTrace();
263 logWarning(
264 "could not compile annotations for class ["
265 + clazz.getFullyQualifiedName() + "] due to: " + e.toString()
266 );
267 }
268 }
269 logInfo("compiled classes written to " + destDir);
270 logInfo("compilation successful");
271 }
272
273 /***
274 * Handles the class annotations.
275 *
276 * @param manager
277 * @param enhancer
278 * @param clazz
279 */
280 private static void handleClassAnnotations(final AnnotationManager manager,
281 final AttributeEnhancer enhancer,
282 final JavaClass clazz) {
283 parseCustomClassAnnotations(clazz, manager, enhancer);
284 parseAspectAnnotations(clazz, manager, enhancer);
285 parseMixinAnnotations(clazz, manager, enhancer);
286 }
287
288 /***
289 * Parses the custom annotations.
290 *
291 * @param clazz
292 * @param manager
293 * @param enhancer
294 */
295 private static void parseCustomClassAnnotations(final JavaClass clazz,
296 final AnnotationManager manager,
297 final AttributeEnhancer enhancer) {
298 for (Iterator it = s_customAnnotations.keySet().iterator(); it.hasNext();) {
299 String annotationName = (String) it.next();
300 Annotation[] customAnnotations = manager.getAnnotations(annotationName, clazz);
301 for (int i = 0; i < customAnnotations.length; i++) {
302 Annotation customAnnotation = customAnnotations[i];
303 if (customAnnotation != null) {
304 enhancer.insertClassAttribute(
305 new AnnotationInfo(
306 annotationName,
307 customAnnotation
308 )
309 );
310 logInfo(
311 " custom class annotation [" + annotationName + " @ "
312 + clazz.getFullyQualifiedName() + ']'
313 );
314 }
315 }
316 }
317 }
318
319 /***
320 * Parses the aspect annotations.
321 *
322 * @param clazz
323 * @param manager
324 * @param enhancer
325 */
326 private static void parseAspectAnnotations(final JavaClass clazz,
327 final AnnotationManager manager,
328 final AttributeEnhancer enhancer) {
329 Annotation[] annotations = manager.getAnnotations(AnnotationConstants.ASPECT, clazz);
330 for (int i = 0; i < annotations.length; i++) {
331 Annotation annotation = annotations[i];
332 if (annotation != null) {
333 enhancer.insertClassAttribute(
334 new AnnotationInfo(AnnotationConstants.ASPECT, annotation)
335 );
336 String name = ((Aspect) annotation).name();
337 if (name == null) {
338 name = clazz.getFullyQualifiedName();
339 }
340 String deploymentModel = ((Aspect) annotation).deploymentModel();
341 if (((Aspect) annotation).value() != null) {
342 deploymentModel = ((Aspect) annotation).value();
343 }
344 logInfo("aspect [" + name + ']');
345 logInfo(" deployment model [" + deploymentModel + ']');
346 }
347 }
348 }
349
350 /***
351 * Parses mixin annotations.
352 *
353 * @param clazz
354 * @param manager
355 * @param enhancer
356 */
357 private static void parseMixinAnnotations(final JavaClass clazz,
358 final AnnotationManager manager,
359 final AttributeEnhancer enhancer) {
360 final Annotation[] introduceAnnotations = manager.getAnnotations(
361 AnnotationConstants.MIXIN_DOCLET, clazz
362 );
363 final String className = clazz.getFullyQualifiedName();
364 for (int k = 0; k < introduceAnnotations.length; k++) {
365 Annotation introduceAnnotation = introduceAnnotations[k];
366 if (introduceAnnotation != null && introduceAnnotation instanceof Mixin) {
367
368 JavaClass[] introducedInterfaceClasses = clazz.getImplementedInterfaces();
369 String[] introducedInterfaceNames = new String[introducedInterfaceClasses.length];
370 for (int j = 0; j < introducedInterfaceClasses.length; j++) {
371 introducedInterfaceNames[j] = introducedInterfaceClasses[j].getFullyQualifiedName();
372 logInfo(" interface introduction [" + introducedInterfaceNames[j] + ']');
373 }
374 if (introducedInterfaceNames.length == 0) {
375 introducedInterfaceNames = enhancer.getNearestInterfacesInHierarchy(className);
376 if (introducedInterfaceNames.length == 0) {
377 throw new RuntimeException("no implicit interfaces found for " + className);
378 }
379 for (int j = 0; j < introducedInterfaceNames.length; j++) {
380 logInfo(" interface introduction [" + introducedInterfaceNames[j] + ']');
381 }
382 }
383 String deploymentModel = DeploymentModel.PER_JVM.toString();
384 if (((Mixin) introduceAnnotation).deploymentModel() != null) {
385 deploymentModel = ((Mixin) introduceAnnotation).deploymentModel();
386 }
387 String expression = ((Mixin) introduceAnnotation).pointcut();
388 if (expression == null) {
389 expression = ((Mixin) introduceAnnotation).value();
390 }
391 logInfo(
392 " mixin introduction [" + clazz.getFullyQualifiedName()
393 + " :: " + expression +
394 "] deployment model ["
395 + deploymentModel + ']'
396 );
397 enhancer.insertClassAttribute(
398 new AnnotationInfo(AnnotationConstants.MIXIN, introduceAnnotation)
399 );
400 }
401 }
402 }
403
404 /***
405 * Handles the method annotations.
406 *
407 * @param manager
408 * @param enhancer
409 * @param method
410 */
411 private static void handleMethodAnnotations(final AnnotationManager manager,
412 final AttributeEnhancer enhancer,
413 final JavaMethod method) {
414
415 Annotation[] expressionAnnotations = manager.getAnnotations(
416 AnnotationConstants.EXPRESSION_DOCLET, method
417 );
418 for (int i = 0; i < expressionAnnotations.length; i++) {
419 Annotation expressionAnnotation = expressionAnnotations[i];
420 if (expressionAnnotation != null && expressionAnnotation instanceof Expression) {
421 enhancer.insertMethodAttribute(
422 method, new AnnotationInfo(
423 AnnotationConstants.EXPRESSION,
424 expressionAnnotation
425 )
426 );
427 logInfo(
428 " pointcut [" + AnnotationC.getShortCallSignature(method) + " :: "
429 + ((Expression) expressionAnnotation).value() + ']'
430 );
431 }
432 }
433 Annotation[] aroundAnnotations = manager.getAnnotations(AnnotationConstants.AROUND_DOCLET, method);
434 for (int i = 0; i < aroundAnnotations.length; i++) {
435 Annotation aroundAnnotation = aroundAnnotations[i];
436 if (aroundAnnotation != null && aroundAnnotation instanceof Around) {
437 enhancer.insertMethodAttribute(
438 method, new AnnotationInfo(
439 AnnotationConstants.AROUND,
440 aroundAnnotation
441 )
442 );
443 logInfo(
444 " around advice [" + AnnotationC.getShortCallSignature(method) + " :: "
445 + ((Around) aroundAnnotation).value() + ']'
446 );
447 }
448 }
449 Annotation[] beforeAnnotations = manager.getAnnotations(AnnotationConstants.BEFORE_DOCLET, method);
450 for (int i = 0; i < beforeAnnotations.length; i++) {
451 Annotation beforeAnnotation = beforeAnnotations[i];
452 if (beforeAnnotation != null && beforeAnnotation instanceof Before) {
453 enhancer.insertMethodAttribute(
454 method, new AnnotationInfo(
455 AnnotationConstants.BEFORE,
456 beforeAnnotation
457 )
458 );
459 logInfo(
460 " before [" + AnnotationC.getShortCallSignature(method) + " :: "
461 + ((Before) beforeAnnotation).value() + ']'
462 );
463 }
464 }
465 Annotation[] afterAnnotations = manager.getAnnotations(AnnotationConstants.AFTER_DOCLET, method);
466 for (int i = 0; i < afterAnnotations.length; i++) {
467 Annotation afterAnnotation = afterAnnotations[i];
468 if (afterAnnotation != null && afterAnnotation instanceof After) {
469 enhancer.insertMethodAttribute(
470 method, new AnnotationInfo(AnnotationConstants.AFTER, afterAnnotation)
471 );
472 logInfo(
473 " after advice [" + AnnotationC.getShortCallSignature(method) + " :: "
474 + ((After) afterAnnotation).value() + ']'
475 );
476 }
477 }
478 Annotation[] afterFinallyAnnotations = manager.getAnnotations(
479 AnnotationConstants.AFTER_FINALLY_DOCLET, method
480 );
481 for (int i = 0; i < afterFinallyAnnotations.length; i++) {
482 Annotation afterAnnotation = afterFinallyAnnotations[i];
483 if (afterAnnotation != null && afterAnnotation instanceof AfterFinally) {
484 enhancer.insertMethodAttribute(
485 method, new AnnotationInfo(AnnotationConstants.AFTER_FINALLY, afterAnnotation)
486 );
487 logInfo(
488 " after finally advice [" + AnnotationC.getShortCallSignature(method) + " :: "
489 + ((AfterFinally) afterAnnotation).value() + ']'
490 );
491 }
492 }
493 Annotation[] afterReturningAnnotations = manager.getAnnotations(
494 AnnotationConstants.AFTER_RETURNING_DOCLET, method
495 );
496 for (int i = 0; i < afterReturningAnnotations.length; i++) {
497 Annotation afterAnnotation = afterReturningAnnotations[i];
498 if (afterAnnotation != null && afterAnnotation instanceof AfterReturning) {
499 enhancer.insertMethodAttribute(
500 method,
501 new AnnotationInfo(AnnotationConstants.AFTER_RETURNING, afterAnnotation)
502 );
503 logInfo(
504 " after returning advice [" + AnnotationC.getShortCallSignature(method) + " :: "
505 +
506 AspectAnnotationParser.getExpressionElseValue(
507 ((AfterReturning) afterAnnotation).value(),
508 ((AfterReturning) afterAnnotation).pointcut()
509 )
510 + " :: " + ((AfterReturning) afterAnnotation).type() + ']'
511 );
512 }
513 }
514 Annotation[] afterThrowingAnnotations = manager.getAnnotations(
515 AnnotationConstants.AFTER_THROWING_DOCLET, method
516 );
517 for (int i = 0; i < afterThrowingAnnotations.length; i++) {
518 Annotation afterAnnotation = afterThrowingAnnotations[i];
519 if (afterAnnotation != null && afterAnnotation instanceof AfterThrowing) {
520 enhancer.insertMethodAttribute(
521 method,
522 new AnnotationInfo(AnnotationConstants.AFTER_THROWING, afterAnnotation)
523 );
524 logInfo(
525 " after throwing advice [" + AnnotationC.getShortCallSignature(method) + " :: "
526 +
527 AspectAnnotationParser.getExpressionElseValue(
528 ((AfterThrowing) afterAnnotation).value(),
529 ((AfterThrowing) afterAnnotation).pointcut()
530 )
531 + " :: " + ((AfterThrowing) afterAnnotation).type() + ']'
532 );
533 }
534 }
535 for (Iterator it = s_customAnnotations.keySet().iterator(); it.hasNext();) {
536 String annotationName = (String) it.next();
537 Annotation[] customAnnotations = manager.getAnnotations(annotationName, method);
538 for (int i = 0; i < customAnnotations.length; i++) {
539 Annotation customAnnotation = customAnnotations[i];
540 if (customAnnotation != null) {
541 enhancer.insertMethodAttribute(method, new AnnotationInfo(
542 annotationName,
543 customAnnotation)
544 );
545 logInfo(
546 " custom method annotation [" + annotationName + " @ "
547 + method.getParentClass().getName() + '.' + method.getName() +
548 ']'
549 );
550 }
551 }
552 }
553 }
554
555 /***
556 * Handles the constructor annotations.
557 *
558 * @param manager
559 * @param enhancer
560 * @param constructor
561 */
562 private static void handleConstructorAnnotations(final AnnotationManager manager,
563 final AttributeEnhancer enhancer,
564 final JavaMethod constructor) {
565 for (Iterator it = s_customAnnotations.keySet().iterator(); it.hasNext();) {
566 String annotationName = (String) it.next();
567 Annotation[] customAnnotations = manager.getAnnotations(annotationName, constructor);
568 for (int i = 0; i < customAnnotations.length; i++) {
569 Annotation customAnnotation = customAnnotations[i];
570 if (customAnnotation != null) {
571 enhancer.insertConstructorAttribute(
572 constructor, new AnnotationInfo(annotationName,
573 customAnnotation)
574 );
575 logInfo(
576 " custom constructor annotation [" + annotationName + " @ "
577 + constructor.getParentClass().getName() + '.' +
578 constructor.getName()
579 + ']'
580 );
581 }
582 }
583 }
584 }
585
586 /***
587 * Handles the field annotations.
588 *
589 * @param manager
590 * @param enhancer
591 * @param field
592 */
593 private static void handleFieldAnnotations(final AnnotationManager manager,
594 final AttributeEnhancer enhancer,
595 final JavaField field) {
596
597 Annotation[] expressionAnnotations = manager.getAnnotations(
598 AnnotationConstants.EXPRESSION_DOCLET, field
599 );
600 for (int i = 0; i < expressionAnnotations.length; i++) {
601 Annotation expressionAnnotation = expressionAnnotations[i];
602 if (expressionAnnotation != null && expressionAnnotation instanceof Expression) {
603 enhancer.insertFieldAttribute(
604 field, new AnnotationInfo(
605 AnnotationConstants.EXPRESSION,
606 expressionAnnotation
607 )
608 );
609 logInfo(
610 " pointcut [" + field.getName() + " :: " + ((Expression) expressionAnnotation).value()
611 + ']'
612 );
613 }
614 }
615 Annotation[] introduceAnnotations = manager.getAnnotations(
616 AnnotationConstants.INTRODUCE_DOCLET, field
617 );
618 for (int i = 0; i < introduceAnnotations.length; i++) {
619 Annotation introduceAnnotation = introduceAnnotations[i];
620 if (introduceAnnotation != null && introduceAnnotation instanceof Introduce) {
621 enhancer.insertFieldAttribute(
622 field, new AnnotationInfo(
623 AnnotationConstants.INTRODUCE,
624 introduceAnnotation
625 )
626 );
627 logInfo(
628 " interface introduction [" + field.getName() + " :: "
629 + ((Introduce) introduceAnnotation).value() + ']'
630 );
631 }
632 }
633 for (Iterator it = s_customAnnotations.keySet().iterator(); it.hasNext();) {
634 String annotationName = (String) it.next();
635 Annotation[] customAnnotations = manager.getAnnotations(annotationName, field);
636 for (int i = 0; i < customAnnotations.length; i++) {
637 Annotation customAnnotation = customAnnotations[i];
638 if (customAnnotation != null) {
639 enhancer.insertFieldAttribute(
640 field, new AnnotationInfo(
641 annotationName,
642 customAnnotation
643 )
644 );
645 logInfo(
646 " custom field annotation [" + annotationName + " @ "
647 + field.getName() + ']'
648 );
649 }
650 }
651 }
652 }
653
654 /***
655 * Handles the inner class annotations.
656 *
657 * @param manager
658 * @param enhancer
659 * @param clazz
660 */
661 private static void handleInnerClassAnnotations(final AnnotationManager manager,
662 final AttributeEnhancer enhancer,
663 final JavaClass clazz) {
664 JavaClass[] innerClasses = clazz.getInnerClasses();
665 for (int i = 0; i < innerClasses.length; i++) {
666 parseMixinAnnotations(innerClasses[i], manager, enhancer);
667 }
668 }
669
670 /***
671 * Registers the system annotations.
672 *
673 * @param manager the annotations manager
674 */
675 private static void registerSystemAnnotations(final AnnotationManager manager) {
676 manager.registerAnnotationProxy(Aspect.class, AnnotationConstants.ASPECT_DOCLET);
677 manager.registerAnnotationProxy(Around.class, AnnotationConstants.AROUND_DOCLET);
678 manager.registerAnnotationProxy(Before.class, AnnotationConstants.BEFORE_DOCLET);
679 manager.registerAnnotationProxy(After.class, AnnotationConstants.AFTER_DOCLET);
680 manager.registerAnnotationProxy(AfterReturning.class, AnnotationConstants.AFTER_RETURNING_DOCLET);
681 manager.registerAnnotationProxy(AfterThrowing.class, AnnotationConstants.AFTER_THROWING_DOCLET);
682 manager.registerAnnotationProxy(AfterFinally.class, AnnotationConstants.AFTER_FINALLY_DOCLET);
683 manager.registerAnnotationProxy(Expression.class, AnnotationConstants.EXPRESSION_DOCLET);
684 manager.registerAnnotationProxy(Introduce.class, AnnotationConstants.INTRODUCE_DOCLET);
685 manager.registerAnnotationProxy(Mixin.class, AnnotationConstants.MIXIN_DOCLET);
686 }
687
688 /***
689 * Registers the user defined annotations.
690 *
691 * @param manager the annotations manager
692 * @param propertiesFiles
693 */
694 private static void registerUserDefinedAnnotations(final AnnotationManager manager,
695 final String[] propertiesFiles) {
696 if (propertiesFiles == null) {
697 return;
698 }
699 InputStream in = null;
700 for (int i = 0; i < propertiesFiles.length; i++) {
701 String propertiesFile = propertiesFiles[i];
702 try {
703 in = new FileInputStream(propertiesFile);
704 ANNOTATION_DEFINITION.load(in);
705 } catch (Exception e) {
706 String message = "custom annotation properties " + propertiesFile + " can not be loaded: " +
707 e.toString();
708 logWarning(message);
709 throw new DefinitionException(message);
710 } finally {
711 try {
712 in.close();
713 } catch (Exception e) {
714 ;
715 }
716 }
717 }
718
719 for (Iterator it = ANNOTATION_DEFINITION.entrySet().iterator(); it.hasNext();) {
720 Map.Entry entry = (Map.Entry) it.next();
721 String name = ((String) entry.getKey()).trim();
722 String className = ((String) entry.getValue()).trim();
723 Class klass;
724 if (className.equals("")) {
725
726 klass = UntypedAnnotation.class;
727 className = klass.getName();
728 } else {
729 try {
730 klass = Class.forName(className, false, s_loader);
731 } catch (ClassNotFoundException e) {
732 String message = className
733 +
734 " could not be found on system classpath or class path provided as argument to the compiler";
735 logError(message);
736 throw new DefinitionException(message);
737 }
738 }
739 logInfo("register custom annotation [" + name + " :: " + className + ']');
740 manager.registerAnnotationProxy(klass, name);
741 s_customAnnotations.put(name, className);
742 }
743 }
744
745 /***
746 * Prints the usage.
747 */
748 private static void printUsage() {
749 System.out.println("AspectWerkz (c) 2002-2005 Jonas BonŽr, Alexandre Vasseur");
750 System.out.println(
751 "usage: java [options...] org.codehaus.aspectwerkz.annotation.AnnotationC [-verbose] -src <path to src dir> | -srcfiles <list of files> | -srcincludes <path to file> -classes <path to classes dir> [-dest <path to destination dir>] [-custom <property file for custom annotations>]"
752 );
753 System.out.println(
754 " -src <path to src dir> provides the list of source directories separated by File.pathSeparator"
755 );
756 System.out.println(" -srcpath <list of files> provides a comma separated list of source files");
757 System.out.println(
758 " -srcincludes <path to file> provides the path to a file containing the list of source files (one name per line)"
759 );
760 System.out.println(
761 " -dest <path to destination dir> is optional, if omitted the compiled classes will be written to the initial directory"
762 );
763 System.out.println(
764 " -custom <property file for cutom annotations> is optional, only needed if you have custom annotations you want to compile"
765 );
766 System.out.println(" -verbose activates compilation status information");
767 System.out.println("");
768 System.out.println("Note: only one of -src -srcpath and -srcincludes may be used");
769
770 System.exit(0);
771 }
772
773 /***
774 * Parses the command line options.
775 *
776 * @param args the arguments
777 * @return a map with the options
778 */
779 private static Map parseCommandLineOptions(final String[] args) {
780 final Map arguments = new HashMap();
781 try {
782 for (int i = 0; i < args.length; i++) {
783 if (args[i].equals(COMMAND_LINE_OPTION_VERBOSE)) {
784 s_verbose = true;
785 } else if (args[i].startsWith(COMMAND_LINE_OPTION_DASH)) {
786 String option = args[i++];
787 String value = args[i];
788 arguments.put(option, value);
789 }
790 }
791 } catch (Exception e) {
792 logError("options list to compiler is not valid");
793 System.exit(1);
794 }
795 return arguments;
796 }
797
798 /***
799 * Logs an INFO message.
800 *
801 * @param message the message
802 */
803 private static void logInfo(final String message) {
804 if (s_verbose) {
805 System.out.println("AnnotationC::INFO - " + message);
806 }
807 }
808
809 /***
810 * Logs an ERROR message.
811 *
812 * @param message the message
813 */
814 private static void logError(final String message) {
815 if (s_verbose) {
816 System.err.println("AnnotationC::ERROR - " + message);
817 }
818 }
819
820 /***
821 * Logs an WARNING message.
822 *
823 * @param message the message
824 */
825 private static void logWarning(final String message) {
826 if (s_verbose) {
827 System.err.println("AnnotationC::WARNING - " + message);
828 }
829 }
830
831 /***
832 * Helper method to get a pretty printable method signature (no FQN class names)
833 *
834 * @param method
835 * @return
836 */
837 private static String getShortCallSignature(final JavaMethod method) {
838 StringBuffer buffer = new StringBuffer(method.getName());
839 buffer.append("(");
840 for (int i = 0; i < method.getParameters().length; i++) {
841 JavaParameter javaParameter = method.getParameters()[i];
842 if (javaParameter.getType().toString().equals(JoinPoint.class.getName())) {
843 buffer.append("JoinPoint");
844 } else if (javaParameter.getType().toString().equals(StaticJoinPoint.class.getName())) {
845 buffer.append("StaticJoinPoint");
846 } else {
847 buffer.append(javaParameter.getType().toString());
848 buffer.append(" ");
849 buffer.append(javaParameter.getName());
850 }
851 if (i + 1 < method.getParameters().length) {
852 buffer.append(", ");
853 }
854 }
855 buffer.append(")");
856 return buffer.toString();
857 }
858
859 private static String[] split(String str, String sep) {
860 if (str == null || str.length() == 0) {
861 return new String[0];
862 }
863
864 int start = 0;
865 int idx = str.indexOf(sep, start);
866 int len = sep.length();
867 List strings = new ArrayList();
868
869 while (idx != -1) {
870 strings.add(str.substring(start, idx));
871 start = idx + len;
872 idx = str.indexOf(sep, start);
873 }
874
875 strings.add(str.substring(start));
876
877 return (String[]) strings.toArray(new String[strings.size()]);
878 }
879
880 /***
881 * Load and solve relative to working directory the list of files.
882 *
883 * @param srcIncludes
884 * @return
885 */
886 private static String[] loadSourceList(final String srcIncludes) {
887 File currentDir = new File(".");
888 List files = new ArrayList();
889 BufferedReader reader = null;
890
891 try {
892 reader = new BufferedReader(new FileReader(srcIncludes));
893
894 String line = reader.readLine();
895 File tmpFile = null;
896 while (line != null) {
897 if (line.length() > 0) {
898 tmpFile = new File(currentDir, line);
899 if (!tmpFile.isFile()) {
900 logWarning("file not found: [" + tmpFile + "]");
901 } else {
902 files.add(tmpFile.getAbsolutePath());
903 }
904 }
905 line = reader.readLine();
906 }
907 } catch (IOException ioe) {
908 throw new BuildException(
909 "an error occured while reading from pattern file: "
910 + srcIncludes, ioe
911 );
912 } finally {
913 if (null != reader) {
914 try {
915 reader.close();
916 } catch (IOException ioe) {
917
918 }
919 }
920 }
921
922 return (String[]) files.toArray(new String[files.size()]);
923 }
924
925 }