KickJava   Java API By Example, From Geeks To Geeks.

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


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.ClassReader;
7 import com.tc.asm.ClassVisitor;
8 import com.tc.asm.ClassWriter;
9 import com.tc.asm.MethodVisitor;
10 import com.tc.asm.Opcodes;
11 import com.tc.asm.Type;
12
13 import com.tc.aspectwerkz.exception.WrappedRuntimeException;
14 import com.tc.aspectwerkz.transform.TransformationConstants;
15 import com.tc.aspectwerkz.transform.inlining.AsmHelper;
16 import com.tc.aspectwerkz.transform.inlining.AsmNullAdapter;
17
18 import java.io.IOException JavaDoc;
19 import java.io.InputStream JavaDoc;
20 import java.util.HashSet JavaDoc;
21 import java.util.Set JavaDoc;
22
23 /**
24  * Compile a proxy class for the delegation strategy.
25  * <p/>
26  * All interfaces methods are taken in the given interface order and implemented using delegation.
27  * A single constructor is compiled wich accept each interface as argument
28  *
29  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
30  */

31 public class ProxyDelegationCompiler implements TransformationConstants {
32
33   /**
34    * Compile the proxy
35    *
36    * @param loader
37    * @param interfaces
38    * @param proxyClassName
39    * @return
40    */

41   public static byte[] compileProxyFor(
42           final ClassLoader JavaDoc loader, final Class JavaDoc[] interfaces, final String JavaDoc proxyClassName) {
43     final ClassWriter proxyWriter = AsmHelper.newClassWriter(true);
44
45     final Set JavaDoc methodSignatures = new HashSet JavaDoc();
46     final String JavaDoc[] interfaceClassNames = new String JavaDoc[interfaces.length];
47     final String JavaDoc[] interfaceSignatures = new String JavaDoc[interfaces.length];
48     for (int i = 0; i < interfaces.length; i++) {
49       interfaceClassNames[i] = interfaces[i].getName().replace('.', '/');
50       interfaceSignatures[i] = 'L' + interfaceClassNames[i] + ';';
51     }
52
53     //FIXME copy interfaces class level annotations, and make sure we ignore doublons if any
54
ProxyCompilerClassVisitor createProxy = new ProxyDelegationCompiler.ProxyCompilerClassVisitor(
55             proxyWriter,
56             proxyClassName.replace('.', '/'),
57             methodSignatures,
58             interfaceClassNames,
59             interfaceSignatures
60     );
61
62     // visit each interface
63
for (int i = 0; i < interfaces.length; i++) {
64       Class JavaDoc anInterface = interfaces[i];
65       final String JavaDoc interfaceClassName = anInterface.getName().replace('.', '/');
66
67       InputStream JavaDoc in = null;
68       final ClassReader classReader;
69       try {
70         if (loader != null) {
71           in = loader.getResourceAsStream(interfaceClassName + ".class");
72         } else {
73           in = ClassLoader.getSystemClassLoader().getResourceAsStream(interfaceClassName + ".class");
74         }
75         classReader = new ClassReader(in);
76       } catch (IOException JavaDoc e) {
77         throw new WrappedRuntimeException("Cannot compile proxy for " + anInterface, e);
78       } finally {
79         try {
80           in.close();
81         } catch (Throwable JavaDoc t) {
82           ;
83         }
84       }
85       classReader.accept(createProxy, true);// no need for debug info
86
}
87     return proxyWriter.toByteArray();
88   }
89
90   /**
91    * Proxy compiler. Ones can call accept as many times as needed.
92    * visitEnd allow to track the index of the visited interface
93    */

94   public static class ProxyCompilerClassVisitor extends AsmNullAdapter.NullClassAdapter implements Opcodes, TransformationConstants {
95     final ClassVisitor m_proxyCv;
96     final String JavaDoc m_proxyClassName;
97     final Set JavaDoc m_signatures;
98     private int currentInterfaceIndex = 0;
99     final String JavaDoc[] m_interfaceClassNames;
100     final String JavaDoc[] m_interfaceSignatures;
101
102     /**
103      * Create the class, a field per interface, and the single constructor
104      *
105      * @param proxyCv
106      * @param proxyClassName
107      * @param signatures
108      * @param interfaceClassNames
109      */

110     public ProxyCompilerClassVisitor(final ClassVisitor proxyCv, final String JavaDoc proxyClassName, final Set JavaDoc signatures, final String JavaDoc[] interfaceClassNames, final String JavaDoc[] interfaceSignatures) {
111       m_proxyCv = proxyCv;
112       m_proxyClassName = proxyClassName;
113       m_signatures = signatures;
114       m_interfaceClassNames = interfaceClassNames;
115       m_interfaceSignatures = interfaceSignatures;
116
117       m_proxyCv.visit(
118               AsmHelper.JAVA_VERSION,
119               ACC_PUBLIC + ACC_SYNTHETIC + ACC_SUPER,
120               m_proxyClassName,
121               null,
122               OBJECT_CLASS_NAME,
123               interfaceClassNames
124       );
125
126       // create one field per implemented interface
127
for (int i = 0; i < interfaceClassNames.length; i++) {
128         m_interfaceSignatures[i] = 'L' + interfaceClassNames[i] + ';';
129         m_proxyCv.visitField(
130                 ACC_PRIVATE + ACC_SYNTHETIC + ACC_FINAL,
131                 "DELEGATE_" + i,
132                 m_interfaceSignatures[i],
133                 null,
134                 null
135         );
136       }
137
138       // create ctor
139
StringBuffer JavaDoc ctorDesc = new StringBuffer JavaDoc("(");
140       for (int i = 0; i < interfaceClassNames.length; i++) {
141         ctorDesc.append(m_interfaceSignatures[i]);
142       }
143       ctorDesc.append(")V");
144       MethodVisitor init = m_proxyCv.visitMethod(
145               ACC_PUBLIC + ACC_SYNTHETIC,
146               INIT_METHOD_NAME,
147               ctorDesc.toString(),
148               null,
149               null
150       );
151       init.visitVarInsn(ALOAD, 0);
152       init.visitMethodInsn(INVOKESPECIAL, OBJECT_CLASS_NAME, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
153       for (int i = 0; i < interfaceClassNames.length; i++) {
154         init.visitVarInsn(ALOAD, 0);
155         init.visitVarInsn(ALOAD, 1 + i);
156         init.visitFieldInsn(PUTFIELD, m_proxyClassName, "DELEGATE_" + i, m_interfaceSignatures[i]);
157       }
158       init.visitInsn(RETURN);
159       init.visitMaxs(0, 0);
160     }
161
162     /**
163      * Implement the interface method by delegating to the corresponding field
164      *
165      * @param access
166      * @param name
167      * @param desc
168      * @param signature
169      * @param exceptions
170      * @return
171      */

172     public MethodVisitor visitMethod(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc signature, String JavaDoc[] exceptions) {
173       if (m_signatures.contains(name + desc)) {
174         return super.visitMethod(access, name, desc, signature, exceptions);
175       }
176       m_signatures.add(name + desc);
177
178       MethodVisitor cv = m_proxyCv.visitMethod(
179               access & ~ACC_ABSTRACT,
180               name,
181               desc,
182               signature,
183               exceptions
184       );
185
186       cv.visitVarInsn(ALOAD, 0);
187       cv.visitFieldInsn(
188               GETFIELD,
189               m_proxyClassName,
190               "DELEGATE_" + currentInterfaceIndex,
191               m_interfaceSignatures[currentInterfaceIndex]
192       );
193       AsmHelper.loadArgumentTypes(cv, Type.getArgumentTypes(desc), false);
194       cv.visitMethodInsn(
195               INVOKEINTERFACE,
196               m_interfaceClassNames[currentInterfaceIndex],
197               name,
198               desc
199       );
200       AsmHelper.addReturnStatement(cv, Type.getReturnType(desc));
201       cv.visitMaxs(0, 0);
202
203       // as we return cv we will copy the interface[currentInterfaceIndex] current method annotations
204
// which is what we want
205
return cv;
206     }
207
208     /**
209      * Update the interface index for the next accept()
210      */

211     public void visitEnd() {
212       currentInterfaceIndex++;
213       super.visitEnd();
214     }
215   }
216
217 }
218
Popular Tags