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