KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > proxy > MethodInterceptorGenerator


1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.sf.cglib.proxy;
17
18 import java.lang.reflect.Method JavaDoc;
19 import java.util.*;
20 import net.sf.cglib.core.*;
21 import org.objectweb.asm.Label;
22 import org.objectweb.asm.Type;
23
24 class MethodInterceptorGenerator
25 implements CallbackGenerator
26 {
27     public static final MethodInterceptorGenerator INSTANCE = new MethodInterceptorGenerator();
28
29     static final String JavaDoc EMPTY_ARGS_NAME = "CGLIB$emptyArgs";
30     static final String JavaDoc FIND_PROXY_NAME = "CGLIB$findMethodProxy";
31     static final Class JavaDoc[] FIND_PROXY_TYPES = { Signature.class };
32
33     private static final Type ABSTRACT_METHOD_ERROR =
34       TypeUtils.parseType("AbstractMethodError");
35     private static final Type METHOD =
36       TypeUtils.parseType("java.lang.reflect.Method");
37     private static final Type REFLECT_UTILS =
38       TypeUtils.parseType("net.sf.cglib.core.ReflectUtils");
39     private static final Type METHOD_PROXY =
40       TypeUtils.parseType("net.sf.cglib.proxy.MethodProxy");
41     private static final Type METHOD_INTERCEPTOR =
42       TypeUtils.parseType("net.sf.cglib.proxy.MethodInterceptor");
43     private static final Signature GET_DECLARED_METHODS =
44       TypeUtils.parseSignature("java.lang.reflect.Method[] getDeclaredMethods()");
45     private static final Signature GET_DECLARING_CLASS =
46       TypeUtils.parseSignature("Class getDeclaringClass()");
47     private static final Signature FIND_METHODS =
48       TypeUtils.parseSignature("java.lang.reflect.Method[] findMethods(String[], java.lang.reflect.Method[])");
49     private static final Signature MAKE_PROXY =
50       new Signature("create", METHOD_PROXY, new Type[]{
51           Constants.TYPE_CLASS,
52           Constants.TYPE_CLASS,
53           Constants.TYPE_STRING,
54           Constants.TYPE_STRING,
55           Constants.TYPE_STRING
56       });
57     private static final Signature INTERCEPT =
58       new Signature("intercept", Constants.TYPE_OBJECT, new Type[]{
59           Constants.TYPE_OBJECT,
60           METHOD,
61           Constants.TYPE_OBJECT_ARRAY,
62           METHOD_PROXY
63       });
64     private static final Signature FIND_PROXY =
65       new Signature(FIND_PROXY_NAME, METHOD_PROXY, new Type[]{ Constants.TYPE_SIGNATURE });
66     private static final Signature TO_STRING =
67       TypeUtils.parseSignature("String toString()");
68     private static final Transformer METHOD_TO_CLASS = new Transformer(){
69         public Object JavaDoc transform(Object JavaDoc value) {
70             return ((MethodInfo)value).getClassInfo();
71         }
72     };
73     private static final Signature CSTRUCT_SIGNATURE =
74         TypeUtils.parseConstructor("String, String");
75
76     private String JavaDoc getMethodField(Signature impl) {
77         return impl.getName() + "$Method";
78     }
79     private String JavaDoc getMethodProxyField(Signature impl) {
80         return impl.getName() + "$Proxy";
81     }
82
83     public void generate(ClassEmitter ce, Context context, List methods) {
84         Map sigMap = new HashMap();
85         for (Iterator it = methods.iterator(); it.hasNext();) {
86             MethodInfo method = (MethodInfo)it.next();
87             Signature sig = method.getSignature();
88             Signature impl = context.getImplSignature(method);
89
90             String JavaDoc methodField = getMethodField(impl);
91             String JavaDoc methodProxyField = getMethodProxyField(impl);
92
93             sigMap.put(sig.toString(), methodProxyField);
94             ce.declare_field(Constants.PRIVATE_FINAL_STATIC, methodField, METHOD, null);
95             ce.declare_field(Constants.PRIVATE_FINAL_STATIC, methodProxyField, METHOD_PROXY, null);
96             ce.declare_field(Constants.PRIVATE_FINAL_STATIC, EMPTY_ARGS_NAME, Constants.TYPE_OBJECT_ARRAY, null);
97             CodeEmitter e;
98
99             // access method
100
e = ce.begin_method(Constants.ACC_FINAL,
101                                 impl,
102                                 method.getExceptionTypes());
103             superHelper(e, method);
104             e.return_value();
105             e.end_method();
106
107             // around method
108
e = context.beginMethod(ce, method);
109             Label nullInterceptor = e.make_label();
110             context.emitCallback(e, context.getIndex(method));
111             e.dup();
112             e.ifnull(nullInterceptor);
113
114             e.load_this();
115             e.getfield(methodField);
116             
117             if (sig.getArgumentTypes().length == 0) {
118                 e.getfield(EMPTY_ARGS_NAME);
119             } else {
120                 e.create_arg_array();
121             }
122             
123             e.getfield(methodProxyField);
124             e.invoke_interface(METHOD_INTERCEPTOR, INTERCEPT);
125             e.unbox_or_zero(sig.getReturnType());
126             e.return_value();
127
128             e.mark(nullInterceptor);
129             superHelper(e, method);
130             e.return_value();
131             e.end_method();
132         }
133         generateFindProxy(ce, sigMap);
134     }
135
136     private static void superHelper(CodeEmitter e, MethodInfo method)
137     {
138         if (TypeUtils.isAbstract(method.getModifiers())) {
139             e.throw_exception(ABSTRACT_METHOD_ERROR, method.toString() + " is abstract" );
140         } else {
141             e.load_this();
142             e.load_args();
143             e.super_invoke(method.getSignature());
144         }
145     }
146
147     public void generateStatic(CodeEmitter e, Context context, List methods) throws Exception JavaDoc {
148         /* generates:
149            static {
150              Class thisClass = Class.forName("NameOfThisClass");
151              Class cls = Class.forName("java.lang.Object");
152              String[] sigs = new String[]{ "toString", "()Ljava/lang/String;", ... };
153              Method[] methods = cls.getDeclaredMethods();
154              methods = ReflectUtils.findMethods(sigs, methods);
155              METHOD_0 = methods[0];
156              CGLIB$ACCESS_0 = MethodProxy.create(cls, thisClass, "()Ljava/lang/String;", "toString", "CGLIB$ACCESS_0");
157              ...
158            }
159         */

160
161         e.push(0);
162         e.newarray();
163         e.putfield(EMPTY_ARGS_NAME);
164
165         Local thisclass = e.make_local();
166         Local declaringclass = e.make_local();
167         EmitUtils.load_class_this(e);
168         e.store_local(thisclass);
169         
170         Map methodsByClass = CollectionUtils.bucket(methods, METHOD_TO_CLASS);
171         for (Iterator i = methodsByClass.keySet().iterator(); i.hasNext();) {
172             ClassInfo classInfo = (ClassInfo)i.next();
173
174             List classMethods = (List)methodsByClass.get(classInfo);
175             e.push(2 * classMethods.size());
176             e.newarray(Constants.TYPE_STRING);
177             for (int index = 0; index < classMethods.size(); index++) {
178                 MethodInfo method = (MethodInfo)classMethods.get(index);
179                 Signature sig = method.getSignature();
180                 e.dup();
181                 e.push(2 * index);
182                 e.push(sig.getName());
183                 e.aastore();
184                 e.dup();
185                 e.push(2 * index + 1);
186                 e.push(sig.getDescriptor());
187                 e.aastore();
188             }
189             
190             EmitUtils.load_class(e, classInfo.getType());
191             e.dup();
192             e.store_local(declaringclass);
193             e.invoke_virtual(Constants.TYPE_CLASS, GET_DECLARED_METHODS);
194             e.invoke_static(REFLECT_UTILS, FIND_METHODS);
195
196             for (int index = 0; index < classMethods.size(); index++) {
197                 MethodInfo method = (MethodInfo)classMethods.get(index);
198                 Signature sig = method.getSignature();
199                 Signature impl = context.getImplSignature(method);
200                 e.dup();
201                 e.push(index);
202                 e.array_load(METHOD);
203                 e.putfield(getMethodField(impl));
204
205                 e.load_local(declaringclass);
206                 e.load_local(thisclass);
207                 e.push(sig.getDescriptor());
208                 e.push(sig.getName());
209                 e.push(impl.getName());
210                 e.invoke_static(METHOD_PROXY, MAKE_PROXY);
211                 e.putfield(getMethodProxyField(impl));
212             }
213             e.pop();
214         }
215     }
216
217     public void generateFindProxy(ClassEmitter ce, final Map sigMap) {
218         final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
219                                               FIND_PROXY,
220                                               null);
221         e.load_arg(0);
222         e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
223         ObjectSwitchCallback callback = new ObjectSwitchCallback() {
224             public void processCase(Object JavaDoc key, Label end) {
225                 e.getfield((String JavaDoc)sigMap.get(key));
226                 e.return_value();
227             }
228             public void processDefault() {
229                 e.aconst_null();
230                 e.return_value();
231             }
232         };
233         EmitUtils.string_switch(e,
234                                 (String JavaDoc[])sigMap.keySet().toArray(new String JavaDoc[0]),
235                                 Constants.SWITCH_STYLE_HASH,
236                                 callback);
237         e.end_method();
238     }
239 }
240
Popular Tags