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