View Javadoc

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 }