KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > proxy > ProxySubclassingCompiler


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.proxy;
5
6 import com.tc.asm.*;
7
8 import com.tc.aspectwerkz.exception.WrappedRuntimeException;
9 import com.tc.aspectwerkz.transform.TransformationConstants;
10 import com.tc.aspectwerkz.transform.inlining.AsmCopyAdapter;
11 import com.tc.aspectwerkz.transform.inlining.AsmHelper;
12 import com.tc.aspectwerkz.transform.inlining.AsmNullAdapter;
13
14 import java.io.IOException JavaDoc;
15 import java.io.InputStream JavaDoc;
16 import java.lang.reflect.Modifier JavaDoc;
17
18 /**
19  * Compiler for the AspectWerkz proxies.
20  * <p/>
21  * Creates a subclass of the target class and adds delegate methods to all the non-private and non-final
22  * methods/constructors which delegates to the super class.
23  * <p/>
24  * The annotations are copied.
25  *
26  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
27  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr</a>
28  */

29 public class ProxySubclassingCompiler implements TransformationConstants {
30
31   /**
32    * Compiles a new proxy for the class specified.
33    *
34    * @param clazz
35    * @param proxyClassName
36    * @return the byte code
37    */

38   public static byte[] compileProxyFor(final Class JavaDoc clazz, final String JavaDoc proxyClassName) {
39     return compileProxyFor(clazz.getClassLoader(), clazz.getName(), proxyClassName);
40   }
41
42   /**
43    * Compiles a new proxy for the class specified.
44    *
45    * @param loader
46    * @param className
47    * @param proxyClassName
48    * @return the byte code
49    */

50   public static byte[] compileProxyFor(final ClassLoader JavaDoc loader, final String JavaDoc className, final String JavaDoc proxyClassName) {
51
52     final String JavaDoc targetClassName = className.replace('.', '/');
53     final ClassWriter proxyWriter = AsmHelper.newClassWriter(true);
54
55     InputStream JavaDoc in = null;
56     final ClassReader classReader;
57     try {
58       if (loader != null) {
59         in = loader.getResourceAsStream(targetClassName + ".class");
60       } else {
61         in = ClassLoader.getSystemClassLoader().getResourceAsStream(targetClassName + ".class");
62       }
63       classReader = new ClassReader(in);
64     } catch (IOException JavaDoc e) {
65       throw new WrappedRuntimeException("Cannot compile proxy for " + className, e);
66     } finally {
67       try {
68         in.close();
69       } catch (Throwable JavaDoc t) {
70         ;
71       }
72     }
73
74     ClassVisitor createProxy = new ProxyCompilerClassVisitor(proxyWriter, proxyClassName.replace('.', '/'));
75     classReader.accept(createProxy, true);// no need for debug info
76
return proxyWriter.toByteArray();
77   }
78
79   /**
80    * Visit the class and create the proxy that delegates to super.
81    *
82    * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
83    */

84   private static class ProxyCompilerClassVisitor extends AsmNullAdapter.NullClassAdapter {
85
86     final private ClassVisitor m_proxyCv;
87     final private String JavaDoc m_proxyClassName;
88     private String JavaDoc m_className;
89
90     public ProxyCompilerClassVisitor(final ClassVisitor proxyCv, final String JavaDoc proxyClassName) {
91       m_proxyCv = proxyCv;
92       m_proxyClassName = proxyClassName;
93     }
94
95     /**
96      * Visits the class.
97      *
98      * @param access
99      * @param name
100      * @param signature
101      * @param superName
102      * @param interfaces
103      */

104     public void visit(final int version,
105                       final int access,
106                       final String JavaDoc name,
107                       final String JavaDoc signature,
108                       final String JavaDoc superName,
109                       final String JavaDoc[] interfaces) {
110       if (Modifier.isFinal(access)) {
111         throw new RuntimeException JavaDoc("Cannot create a proxy from final class " + name);
112       }
113       m_className = name;
114       m_proxyCv.visit(
115               version,
116               ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC,
117               m_proxyClassName.replace('.', '/'),
118               signature,
119               name,
120               interfaces
121       );
122     }
123
124     /**
125      * Visits the methods.
126      *
127      * @param access
128      * @param name
129      * @param desc
130      * @param signature
131      * @param exceptions
132      * @return
133      */

134     public MethodVisitor visitMethod(final int access,
135                                      final String JavaDoc name,
136                                      final String JavaDoc desc,
137                                      final String JavaDoc signature,
138                                      final String JavaDoc[] exceptions) {
139       final MethodVisitor proxyCode;
140       final boolean copyAnnotation;
141       if (Modifier.isFinal(access) || Modifier.isPrivate(access) || Modifier.isNative(access)) {
142         // skip final or private or native methods
143
// TODO we could proxy native methods but that would lead to difference with regular weaving
144
proxyCode = AsmNullAdapter.NullMethodAdapter.NULL_METHOD_ADAPTER;
145         copyAnnotation = false;
146       } else if (CLINIT_METHOD_NAME.equals(name)) {
147         // skip clinit
148
proxyCode = AsmNullAdapter.NullMethodAdapter.NULL_METHOD_ADAPTER;
149         copyAnnotation = false;
150       } else if (INIT_METHOD_NAME.equals(name)) {
151         // constructors
152
proxyCode = m_proxyCv.visitMethod(
153                 access + ACC_SYNTHETIC,
154                 INIT_METHOD_NAME,
155                 desc,
156                 signature,
157                 exceptions
158         );
159
160         proxyCode.visitVarInsn(ALOAD, 0);
161         AsmHelper.loadArgumentTypes(proxyCode, Type.getArgumentTypes(desc), false);
162         proxyCode.visitMethodInsn(INVOKESPECIAL, m_className, INIT_METHOD_NAME, desc);
163         proxyCode.visitInsn(RETURN);
164         proxyCode.visitMaxs(0, 0);
165         copyAnnotation = true;
166       } else {
167         // method that can be proxied
168
proxyCode = m_proxyCv.visitMethod(
169                 access + ACC_SYNTHETIC,
170                 name,
171                 desc,
172                 signature,
173                 exceptions
174         );
175
176         if (Modifier.isStatic(access)) {
177           AsmHelper.loadArgumentTypes(proxyCode, Type.getArgumentTypes(desc), true);
178           proxyCode.visitMethodInsn(INVOKESTATIC, m_className, name, desc);
179           AsmHelper.addReturnStatement(proxyCode, Type.getReturnType(desc));
180           proxyCode.visitMaxs(0, 0);
181         } else {
182           proxyCode.visitVarInsn(ALOAD, 0);
183           AsmHelper.loadArgumentTypes(proxyCode, Type.getArgumentTypes(desc), false);
184           proxyCode.visitMethodInsn(INVOKESPECIAL, m_className, name, desc);
185           AsmHelper.addReturnStatement(proxyCode, Type.getReturnType(desc));
186           proxyCode.visitMaxs(0, 0);
187         }
188         copyAnnotation = true;
189       }
190
191       // copy the annotation if necessary
192
if (copyAnnotation) {
193         return new AsmCopyAdapter.CopyMethodAnnotationElseNullAdapter(proxyCode);
194       } else {
195         return AsmNullAdapter.NullMethodAdapter.NULL_METHOD_ADAPTER;
196       }
197     }
198
199     /**
200      * Visit the class annotation (copy)
201      *
202      * @param desc
203      * @param visible
204      * @return
205      */

206     public AnnotationVisitor visitAnnotation(String JavaDoc desc, boolean visible) {
207       return new AsmCopyAdapter.CopyAnnotationAdapter(
208               super.visitAnnotation(desc, visible),
209               m_proxyCv.visitAnnotation(desc, visible)
210       );
211     }
212
213     /**
214      * Visit the custom attribute (copy)
215      *
216      * @param attribute
217      */

218     public void visitAttribute(Attribute attribute) {
219       m_proxyCv.visitAttribute(attribute);
220     }
221   }
222 }
223
Popular Tags