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.transform.delegation;
9
10 import org.codehaus.aspectwerkz.definition.SystemDefinition;
11 import org.codehaus.aspectwerkz.expression.ExpressionContext;
12 import org.codehaus.aspectwerkz.expression.PointcutType;
13 import org.codehaus.aspectwerkz.reflect.ClassInfo;
14 import org.codehaus.aspectwerkz.reflect.impl.javassist.JavassistClassInfo;
15 import org.codehaus.aspectwerkz.transform.Context;
16 import org.codehaus.aspectwerkz.transform.TransformationUtil;
17 import org.codehaus.aspectwerkz.transform.Transformer;
18 import org.codehaus.aspectwerkz.transform.TransformationConstants;
19 import org.codehaus.aspectwerkz.transform.TransformationConstants;
20
21 import java.util.Iterator;
22 import java.util.List;
23
24 import javassist.CannotCompileException;
25 import javassist.CtBehavior;
26 import javassist.CtClass;
27 import javassist.CtField;
28 import javassist.CtMethod;
29 import javassist.Modifier;
30 import javassist.NotFoundException;
31 import javassist.bytecode.CodeIterator;
32 import javassist.expr.ExprEditor;
33 import javassist.expr.MethodCall;
34
35 /***
36 * Advises method CALL join points.
37 *
38 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
39 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
40 */
41 public class MethodCallUnTransformer implements Transformer {
42 /***
43 * Transforms the call side pointcuts.
44 *
45 * @param context the transformation context
46 * @param klass the class set.
47 */
48 public void transform(final Context context, final Klass klass) throws NotFoundException, CannotCompileException {
49 List definitions = context.getDefinitions();
50 for (Iterator it = definitions.iterator(); it.hasNext();) {
51 final SystemDefinition definition = (SystemDefinition) it.next();
52 final CtClass ctClass = klass.getCtClass();
53 ClassInfo classInfo = JavassistClassInfo.getClassInfo(ctClass, context.getLoader());
54 if (classFilter(definition, new ExpressionContext(PointcutType.CALL, null, classInfo), ctClass)) {
55 return;
56 }
57 ctClass.instrument(new ExprEditor() {
58 public void edit(MethodCall methodCall) throws CannotCompileException {
59 try {
60 CtBehavior where = null;
61 try {
62 where = methodCall.where();
63 } catch (RuntimeException e) {
64
65 where = ctClass.getClassInitializer();
66 }
67
68
69 if (methodFilterCaller(where)) {
70 return;
71 }
72
73
74 CtMethod calleeMethod = methodCall.getMethod();
75 String calleeClassName = methodCall.getClassName();
76 if (!(calleeMethod.getName().equals("proceedWithCallJoinPoint") && calleeClassName
77 .equals("org.codehaus.aspectwerkz.joinpoint.management.JoinPointManager"))) {
78 return;
79 }
80 System.out.println("found smtg to REMOVE");
81 System.out.println("calleeMethod = " + calleeMethod.getName());
82 System.out.println("calleeClassName = " + calleeClassName);
83 System.out.println("methodCall = " + methodCall.indexOfBytecode());
84 methodCall.replace("{java.lang.System.out.println($args[0]); $_=null;}");
85 try {
86 CodeIterator it = where.getMethodInfo().getCodeAttribute().iterator();
87 it.move(methodCall.indexOfBytecode() - 5);
88 System.out.println("it.get() = " + it.get());
89 it.next();
90 System.out.println("it.get() = " + it.get());
91 it.next();
92 System.out.println("it.get() = " + it.get());
93 it.next();
94 System.out.println("it.get() = " + it.get());
95 it.next();
96 } catch (Throwable t) {
97 t.printStackTrace();
98 }
99 return;
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 } catch (NotFoundException nfe) {
221 nfe.printStackTrace();
222
223
224 }
225 }
226 });
227 }
228
229
230 }
231
232 /***
233 * Creates a new static class field, for the declaring class of the callee method.
234 *
235 * @param ctClass the class
236 * @param ctMethod the method
237 * @return the name of the field
238 */
239 private String addCalleeMethodDeclaringClassField(final CtClass ctClass, final CtMethod ctMethod) throws NotFoundException,
240 CannotCompileException {
241 String fieldName = TransformationConstants.STATIC_CLASS_FIELD
242 + TransformationConstants.DELIMITER
243 + "method"
244 + TransformationConstants.DELIMITER
245 + ctMethod.getDeclaringClass().getName().replace('.', '_');
246 boolean hasField = false;
247 CtField[] fields = ctClass.getDeclaredFields();
248 for (int i = 0; i < fields.length; i++) {
249 CtField field = fields[i];
250 if (field.getName().equals(fieldName)) {
251 hasField = true;
252 break;
253 }
254 }
255 if (!hasField) {
256 CtField field = new CtField(ctClass.getClassPool().get("java.lang.Class"), fieldName, ctClass);
257 field.setModifiers(Modifier.STATIC | Modifier.PRIVATE | Modifier.FINAL);
258 ctClass.addField(field, "java.lang.Class#forName(\""
259 + ctMethod.getDeclaringClass().getName().replace('/', '.')
260 + "\")");
261 }
262 return fieldName;
263 }
264
265 /***
266 * Filters the classes to be transformed.
267 *
268 * @param definition the definition
269 * @param ctx the context
270 * @param cg the class to filter
271 * @return boolean true if the method should be filtered away
272 */
273 public static boolean classFilter(final SystemDefinition definition, final ExpressionContext ctx, final CtClass cg) {
274 if (cg.isInterface()) {
275 return true;
276 }
277 String className = cg.getName().replace('/', '.');
278 if (definition.inExcludePackage(className)) {
279 return true;
280 }
281 if (!definition.inIncludePackage(className)) {
282 return true;
283 }
284 if (definition.isAdvised(ctx)) {
285 return false;
286 }
287 return true;
288 }
289
290 /***
291 * Filters the caller methods.
292 *
293 * @param method the method to filter
294 * @return boolean true if the method should be filtered away
295 */
296 public static boolean methodFilterCaller(final CtBehavior method) {
297 if (Modifier.isNative(method.getModifiers())
298 || Modifier.isInterface(method.getModifiers())
299 || method.getName().equals(TransformationConstants.CLASS_LOOKUP_METHOD)) {
300 return true;
301 } else {
302 return false;
303 }
304 }
305
306 /***
307 * Filters the callee methods.
308 *
309 * @param method the name of method to filter
310 * @return boolean true if the method should be filtered away
311 * @TODO: create metadata instance and check with the system
312 */
313 public static boolean methodFilterCallee(final CtMethod method) {
314 if (method.getName().equals("<init>")
315 || method.getName().equals("<clinit>")
316 || method.getName().startsWith(TransformationConstants.ORIGINAL_METHOD_PREFIX)
317 || method.getName().equals(TransformationConstants.CLASS_LOOKUP_METHOD)) {
318 return true;
319 } else {
320 return false;
321 }
322 }
323 }