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.hook.impl;
    9
    10  import org.codehaus.aspectwerkz.hook.ClassPreProcessor;
    11
    12  import java.security.ProtectionDomain;
    13  import java.lang.reflect.Method;
    14
    15  /***
    16   * Helper class called by the modified java.lang.ClassLoader. <p/>This class is called at different points by the
    17   * modified java.lang.ClassLoader of the org.codehaus.aspectwerkz.hook.impl.ClassLoaderPreProcessorImpl implemention.
    18   * <br/>This class must reside in the -Xbootclasspath when AspectWerkz layer 1 is used, but the effective implementation
    19   * of the class preprocessor (AspectWerkz layer 2) can be in standard system classpath (-cp).
    20   *
    21   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
    22   */
    23  public class ClassPreProcessorHelper {
    24      /***
    25       * ClassPreProcessor used if aspectwerkz.classloader.preprocessor property is defined to full qualified class name
    26       */
    27      private static ClassPreProcessor preProcessor;
    28
    29      /***
    30       * true if preProcesor already initalized
    31       */
    32      private static boolean preProcessorInitialized;
    33
    34      /***
    35       * option used to defined the class preprocessor
    36       */
    37      private static String PRE_PROCESSOR_CLASSNAME_PROPERTY = "aspectwerkz.classloader.preprocessor";
    38
    39      /***
    40       * default class preprocessor
    41       */
    42      private static String PRE_PROCESSOR_CLASSNAME_DEFAULT = "org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor";
    43
    44      static {
    45          initializePreProcessor();
    46      }
    47
    48      /***
    49       * Returns the configured class preprocessor Should be called after initialization only
    50       *
    51       * @return the preprocessor or null if not initialized
    52       */
    53      public static ClassPreProcessor getClassPreProcessor() {
    54          return preProcessor;
    55      }
    56
    57      /***
    58       * Initialization of the ClassPreProcessor The ClassPreProcessor implementation is lazy loaded. This allow to put it
    59       * in the regular classpath whereas the instrumentation layer (layer 1) is in the bootclasspath
    60       */
    61      public static synchronized void initializePreProcessor() {
    62          if (preProcessorInitialized) {
    63              return;
    64          }
    65          preProcessorInitialized = true;
    66          Class klass = null;
    67          String s = System.getProperty(PRE_PROCESSOR_CLASSNAME_PROPERTY, PRE_PROCESSOR_CLASSNAME_DEFAULT);
    68          try {
    69              // force loading thru System class loader to allow
    70              // preprocessor implementation to be in standard classpath
    71              klass = Class.forName(s, true, ClassLoader.getSystemClassLoader());
    72          } catch (ClassNotFoundException _ex) {
    73              System.err.println("AspectWerkz - WARN - Pre-processor class '" + s + "' not found");
    74          }
    75          if (klass != null) {
    76              try {
    77                  preProcessor = (ClassPreProcessor) klass.newInstance();
    78                  preProcessor.initialize();
    79                  System.out.println("AspectWerkz - INFO - Pre-processor " + s + " loaded and initialized");
    80              } catch (Throwable throwable) {
    81                  System.err.println("AspectWerkz - WARN - Error initializing pre-processor class " + s + ':');
    82                  throwable.printStackTrace();
    83              }
    84          }
    85      }
    86
    87      /***
    88       * byte code instrumentation of class loaded
    89       */
    90      public static byte[] defineClass0Pre(ClassLoader caller,
    91                                           String name,
    92                                           byte[] b,
    93                                           int off,
    94                                           int len,
    95                                           ProtectionDomain pd) {
    96          if (preProcessor == null) {
    97              // we need to check this due to reentrancy when ClassPreProcessorHelper is beeing
    98              // initialized
    99              // since it tries to load a ClassPreProcessor implementation
    100             byte[] obyte = new byte[len];
    101             System.arraycopy(b, off, obyte, 0, len);
    102             return obyte;
    103         } else {
    104             try {
    105                 byte[] ibyte = new byte[len];
    106                 System.arraycopy(b, off, ibyte, 0, len);
    107                 return preProcessor.preProcess(name, ibyte, caller);
    108             } catch (Throwable throwable) {
    109                 System.err.println(
    110                         "AspectWerkz - WARN - Error pre-processing class "
    111                         + name
    112                         + " in "
    113                         + Thread.currentThread()
    114                 );
    115                 throwable.printStackTrace();
    116                 // fallback to unweaved bytecode
    117                 byte[] obyte = new byte[len];
    118                 System.arraycopy(b, off, obyte, 0, len);
    119                 return obyte;
    120             }
    121         }
    122     }
    123
    124     /***
    125      * Byte code instrumentation of class loaded using Java 5 style thru NIO
    126      * Since Java 5 comes with JVMTI this helper should be rarely used.
    127      * We do no reference ByteBuffer directly to allow Java 1.3 compilation, though
    128      * this helper will be really slow
    129      *
    130      * @param caller
    131      * @param name
    132      * @param byteBuffer Object that is instance of Java 1.4 NIO ButeBuffer
    133      * @param off
    134      * @param len
    135      * @param pd
    136      * @return Object instance of Java 1.4 NIO ByteBuffer
    137      */
    138     public static Object/*java.nio.ByteBuffer*/ defineClass0Pre(ClassLoader caller,
    139                                              String name,
    140                                              Object/*java.nio.ByteBuffer*/ byteBuffer,
    141                                              int off,
    142                                              int len,
    143                                              ProtectionDomain pd) {
    144         byte[] bytes = new byte[len];
    145         //Java 1.4 : byteBuffer.get(bytes, off, len);
    146         byteBufferGet(byteBuffer, bytes, off, len);
    147         byte[] newbytes = defineClass0Pre(caller, name, bytes, 0, bytes.length, pd);
    148         //Java 1.4 : ByteBuffer newBuffer = ByteBuffer.wrap(newbytes);
    149         Object newBuffer = byteBufferWrap(newbytes);
    150         return newBuffer;
    151     }
    152
    153     /***
    154      * Equivalent to Java 1.4 NIO aByteBuffer.get(bytes, offset, length) to populate
    155      * the bytes array from the aByteBuffer.
    156      *
    157      * @param byteBuffer
    158      * @param dest
    159      * @param offset
    160      * @param length
    161      */
    162     private static void byteBufferGet(Object byteBuffer, byte[] dest, int offset, int length) {
    163         try {
    164             Class cByteBuffer = Class.forName("java.nio.ByteBuffer");
    165             Method mGet = cByteBuffer.getDeclaredMethod("get", new Class[]{BYTE_ARRAY_CLASS, int.class, int.class});
    166             mGet.invoke(byteBuffer, new Object[]{dest, new Integer(offset), new Integer(length)});
    167         } catch (Throwable t) {
    168             System.err.println("AW : java.nio not supported");
    169             throw new RuntimeException(t.toString());
    170         }
    171     }
    172
    173     /***
    174      * Equivalent to Java 1.4 NIO static ByteBuffer.wrap(bytes) to create
    175      * a new byteBuffer instance.
    176      *
    177      * @param bytes
    178      * @return a ByteBuffer
    179      */
    180     private static Object/*java.nio.ByteBuffer*/ byteBufferWrap(byte[] bytes) {
    181         try {
    182             Class cByteBuffer = Class.forName("java.nio.ByteBuffer");
    183             Method mGet = cByteBuffer.getDeclaredMethod("wrap", new Class[]{BYTE_ARRAY_CLASS});
    184             Object byteBuffer = mGet.invoke(null, new Object[]{bytes});
    185             return byteBuffer;
    186         } catch (Throwable t) {
    187             System.err.println("AW : java.nio not supported");
    188             throw new RuntimeException(t.toString());
    189         }
    190     }
    191
    192     private final static byte[] EMPTY_BYTEARRAY = new byte[0];
    193     private final static Class BYTE_ARRAY_CLASS = EMPTY_BYTEARRAY.getClass();
    194
    195 }