KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > proxy > ProxyCompiler


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.proxy;
9
10 import java.lang.reflect.Method JavaDoc;
11 import java.lang.reflect.Modifier JavaDoc;
12 import java.lang.reflect.Constructor JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.io.BufferedInputStream JavaDoc;
16 import java.io.ByteArrayInputStream JavaDoc;
17
18 import org.codehaus.aspectwerkz.transform.TransformationConstants;
19 import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
20 import org.codehaus.aspectwerkz.reflect.ReflectHelper;
21 import org.codehaus.aspectwerkz.util.ContextClassLoader;
22 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
23 import org.codehaus.aspectwerkz.annotation.instrumentation.asm.AsmAnnotationHelper;
24 import org.objectweb.asm.ClassWriter;
25 import org.objectweb.asm.CodeVisitor;
26 import org.objectweb.asm.Type;
27 import org.objectweb.asm.ClassReader;
28 import org.objectweb.asm.ClassAdapter;
29 import org.objectweb.asm.ClassVisitor;
30 import org.objectweb.asm.Attribute;
31 import org.objectweb.asm.attrs.Attributes;
32
33 /**
34  * Compiler for the AspectWerkz proxies.
35  * <p/>
36  * Creates a subclass of the target class and adds delegate methods to all the non-private and non-final
37  * methods/constructors which delegates to the super class.
38  * <p/>
39  * The annotations are copied.
40  *
41  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
42  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr</a>
43  */

44 public class ProxyCompiler implements TransformationConstants {
45     private final static String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
46
47     /**
48      * Returns an InputStream that would be the one of the AWproxy for the given proxy class name
49      * Used to read annotations from proxy f.e.
50      *
51      * @param loader
52      * @param proxyClassName
53      * @return or null if not found
54      */

55     public static InputStream JavaDoc getProxyResourceAsStream(final ClassLoader JavaDoc loader, final String JavaDoc proxyClassName) {
56         String JavaDoc className = Proxy.getUniqueClassNameFromProxy(proxyClassName);
57         if (className != null) {
58             byte[] proxy = compileProxyFor(loader, className, proxyClassName);
59             return new BufferedInputStream JavaDoc(new ByteArrayInputStream JavaDoc(proxy));
60         } else {
61             return null;
62         }
63     }
64
65     /**
66      * Compiles a new proxy for the class specified.
67      *
68      * @param clazz
69      * @param proxyClassName
70      * @return the byte code
71      */

72     public static byte[] compileProxyFor(final Class JavaDoc clazz, final String JavaDoc proxyClassName) {
73         return compileProxyFor(clazz.getClassLoader(), clazz.getName(), proxyClassName);
74     }
75
76     /**
77      * Compiles a new proxy for the class specified.
78      *
79      * @param loader
80      * @param className
81      * @param proxyClassName
82      * @return the byte code
83      */

84     public static byte[] compileProxyFor(final ClassLoader JavaDoc loader, final String JavaDoc className, final String JavaDoc proxyClassName) {
85
86         final String JavaDoc targetClassName = className.replace('.', '/');
87         final ClassWriter proxyWriter = AsmHelper.newClassWriter(true);
88
89         InputStream JavaDoc in = null;
90         final ClassReader classReader;
91         try {
92             if (loader != null) {
93                 in = loader.getResourceAsStream(targetClassName + ".class");
94             } else {
95                 in = ClassLoader.getSystemClassLoader().getResourceAsStream(targetClassName + ".class");
96             }
97             classReader = new ClassReader(in);
98         } catch (IOException JavaDoc e) {
99             throw new WrappedRuntimeException("Cannot compile proxy for " + className, e);
100         } finally {
101             try {
102                 in.close();
103             } catch (Throwable JavaDoc t) {
104                 ;
105             }
106         }
107
108         ClassVisitor createProxy = new ProxyCompilerClassVisitor(proxyWriter, proxyClassName.replace('.', '/'));
109         classReader.accept(createProxy, Attributes.getDefaultAttributes(), true);// no need for debug info
110
return proxyWriter.toByteArray();
111     }
112
113     /**
114      * Visit the class and create the proxy that delegates to super.
115      *
116      * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
117      */

118     private static class ProxyCompilerClassVisitor extends AsmAnnotationHelper.NullClassAdapter {
119
120         final private ClassVisitor m_proxyCv;
121         final private String JavaDoc m_proxyClassName;
122         private String JavaDoc m_className;
123
124         public ProxyCompilerClassVisitor(final ClassVisitor proxyCv, final String JavaDoc proxyClassName) {
125             m_proxyCv = proxyCv;
126             m_proxyClassName = proxyClassName;
127         }
128
129         /**
130          * Visits the class.
131          *
132          * @param access
133          * @param name
134          * @param superName
135          * @param interfaces
136          * @param sourceFile
137          */

138         public void visit(final int version,
139                           final int access,
140                           final String JavaDoc name,
141                           final String JavaDoc superName,
142                           final String JavaDoc[] interfaces,
143                           final String JavaDoc sourceFile) {
144             if (Modifier.isFinal(access)) {
145                 throw new RuntimeException JavaDoc("Cannot create a proxy from final class " + name);
146             }
147             m_className = name;
148             m_proxyCv.visit(
149                     version,
150                     ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC,
151                     m_proxyClassName.replace('.', '/'),
152                     name,
153                     interfaces,
154                     null
155             );
156         }
157
158         /**
159          * Visits the methods.
160          *
161          * @param access
162          * @param name
163          * @param desc
164          * @param exceptions
165          * @param attrs
166          * @return
167          */

168         public CodeVisitor visitMethod(final int access,
169                                        final String JavaDoc name,
170                                        final String JavaDoc desc,
171                                        final String JavaDoc[] exceptions,
172                                        final Attribute attrs) {
173             if (Modifier.isFinal(access) || Modifier.isPrivate(access) || Modifier.isNative(access)) {
174                 // skip final or private or native methods
175
// TODO we could proxy native methods but that would lead to difference with regular weaving
176
;
177             } else if (CLINIT_METHOD_NAME.equals(name)) {
178                 // skip clinit
179
;
180             } else if (INIT_METHOD_NAME.equals(name)) {
181                 // constructors
182
CodeVisitor proxyCode = m_proxyCv.visitMethod(
183                         access + ACC_SYNTHETIC,
184                         INIT_METHOD_NAME,
185                         desc,
186                         exceptions,
187                         attrs
188                 );
189
190                 proxyCode.visitVarInsn(ALOAD, 0);
191                 AsmHelper.loadArgumentTypes(proxyCode, Type.getArgumentTypes(desc), false);
192                 proxyCode.visitMethodInsn(INVOKESPECIAL, m_className, INIT_METHOD_NAME, desc);
193                 proxyCode.visitInsn(RETURN);
194                 proxyCode.visitMaxs(0, 0);
195             } else {
196                 // method that can be proxied
197
CodeVisitor proxyCode = m_proxyCv.visitMethod(
198                         access + ACC_SYNTHETIC,
199                         name,
200                         desc,
201                         exceptions,
202                         attrs
203                 );
204
205                 if (Modifier.isStatic(access)) {
206                     AsmHelper.loadArgumentTypes(proxyCode, Type.getArgumentTypes(desc), true);
207                     proxyCode.visitMethodInsn(INVOKESTATIC, m_className, name, desc);
208                     AsmHelper.addReturnStatement(proxyCode, Type.getReturnType(desc));
209                     proxyCode.visitMaxs(0, 0);
210                 } else {
211                     proxyCode.visitVarInsn(ALOAD, 0);
212                     AsmHelper.loadArgumentTypes(proxyCode, Type.getArgumentTypes(desc), false);
213                     proxyCode.visitMethodInsn(INVOKESPECIAL, m_className, name, desc);
214                     AsmHelper.addReturnStatement(proxyCode, Type.getReturnType(desc));
215                     proxyCode.visitMaxs(0, 0);
216                 }
217             }
218
219             return AsmAnnotationHelper.NullCodeAdapter.NULL_CODE_ADAPTER;
220         }
221     }
222
223 // /**
224
// * Creates constructors that delgates to the matching base class constructors.
225
// * Skips all private constructors.
226
// *
227
// * @param writer
228
// * @param clazz
229
// * @param targetClassName
230
// */
231
// private static void createConstructorDelegators(final ClassWriter writer,
232
// final Class clazz,
233
// final String targetClassName) {
234
// CodeVisitor cv;
235
// Constructor[] constructors = clazz.getDeclaredConstructors();
236
// for (int i = 0; i < constructors.length; i++) {
237
// Constructor constructor = constructors[i];
238
// int mods = constructor.getModifiers();
239
// if (!Modifier.isPrivate(mods) && !Modifier.isFinal(mods)) {
240
// Class[] exceptionClasses = constructor.getExceptionTypes();
241
// String[] exceptionTypeNames = new String[constructor.getExceptionTypes().length];
242
// for (int j = 0; j < exceptionTypeNames.length; j++) {
243
// exceptionTypeNames[j] = exceptionClasses[j].getName().replace('.', '/');
244
// }
245
// final String desc = ReflectHelper.getConstructorSignature(constructor);
246
// cv = writer.visitMethod(
247
// mods + ACC_SYNTHETIC,
248
// INIT_METHOD_NAME,
249
// desc,
250
// exceptionTypeNames,
251
// null
252
// );
253
//
254
// cv.visitVarInsn(ALOAD, 0);
255
// AsmHelper.loadArgumentTypes(cv, Type.getArgumentTypes(desc), false);
256
//
257
// cv.visitMethodInsn(INVOKESPECIAL, targetClassName, INIT_METHOD_NAME, desc);
258
//
259
// cv.visitInsn(RETURN);
260
// cv.visitMaxs(0, 0);
261
// }
262
// }
263
// }
264
//
265
// /**
266
// * Creates method methods that delgates to the base class method.
267
// * Skips all private and final methods.
268
// *
269
// * @param writer
270
// * @param clazz
271
// * @param targetClassName
272
// */
273
// private static void createMethodDelegators(final ClassWriter writer,
274
// final Class clazz,
275
// final String targetClassName) {
276
// CodeVisitor cv;
277
// Method[] methods = clazz.getDeclaredMethods();
278
// for (int i = 0; i < methods.length; i++) {
279
// Method method = methods[i];
280
// int mods = method.getModifiers();
281
// if (!Modifier.isPrivate(mods) && !Modifier.isFinal(mods)) {
282
//
283
// Class[] exceptionClasses = method.getExceptionTypes();
284
// String[] exceptionTypeNames = new String[method.getExceptionTypes().length];
285
// for (int j = 0; j < exceptionTypeNames.length; j++) {
286
// exceptionTypeNames[j] = exceptionClasses[j].getName().replace('.', '/');
287
// }
288
// final String methodName = method.getName();
289
// final String desc = Type.getMethodDescriptor(method);
290
//
291
// cv = writer.visitMethod(
292
// mods + ACC_SYNTHETIC,
293
// methodName,
294
// desc,
295
// exceptionTypeNames,
296
// null
297
// );
298
//
299
// if (Modifier.isStatic(mods)) {
300
// AsmHelper.loadArgumentTypes(cv, Type.getArgumentTypes(desc), true);
301
// cv.visitMethodInsn(INVOKESTATIC, targetClassName, methodName, desc);
302
// } else {
303
// cv.visitVarInsn(ALOAD, 0);
304
// AsmHelper.loadArgumentTypes(cv, Type.getArgumentTypes(desc), false);
305
// cv.visitMethodInsn(INVOKESPECIAL, targetClassName, methodName, desc);
306
// }
307
//
308
// AsmHelper.addReturnStatement(cv, Type.getReturnType(method));
309
// cv.visitMaxs(0, 0);
310
// }
311
// }
312
// }
313
}
314
Popular Tags