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.ClassLoaderPatcher;
11  import org.codehaus.aspectwerkz.hook.ClassLoaderPreProcessor;
12  
13  import java.io.InputStream;
14  
15  import javassist.CannotCompileException;
16  import javassist.ClassPool;
17  import javassist.CtClass;
18  import javassist.expr.ExprEditor;
19  import javassist.expr.MethodCall;
20  
21  /***
22   * Instruments the java.lang.ClassLoader to plug in the Class PreProcessor mechanism using Javassist. <p/>We are using a
23   * lazy initialization of the class preprocessor to allow all class pre processor logic to be in system classpath and
24   * not in bootclasspath. <p/>This implementation should support IBM custom JRE
25   *
26   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
27   */
28  public class ClassLoaderPreProcessorImpl implements ClassLoaderPreProcessor {
29      public ClassLoaderPreProcessorImpl() {
30      }
31  
32      public byte[] preProcess(final byte[] b) {
33          try {
34              ClassPool pool = ClassPool.getDefault();
35              CtClass klass = pool.get("java.lang.ClassLoader");
36  
37              // patch caller side of defineClass0
38              // pre-call
39              // byte[] besee =
40              // com.gnilux.besee.hook.impl.ClassPreProcessorHelper.defineClass0Pre(this, $$);
41              // <call> c = defineClass0(name, besee, 0, besee.length, protectionDomain);
42              ExprEditor defineClass0Pre = new ExprEditor() {
43                  public void edit(MethodCall m) throws CannotCompileException {
44                      if ("defineClass0".equals(m.getMethodName())) {
45                          int argsCount = 5;
46  
47                          // For SUN VM, argCount = 5: name, byte[], int, int, ProtectionDomain
48                          // For IBM 1.3, argCount = 7: ... + Certificate + byte[] flatSource
49                          try {
50                              argsCount = m.getMethod().getParameterTypes().length;
51                          } catch (Throwable t) {
52                              throw new RuntimeException(t.toString());
53                          }
54                          if (argsCount == 5) {
55                              m.replace(
56                                      '{'
57                                      +
58                                      "  byte[] newBytes = org.codehaus.aspectwerkz.hook.impl.ClassPreProcessorHelper.defineClass0Pre($0, $$);"
59                                      + "  $_ = $proceed($1, newBytes, 0, newBytes.length, $5);"
60                                      + '}'
61                              );
62                          } else if (argsCount == 7) {
63                              m.replace(
64                                      '{'
65                                      +
66                                      "  byte[] newBytes = org.codehaus.aspectwerkz.hook.impl.ClassPreProcessorHelper.defineClass0Pre($0, $1, $2, $3, $4, $5);"
67                                      + "  $_ = $proceed($1, newBytes, 0, newBytes.length, $5, $6, $7);"
68                                      + '}'
69                              );
70                          }
71                      }
72                  }
73              };
74              klass.instrument(defineClass0Pre);
75  
76              //
77              //            pool.writeFile("java.lang.ClassLoader", "___");
78              //            System.out.println("========DUMPED");
79              return klass.toBytecode();
80  
81              //            return pool.write("java.lang.ClassLoader");
82          } catch (Exception e) {
83              System.err.println("failed to patch ClassLoader:");
84              e.printStackTrace();
85              return b;
86          }
87      }
88  
89      /***
90       * main test
91       */
92      public static void main(String[] args) throws Exception {
93          ClassLoaderPreProcessor me = new ClassLoaderPreProcessorImpl();
94          InputStream is = ClassLoader.getSystemClassLoader().getParent().getResourceAsStream(
95                  "java/lang/ClassLoader.class"
96          );
97          me.preProcess(ClassLoaderPatcher.inputStreamToByteArray(is));
98          is.close();
99      }
100 }