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 // <clinit> access leads to a bug in Javassist
65 where = ctClass.getClassInitializer();
66 }
67
68 // filter caller methods
69 if (methodFilterCaller(where)) {
70 return;
71 }
72
73 // get the callee method name, signature and class name
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 // // filter callee methods
103 // if (methodFilterCallee(calleeMethod)) {
104 // return;
105 // }
106 //
107 // // create the class meta-data
108 // ClassMetaData calleeSideClassMetaData;
109 // try {
110 // calleeSideClassMetaData =
111 // JavassistMetaDataMaker.createClassMetaData(
112 // context.getClassPool().get(calleeClassName)
113 // );
114 // }
115 // catch (NotFoundException e) {
116 // throw new WrappedRuntimeException(e);
117 // }
118 //
119 // // create the method meta-data
120 // MethodMetaData calleeSideMethodMetaData =
121 // JavassistMetaDataMaker.createMethodMetaData(
122 // methodCall.getMethod()
123 // );
124 //
125 // // is this a caller side method pointcut?
126 // if (definition.isPickedOutByCallPointcut(
127 // calleeSideClassMetaData, calleeSideMethodMetaData
128 // )) {
129 //
130 //// // TODO: should this caller data be passed to the
131 // join point? It is possible.
132 //// String callerMethodName =
133 // callerBehaviour.getName();
134 //// String callerMethodSignature =
135 // callerBehaviour.getSignature();
136 //// CtClass[] callerMethodParameterTypes =
137 // callerBehaviour.getParameterTypes();
138 //// int callerMethodModifiers =
139 // callerBehaviour.getModifiers();
140 //
141 // // check the callee class is not the same as target
142 // class, if that is the case
143 // // then we have have class loaded and set in the
144 // ___AW_clazz already
145 // String declaringClassMethodName =
146 // TransformationUtil.STATIC_CLASS_FIELD;
147 // CtMethod method = methodCall.getMethod();
148 // CtClass declaringClass = method.getDeclaringClass();
149 // if (!declaringClass.getName().replace('/',
150 // '.').equals(where.getDeclaringClass().getName().replace('/',
151 // '.'))) {
152 // declaringClassMethodName =
153 // addCalleeMethodDeclaringClassField(ctClass, method);
154 // }
155 //
156 // // call the wrapper method instead of the callee
157 // method
158 // StringBuffer body = new StringBuffer();
159 // StringBuffer callBody = new StringBuffer();
160 //
161 // callBody.append(TransformationUtil.JOIN_POINT_MANAGER_FIELD);
162 // callBody.append('.');
163 // callBody.append(TransformationUtil.PROCEED_WITH_CALL_JOIN_POINT_METHOD);
164 // callBody.append('(');
165 // callBody.append(TransformationUtil.calculateHash(method));
166 // callBody.append(',');
167 // callBody.append(1);
168 // callBody.append(", args");
169 // callBody.append(", $0, declaringClassMethodName, ");
170 // callBody.append(TransformationUtil.JOIN_POINT_TYPE_METHOD_CALL);
171 // callBody.append(");");
172 //
173 // body.append('{');
174 // if (method.getParameterTypes().length > 0) {
175 // body.append("Object[] args = $args; ");
176 // }
177 // else {
178 // body.append("Object[] args = null; ");
179 // }
180 // body.append("Class declaringClassMethodName = ");
181 // body.append(declaringClassMethodName);
182 // body.append("; ");
183 //
184 // if (methodCall.getMethod().getReturnType() ==
185 // CtClass.voidType) {
186 // body.append("$_ =
187 // ").append(callBody.toString()).append("}");
188 // }
189 // else if
190 // (!methodCall.getMethod().getReturnType().isPrimitive())
191 // {
192 // body.append("$_ = ($r)");
193 // body.append(callBody.toString());
194 // body.append("}");
195 // }
196 // else {
197 // String localResult =
198 // TransformationUtil.ASPECTWERKZ_PREFIX + "res";
199 // body.append("Object ").append(localResult).append(" =
200 // ");
201 // body.append(callBody.toString());
202 // body.append("if (").append(localResult).append(" !=
203 // null)");
204 // body.append("$_ = ($r)
205 // ").append(localResult).append("; else ");
206 // body.append("$_ = ");
207 // body.append(
208 // JavassistHelper.getDefaultPrimitiveValue(
209 // methodCall.getMethod().getReturnType()
210 // )
211 // );
212 // body.append("; }");
213 // }
214 //
215 // methodCall.replace(body.toString());
216 // context.markAsAdvised();
217 //
218 // //1++;
219 // }
220 } catch (NotFoundException nfe) {
221 nfe.printStackTrace();
222
223 // TODO: should we swallow this exception?
224 }
225 }
226 });
227 }
228
229 //TransformationUtil.setJoinPointIndex(klass.getCtClass(), 1);
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 }