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.transform.inlining.weaver;
    9
    10  import java.util.Iterator;
    11  import java.util.Set;
    12  import java.util.HashSet;
    13  import java.util.List;
    14
    15  import org.objectweb.asm.*;
    16  import org.codehaus.aspectwerkz.transform.Context;
    17  import org.codehaus.aspectwerkz.transform.TransformationConstants;
    18  import org.codehaus.aspectwerkz.transform.TransformationUtil;
    19  import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
    20  import org.codehaus.aspectwerkz.definition.SystemDefinition;
    21  import org.codehaus.aspectwerkz.definition.InterfaceIntroductionDefinition;
    22  import org.codehaus.aspectwerkz.definition.MixinDefinition;
    23  import org.codehaus.aspectwerkz.expression.ExpressionContext;
    24  import org.codehaus.aspectwerkz.expression.PointcutType;
    25  import org.codehaus.aspectwerkz.reflect.ClassInfo;
    26  import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
    27
    28  /***
    29   * Adds an interface to the target class.
    30   *
    31   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    32   * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
    33   */
    34  public class AddInterfaceVisitor extends ClassAdapter implements TransformationConstants {
    35
    36      private final static String ADVISABLE_MIXIN_IMPL_NAME = "org.codehaus.aspectwerkz.intercept.AdvisableImpl";
    37
    38      private final ContextImpl m_ctx;
    39      private final ClassInfo m_classInfo;
    40
    41      /***
    42       * Creates a new add interface class adapter.
    43       *
    44       * @param cv
    45       * @param classInfo
    46       * @param ctx
    47       */
    48      public AddInterfaceVisitor(final ClassVisitor cv,
    49                                 final ClassInfo classInfo,
    50                                 final Context ctx) {
    51          super(cv);
    52          m_classInfo = classInfo;
    53          m_ctx = (ContextImpl) ctx;
    54      }
    55
    56      /***
    57       * Visits the class.
    58       *
    59       * @param access
    60       * @param name
    61       * @param superName
    62       * @param interfaces
    63       * @param sourceFile
    64       */
    65      public void visit(final int version,
    66                        final int access,
    67                        final String name,
    68                        final String superName,
    69                        final String[] interfaces,
    70                        final String sourceFile) {
    71          ExpressionContext ctx = new ExpressionContext(PointcutType.WITHIN, m_classInfo, m_classInfo);
    72          if (classFilter(m_classInfo, ctx, m_ctx.getDefinitions())) {
    73              super.visit(version, access, name, superName, interfaces, sourceFile);
    74              return;
    75          }
    76
    77          // javaclass names of interface to have
    78          // use a Set to avoid doublons
    79          final Set interfacesToAdd = new HashSet();
    80
    81          // already there interface javaclass names
    82          for (int i = 0; i < interfaces.length; i++) {
    83              interfacesToAdd.add(interfaces[i].replace('/', '.'));
    84          }
    85
    86          // add new ones
    87          final Set systemDefinitions = m_ctx.getDefinitions();
    88          for (Iterator it = systemDefinitions.iterator(); it.hasNext();) {
    89              SystemDefinition systemDefinition = (SystemDefinition) it.next();
    90              final List interfaceIntroDefs = systemDefinition.getInterfaceIntroductionDefinitions(ctx);
    91              for (Iterator it2 = interfaceIntroDefs.iterator(); it2.hasNext();) {
    92                  final InterfaceIntroductionDefinition interfaceIntroDef = (InterfaceIntroductionDefinition) it2.next();
    93                  interfacesToAdd.addAll(interfaceIntroDef.getInterfaceClassNames());
    94              }
    95              final List mixinDefinitions = systemDefinition.getMixinDefinitions(ctx);
    96              for (Iterator it2 = mixinDefinitions.iterator(); it2.hasNext();) {
    97                  final MixinDefinition mixinDef = (MixinDefinition) it2.next();
    98                  if (ADVISABLE_MIXIN_IMPL_NAME.equals(mixinDef.getMixinImpl().getName())) {
    99                      // mark it as made advisable
    100                     m_ctx.markMadeAdvisable();
    101                 }
    102                 final List interfaceList = mixinDef.getInterfaceClassNames();
    103                 for (Iterator it3 = interfaceList.iterator(); it3.hasNext();) {
    104                     interfacesToAdd.add(((String) it3.next()));
    105                 }
    106             }
    107         }
    108
    109         if (ClassInfoHelper.hasMethodClash(interfacesToAdd, m_ctx.getLoader())) {
    110             super.visit(version, access, name, superName, interfaces, sourceFile);
    111             return;
    112         }
    113
    114         int i = 0;
    115         final String[] newInterfaceArray = new String[interfacesToAdd.size()];
    116         for (Iterator it = interfacesToAdd.iterator(); it.hasNext();) {
    117             newInterfaceArray[i++] = (String) it.next();
    118         }
    119
    120         for (int j = 0; j < newInterfaceArray.length; j++) {
    121             newInterfaceArray[j] = newInterfaceArray[j].replace('.', '/');
    122
    123         }
    124         super.visit(version, access, name, superName, newInterfaceArray, sourceFile);
    125         m_ctx.markAsAdvised();
    126     }
    127
    128     /***
    129      * Filters the classes to be transformed.
    130      *
    131      * @param classInfo   the class to filter
    132      * @param ctx         the context
    133      * @param definitions a set with the definitions
    134      * @return boolean true if the method should be filtered away
    135      */
    136     public static boolean classFilter(final ClassInfo classInfo,
    137                                       final ExpressionContext ctx,
    138                                       final Set definitions) {
    139         for (Iterator it = definitions.iterator(); it.hasNext();) {
    140             SystemDefinition systemDef = (SystemDefinition) it.next();
    141             if (classInfo.isInterface()) {
    142                 return true;
    143             }
    144             String className = classInfo.getName().replace('/', '.');
    145             if (systemDef.inExcludePackage(className)) {
    146                 return true;
    147             }
    148             if (!systemDef.inIncludePackage(className)) {
    149                 return true;
    150             }
    151             if (systemDef.hasMixin(ctx) || systemDef.hasIntroducedInterface(ctx)) {
    152                 return false;
    153             }
    154         }
    155         return true;
    156     }
    157 }