001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.hook.impl;
005:
006: import com.tc.aspectwerkz.hook.ClassPreProcessor;
007:
008: import java.security.ProtectionDomain;
009: import java.lang.reflect.Method;
010:
011: /**
012: * Helper class called by the modified java.lang.ClassLoader. <p/>This class is called at different points by the
013: * modified java.lang.ClassLoader of the com.tc.aspectwerkz.hook.impl.ClassLoaderPreProcessorImpl implemention.
014: * <br/>This class must reside in the -Xbootclasspath when AspectWerkz layer 1 is used, but the effective implementation
015: * of the class preprocessor (AspectWerkz layer 2) can be in standard system classpath (-cp).
016: *
017: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
018: */
019: public class ClassPreProcessorHelper {
020: /**
021: * ClassPreProcessor used if aspectwerkz.classloader.preprocessor property is defined to full qualified class name
022: */
023: private static ClassPreProcessor preProcessor;
024:
025: /**
026: * true if preProcesor already initalized
027: */
028: private static boolean preProcessorInitialized;
029:
030: /**
031: * option used to defined the class preprocessor
032: */
033: private static String PRE_PROCESSOR_CLASSNAME_PROPERTY = "aspectwerkz.classloader.preprocessor";
034:
035: /**
036: * default class preprocessor
037: */
038: private static String PRE_PROCESSOR_CLASSNAME_DEFAULT = "com.tc.aspectwerkz.transform.AspectWerkzPreProcessor";
039:
040: static {
041: initializePreProcessor();
042: }
043:
044: /**
045: * Returns the configured class preprocessor Should be called after initialization only
046: *
047: * @return the preprocessor or null if not initialized
048: */
049: public static ClassPreProcessor getClassPreProcessor() {
050: return preProcessor;
051: }
052:
053: /**
054: * Initialization of the ClassPreProcessor The ClassPreProcessor implementation is lazy loaded. This allow to put it
055: * in the regular classpath whereas the instrumentation layer (layer 1) is in the bootclasspath
056: */
057: public static synchronized void initializePreProcessor() {
058: if (preProcessorInitialized) {
059: return;
060: }
061: preProcessorInitialized = true;
062: Class klass = null;
063: String s = System.getProperty(PRE_PROCESSOR_CLASSNAME_PROPERTY,
064: PRE_PROCESSOR_CLASSNAME_DEFAULT);
065: try {
066: // force loading thru System class loader to allow
067: // preprocessor implementation to be in standard classpath
068: klass = Class.forName(s, true, ClassLoader
069: .getSystemClassLoader());
070: } catch (ClassNotFoundException _ex) {
071: System.err
072: .println("AspectWerkz - WARN - Pre-processor class '"
073: + s + "' not found");
074: }
075: if (klass != null) {
076: try {
077: preProcessor = (ClassPreProcessor) klass.newInstance();
078: preProcessor.initialize();
079: System.err
080: .println("AspectWerkz - INFO - Pre-processor "
081: + s + " loaded and initialized");
082: } catch (Throwable throwable) {
083: System.err
084: .println("AspectWerkz - WARN - Error initializing pre-processor class "
085: + s + ':');
086: throwable.printStackTrace();
087: }
088: }
089: }
090:
091: /**
092: * byte code instrumentation of class loaded
093: */
094: public static byte[] defineClass0Pre(ClassLoader caller,
095: String name, byte[] b, int off, int len, ProtectionDomain pd) {
096: if (preProcessor == null) {
097: // we need to check this due to reentrancy when ClassPreProcessorHelper is beeing
098: // initialized
099: // 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
110: .println("AspectWerkz - WARN - Error pre-processing class "
111: + name
112: + " in "
113: + Thread.currentThread());
114: throwable.printStackTrace();
115: // fallback to unweaved bytecode
116: byte[] obyte = new byte[len];
117: System.arraycopy(b, off, obyte, 0, len);
118: return obyte;
119: }
120: }
121: }
122:
123: /**
124: * Byte code instrumentation of class loaded using Java 5 style thru NIO
125: * Since Java 5 comes with JVMTI this helper should be rarely used.
126: * We do no reference ByteBuffer directly to allow Java 1.3 compilation, though
127: * this helper will be really slow
128: *
129: * @param caller
130: * @param name
131: * @param byteBuffer Object that is instance of Java 1.4 NIO ButeBuffer
132: * @param off
133: * @param len
134: * @param pd
135: * @return Object instance of Java 1.4 NIO ByteBuffer
136: */
137: public static Object/*java.nio.ByteBuffer*/defineClass0Pre(
138: ClassLoader caller, String name,
139: Object/*java.nio.ByteBuffer*/byteBuffer, int off, int len,
140: ProtectionDomain pd) {
141: byte[] bytes = new byte[len];
142: //Java 1.4 : byteBuffer.getDefault(bytes, off, len);
143: byteBufferGet(byteBuffer, bytes, off, len);
144: byte[] newbytes = defineClass0Pre(caller, name, bytes, 0,
145: bytes.length, pd);
146: //Java 1.4 : ByteBuffer newBuffer = ByteBuffer.wrap(newbytes);
147: Object newBuffer = byteBufferWrap(newbytes);
148: return newBuffer;
149: }
150:
151: /**
152: * Equivalent to Java 1.4 NIO aByteBuffer.getDefault(bytes, offset, length) to populate
153: * the bytes array from the aByteBuffer.
154: *
155: * @param byteBuffer
156: * @param dest
157: * @param offset
158: * @param length
159: */
160: private static void byteBufferGet(Object byteBuffer, byte[] dest,
161: int offset, int length) {
162: try {
163: Class cByteBuffer = Class.forName("java.nio.ByteBuffer");
164: Method mGet = cByteBuffer.getDeclaredMethod("getDefault",
165: new Class[] { BYTE_ARRAY_CLASS, int.class,
166: int.class });
167: mGet.invoke(byteBuffer, new Object[] { dest,
168: new Integer(offset), new Integer(length) });
169: } catch (Throwable t) {
170: System.err.println("AW : java.nio not supported");
171: throw new RuntimeException(t.toString());
172: }
173: }
174:
175: /**
176: * Equivalent to Java 1.4 NIO static ByteBuffer.wrap(bytes) to create
177: * a new byteBuffer instance.
178: *
179: * @param bytes
180: * @return a ByteBuffer
181: */
182: private static Object/*java.nio.ByteBuffer*/byteBufferWrap(
183: byte[] bytes) {
184: try {
185: Class cByteBuffer = Class.forName("java.nio.ByteBuffer");
186: Method mGet = cByteBuffer.getDeclaredMethod("wrap",
187: new Class[] { BYTE_ARRAY_CLASS });
188: Object byteBuffer = mGet.invoke(null,
189: new Object[] { bytes });
190: return byteBuffer;
191: } catch (Throwable t) {
192: System.err.println("AW : java.nio not supported");
193: throw new RuntimeException(t.toString());
194: }
195: }
196:
197: private final static byte[] EMPTY_BYTEARRAY = new byte[0];
198: private final static Class BYTE_ARRAY_CLASS = EMPTY_BYTEARRAY
199: .getClass();
200:
201: }
|