KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > transform > impl > InterceptFieldTransformer


1 /*
2  * Copyright 2003 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.transform.impl;
17
18 import net.sf.cglib.transform.*;
19 import net.sf.cglib.core.*;
20 import org.objectweb.asm.ClassVisitor;
21 import org.objectweb.asm.MethodAdapter;
22 import org.objectweb.asm.MethodVisitor;
23 import org.objectweb.asm.Attribute;
24 import org.objectweb.asm.Label;
25 import org.objectweb.asm.Type;
26
27 /**
28  * @author Juozas Baliuka, Chris Nokleberg
29  */

30 public class InterceptFieldTransformer extends ClassEmitterTransformer {
31     private static final String JavaDoc CALLBACK_FIELD = "$CGLIB_READ_WRITE_CALLBACK";
32     private static final Type CALLBACK =
33       TypeUtils.parseType("net.sf.cglib.transform.impl.InterceptFieldCallback");
34     private static final Type ENABLED =
35       TypeUtils.parseType("net.sf.cglib.transform.impl.InterceptFieldEnabled");
36     private static final Signature ENABLED_SET =
37       new Signature("setInterceptFieldCallback", Type.VOID_TYPE, new Type[]{ CALLBACK });
38     private static final Signature ENABLED_GET =
39       new Signature("getInterceptFieldCallback", CALLBACK, new Type[0]);
40
41     private InterceptFieldFilter filter;
42     
43     public InterceptFieldTransformer(InterceptFieldFilter filter) {
44         this.filter = filter;
45     }
46     
47     public void begin_class(int version, int access, String JavaDoc className, Type superType, Type[] interfaces, String JavaDoc sourceFile) {
48         if (!TypeUtils.isInterface(access)) {
49             super.begin_class(version, access, className, superType, TypeUtils.add(interfaces, ENABLED), sourceFile);
50                     
51             super.declare_field(Constants.ACC_PRIVATE | Constants.ACC_TRANSIENT,
52                                 CALLBACK_FIELD,
53                                 CALLBACK,
54                                 null);
55
56             CodeEmitter e;
57             e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_GET, null);
58             e.load_this();
59             e.getfield(CALLBACK_FIELD);
60             e.return_value();
61             e.end_method();
62                 
63             e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_SET, null);
64             e.load_this();
65             e.load_arg(0);
66             e.putfield(CALLBACK_FIELD);
67             e.return_value();
68             e.end_method();
69         } else {
70             super.begin_class(version, access, className, superType, interfaces, sourceFile);
71         }
72     }
73
74     public void declare_field(int access, String JavaDoc name, Type type, Object JavaDoc value) {
75         super.declare_field(access, name, type, value);
76         if (!TypeUtils.isStatic(access)) {
77             if (filter.acceptRead(getClassType(), name)) {
78                 addReadMethod(name, type);
79             }
80             if (filter.acceptWrite(getClassType(), name)) {
81                 addWriteMethod(name, type);
82             }
83         }
84     }
85
86     private void addReadMethod(String JavaDoc name, Type type) {
87         CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
88                                            readMethodSig(name, type.getDescriptor()),
89                                            null);
90         e.load_this();
91         e.getfield(name);
92         e.load_this();
93         e.invoke_interface(ENABLED,ENABLED_GET);
94         Label intercept = e.make_label();
95         e.ifnonnull(intercept);
96         e.return_value();
97
98         e.mark(intercept);
99         Local result = e.make_local(type);
100         e.store_local(result);
101         e.load_this();
102         e.invoke_interface(ENABLED,ENABLED_GET);
103         e.load_this();
104         e.push(name);
105         e.load_local(result);
106         e.invoke_interface(CALLBACK, readCallbackSig(type));
107         if (!TypeUtils.isPrimitive(type)) {
108             e.checkcast(type);
109         }
110         e.return_value();
111         e.end_method();
112     }
113
114     private void addWriteMethod(String JavaDoc name, Type type) {
115         CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
116                                            writeMethodSig(name, type.getDescriptor()),
117                                            null);
118         e.load_this();
119         e.dup();
120         e.invoke_interface(ENABLED,ENABLED_GET);
121         Label skip = e.make_label();
122         e.ifnull(skip);
123
124         e.load_this();
125         e.invoke_interface(ENABLED,ENABLED_GET);
126         e.load_this();
127         e.push(name);
128         e.load_this();
129         e.getfield(name);
130         e.load_arg(0);
131         e.invoke_interface(CALLBACK, writeCallbackSig(type));
132         if (!TypeUtils.isPrimitive(type)) {
133             e.checkcast(type);
134         }
135         Label go = e.make_label();
136         e.goTo(go);
137         e.mark(skip);
138         e.load_arg(0);
139         e.mark(go);
140         e.putfield(name);
141         e.return_value();
142         e.end_method();
143     }
144                 
145     public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
146         return new CodeEmitter(super.begin_method(access, sig, exceptions)) {
147             public void visitFieldInsn(int opcode, String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
148                 Type towner = TypeUtils.fromInternalName(owner);
149                 switch (opcode) {
150                 case Constants.GETFIELD:
151                     if (filter.acceptRead(towner, name)) {
152                         helper(towner, readMethodSig(name, desc));
153                         return;
154                     }
155                     break;
156                 case Constants.PUTFIELD:
157                     if (filter.acceptWrite(towner, name)) {
158                         helper(towner, writeMethodSig(name, desc));
159                         return;
160                     }
161                     break;
162                 }
163                 super.visitFieldInsn(opcode, owner, name, desc);
164             }
165
166             private void helper(Type owner, Signature sig) {
167                 invoke_virtual(owner, sig);
168             }
169         };
170     }
171
172     private static Signature readMethodSig(String JavaDoc name, String JavaDoc desc) {
173         return new Signature("$cglib_read_" + name, "()" + desc);
174     }
175
176     private static Signature writeMethodSig(String JavaDoc name, String JavaDoc desc) {
177         return new Signature("$cglib_write_" + name, "(" + desc + ")V");
178     }
179
180     private static Signature readCallbackSig(Type type) {
181         Type remap = remap(type);
182         return new Signature("read" + callbackName(remap),
183                              remap,
184                              new Type[]{ Constants.TYPE_OBJECT,
185                                          Constants.TYPE_STRING,
186                                          remap });
187     }
188
189     private static Signature writeCallbackSig(Type type) {
190         Type remap = remap(type);
191         return new Signature("write" + callbackName(remap),
192                              remap,
193                              new Type[]{ Constants.TYPE_OBJECT,
194                                          Constants.TYPE_STRING,
195                                          remap,
196                                          remap });
197     }
198
199     private static Type remap(Type type) {
200         switch (type.getSort()) {
201         case Type.OBJECT:
202         case Type.ARRAY:
203             return Constants.TYPE_OBJECT;
204         default:
205             return type;
206         }
207     }
208
209     private static String JavaDoc callbackName(Type type) {
210         return (type == Constants.TYPE_OBJECT) ?
211             "Object" :
212             TypeUtils.upperFirst(TypeUtils.getClassName(type));
213     }
214 }
215
Popular Tags