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.compiler;
    9
    10  import java.util.Map;
    11  import java.util.Iterator;
    12  import java.util.WeakHashMap;
    13  import java.util.HashSet;
    14  import java.util.Set;
    15
    16  import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
    17  import org.codehaus.aspectwerkz.expression.ExpressionContext;
    18  import org.codehaus.aspectwerkz.expression.PointcutType;
    19  import org.codehaus.aspectwerkz.expression.ExpressionInfo;
    20  import org.codehaus.aspectwerkz.reflect.MethodInfo;
    21  import org.codehaus.aspectwerkz.reflect.ClassInfo;
    22  import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
    23  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
    24  import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
    25
    26  /***
    27   * TODO is factory a good name, now that it does so much more?
    28   * <p/>
    29   * Factory for the different join point implementations.
    30   * Compiles a new join point on the fly and loads the class.
    31   *
    32   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    33   */
    34  public class JoinPointFactory {
    35
    36      /***
    37       * Stores the compilation infos - mapped to the last compiled join point class based on this compilation info.
    38       */
    39      private static final Map COMPILATION_INFO_REPOSITORY = new WeakHashMap();
    40
    41      /***
    42       * Compiles and loades a join point class, one specific class for each distinct join point.
    43       *
    44       * @param model  the model for the compilation
    45       * @param loader the class loader that the compiled join point should live in
    46       * @return the compiled join point class
    47       */
    48      public static Class compileJoinPointAndAttachToClassLoader(final CompilationInfo.Model model,
    49                                                                 final ClassLoader loader) {
    50          return attachToClassLoader(model.getJoinPointClassName(), loader, compileJoinPoint(model));
    51      }
    52
    53      /***
    54       * Loads a join point class, one specific class for each distinct join point.
    55       *
    56       * @param joinpointClassName
    57       * @param loader the class loader that the compiled join point should live in
    58       * @param bytecode of the joinpoint
    59       * @return the compiled join point class
    60       */
    61      public static Class attachToClassLoader(final String joinpointClassName,
    62                                              final ClassLoader loader,
    63                                              final byte[] bytecode) {
    64          return AsmHelper.defineClass(loader, bytecode, joinpointClassName);
    65      }
    66
    67      /***
    68       * Adds or updates a compilation info. The class key is always the first compiled join point class.
    69       *
    70       * @param clazz
    71       * @param compilationInfo
    72       */
    73      public static void addCompilationInfo(final Class clazz, final CompilationInfo compilationInfo) {
    74          COMPILATION_INFO_REPOSITORY.put(clazz, compilationInfo);
    75      }
    76
    77      /***
    78       * Compiles a join point class, one specific class for each distinct join point.
    79       *
    80       * @param model the model for the compilation
    81       * @return the compiled join point bytecode
    82       */
    83      public static byte[] compileJoinPoint(final CompilationInfo.Model model) {
    84          switch (model.getEmittedJoinPoint().getJoinPointType()) {
    85              case JoinPointType.METHOD_EXECUTION_INT:
    86                  return new MethodExecutionJoinPointCompiler(model).compile();
    87              case JoinPointType.METHOD_CALL_INT:
    88                  return new MethodCallJoinPointCompiler(model).compile();
    89              case JoinPointType.CONSTRUCTOR_EXECUTION_INT:
    90                  return new ConstructorExecutionJoinPointCompiler(model).compile();
    91              case JoinPointType.CONSTRUCTOR_CALL_INT:
    92                  return new ConstructorCallJoinPointCompiler(model).compile();
    93              case JoinPointType.FIELD_SET_INT:
    94                  return new FieldSetJoinPointCompiler(model).compile();
    95              case JoinPointType.FIELD_GET_INT:
    96                  return new FieldGetJoinPointCompiler(model).compile();
    97              case JoinPointType.HANDLER_INT:
    98                  return new HandlerJoinPointCompiler(model).compile();
    99              case JoinPointType.STATIC_INITIALIZATION_INT:
    100                 return new StaticInitializationJoinPointCompiler(model).compile();
    101             default:
    102                 throw new UnsupportedOperationException(
    103                         "join point type is not supported: " + model.getEmittedJoinPoint().getJoinPointType()
    104                 );
    105         }
    106     }
    107
    108     /***
    109      * Redefines the originally compiled join point.
    110      *
    111      * @param compilationInfo the model for the compilation
    112      * @return the compiled join point bytecode
    113      */
    114     public static byte[] redefineJoinPoint(final CompilationInfo compilationInfo) {
    115         switch (compilationInfo.getInitialModel().getEmittedJoinPoint().getJoinPointType()) {
    116             case JoinPointType.METHOD_EXECUTION_INT:
    117                 return new MethodExecutionJoinPointRedefiner(compilationInfo).compile();
    118             case JoinPointType.METHOD_CALL_INT:
    119                 return new MethodCallJoinPointRedefiner(compilationInfo).compile();
    120             case JoinPointType.CONSTRUCTOR_EXECUTION_INT:
    121                 return new ConstructorExecutionJoinPointRedefiner(compilationInfo).compile();
    122             case JoinPointType.CONSTRUCTOR_CALL_INT:
    123                 return new ConstructorCallJoinPointRedefiner(compilationInfo).compile();
    124             case JoinPointType.FIELD_SET_INT:
    125                 return new FieldSetJoinPointRedefiner(compilationInfo).compile();
    126             case JoinPointType.FIELD_GET_INT:
    127                 return new FieldGetJoinPointRedefiner(compilationInfo).compile();
    128             case JoinPointType.HANDLER_INT:
    129                 return new HandlerJoinPointRedefiner(compilationInfo).compile();
    130             default:
    131                 throw new UnsupportedOperationException(
    132                         "join point type is not supported: " +
    133                         compilationInfo.getInitialModel().getEmittedJoinPoint().getJoinPointType()
    134                 );
    135         }
    136     }
    137
    138     /***
    139      * Returns a list with all the join point compilers that matches a specific pointcut expression.
    140      * <p/>
    141      * To be used for redefinition of the join point compilers only. This since the compilers must have been created
    142      * in advance to exist in the repository (which is done when the target class is loaded).
    143      *
    144      * @param expression the pointcut expression
    145      * @return a set with the matching emitted join point
    146      */
    147     public static Set getJoinPointsMatching(final ExpressionInfo expression) {
    148         final Set matchingJoinPointInfos = new HashSet();
    149         for (Iterator it = COMPILATION_INFO_REPOSITORY.entrySet().iterator(); it.hasNext();) {
    150             final Map.Entry entry = (Map.Entry) it.next();
    151
    152             final Class clazz = (Class) entry.getKey();
    153             final CompilationInfo compilationInfo = (CompilationInfo) entry.getValue();
    154             final EmittedJoinPoint joinPoint = (EmittedJoinPoint) compilationInfo.
    155                     getInitialModel().getEmittedJoinPoint();
    156             final ClassLoader loader = clazz.getClassLoader();
    157
    158             final ClassInfo calleeClassInfo = AsmClassInfo.getClassInfo(joinPoint.getCalleeClassName(), loader);
    159             final ClassInfo callerClassInfo = AsmClassInfo.getClassInfo(joinPoint.getCallerClassName(), loader);
    160             final MethodInfo callerMethodInfo = getCallerMethodInfo(callerClassInfo, joinPoint);
    161
    162             ExpressionContext ctx = null;
    163             switch (joinPoint.getJoinPointType()) {
    164                 case JoinPointType.METHOD_EXECUTION_INT:
    165                     ctx = new ExpressionContext(
    166                             PointcutType.EXECUTION,
    167                             calleeClassInfo.getMethod(joinPoint.getJoinPointHash()),
    168                             callerMethodInfo
    169                     );
    170                     break;
    171                 case JoinPointType.METHOD_CALL_INT:
    172                     ctx = new ExpressionContext(
    173                             PointcutType.CALL,
    174                             calleeClassInfo.getMethod(joinPoint.getJoinPointHash()),
    175                             callerMethodInfo
    176                     );
    177                     break;
    178                 case JoinPointType.CONSTRUCTOR_EXECUTION_INT:
    179                     ctx = new ExpressionContext(
    180                             PointcutType.EXECUTION,
    181                             calleeClassInfo.getConstructor(joinPoint.getJoinPointHash()),
    182                             callerMethodInfo
    183                     );
    184                     break;
    185                 case JoinPointType.CONSTRUCTOR_CALL_INT:
    186                     ctx = new ExpressionContext(
    187                             PointcutType.CALL,
    188                             calleeClassInfo.getConstructor(joinPoint.getJoinPointHash()),
    189                             callerMethodInfo
    190                     );
    191                     break;
    192                 case JoinPointType.FIELD_SET_INT:
    193                     ctx = new ExpressionContext(
    194                             PointcutType.SET,
    195                             calleeClassInfo.getField(joinPoint.getJoinPointHash()),
    196                             callerMethodInfo
    197                     );
    198                     break;
    199                 case JoinPointType.FIELD_GET_INT:
    200                     ctx = new ExpressionContext(
    201                             PointcutType.GET,
    202                             calleeClassInfo.getField(joinPoint.getJoinPointHash()),
    203                             callerMethodInfo
    204                     );
    205                     break;
    206                 case JoinPointType.HANDLER_INT:
    207                     ctx = new ExpressionContext(
    208                             PointcutType.HANDLER,
    209                             AsmClassInfo.getClassInfo(joinPoint.getCalleeClassName(), loader),
    210                             callerMethodInfo
    211                     );
    212                     break;
    213                 case JoinPointType.STATIC_INITIALIZATION_INT:
    214                 	ctx = new ExpressionContext(
    215                 	        PointcutType.STATIC_INITIALIZATION,
    216                 	        calleeClassInfo.staticInitializer(),
    217                 	        calleeClassInfo
    218                 	);
    219             }
    220             if (expression.getExpression().match(ctx)) {
    221                 matchingJoinPointInfos.add(new MatchingJoinPointInfo(clazz, compilationInfo, ctx));
    222             }
    223         }
    224         return matchingJoinPointInfos;
    225     }
    226
    227     /***
    228      * Returns the emitted join point structure for a specific JIT generated join point class.
    229      *
    230      * @param clazz the join point class
    231      * @return the emitted join point structure
    232      */
    233     public static EmittedJoinPoint getEmittedJoinPoint(final Class clazz) {
    234         return (EmittedJoinPoint) COMPILATION_INFO_REPOSITORY.get(clazz);
    235     }
    236
    237     /***
    238      * Grabs the caller method info.
    239      *
    240      * @param callerClassInfo
    241      * @param emittedJoinPoint
    242      * @return
    243      */
    244     private static MethodInfo getCallerMethodInfo(final ClassInfo callerClassInfo,
    245                                                   final EmittedJoinPoint emittedJoinPoint) {
    246         MethodInfo callerMethodInfo = null;
    247         MethodInfo[] callerMethods = callerClassInfo.getMethods();
    248         for (int i = 0; i < callerMethods.length; i++) {
    249             MethodInfo method = callerMethods[i];
    250             if (method.getName().equals(emittedJoinPoint.getCallerMethodName()) &&
    251                 method.getSignature().equals(emittedJoinPoint.getCallerMethodDesc())) {
    252                 callerMethodInfo = method;
    253                 break;
    254             }
    255         }
    256         return callerMethodInfo;
    257     }
    258 }