View Javadoc

    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)) { // FIXME: refactor
    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         // register annotations
    231         registerSystemAnnotations(manager);
    232         registerUserDefinedAnnotations(manager, annotationPropetiesFiles);
    233
    234         // get all the classes
    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                     // write enhanced class to disk
    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                 //directly implemented interfaces
    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         // Pointcut with signature
    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                 // use default untyped annotation
    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                     //Ignore exception
    918                 }
    919             }
    920         }
    921
    922         return (String[]) files.toArray(new String[files.size()]);
    923     }
    924
    925 }