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.MemberInfo;
15  import org.codehaus.aspectwerkz.reflect.impl.javassist.JavassistClassInfo;
16  import org.codehaus.aspectwerkz.reflect.impl.javassist.JavassistConstructorInfo;
17  import org.codehaus.aspectwerkz.reflect.impl.javassist.JavassistMethodInfo;
18  import org.codehaus.aspectwerkz.transform.Context;
19  import org.codehaus.aspectwerkz.transform.TransformationUtil;
20  import org.codehaus.aspectwerkz.transform.Transformer;
21  import org.codehaus.aspectwerkz.transform.TransformationConstants;
22  import org.codehaus.aspectwerkz.transform.TransformationConstants;
23  
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import javassist.CannotCompileException;
28  import javassist.CtBehavior;
29  import javassist.CtClass;
30  import javassist.CtConstructor;
31  import javassist.CtMethod;
32  import javassist.Modifier;
33  import javassist.NotFoundException;
34  import javassist.expr.ExprEditor;
35  import javassist.expr.Handler;
36  
37  /***
38   * Advises HANDLER join points.
39   * 
40   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
41   */
42  public class HandlerTransformer implements Transformer {
43      /***
44       * The join point index.
45       */
46  
47      //AXprivate int m_joinPointIndex;
48      /***
49       * Transforms the call side pointcuts.
50       * 
51       * @param context the transformation context
52       * @param klass the class set.
53       */
54      public void transform(final Context context, final Klass klass) throws NotFoundException, CannotCompileException {
55          List definitions = context.getDefinitions();
56  
57          //AXm_joinPointIndex =
58          // TransformationUtil.getJoinPointIndex(klass.getCtClass()); //TODO
59          // thread safe reentrant
60          for (Iterator it = definitions.iterator(); it.hasNext();) {
61              final SystemDefinition definition = (SystemDefinition) it.next();
62              final CtClass ctClass = klass.getCtClass();
63              ClassInfo classInfo = JavassistClassInfo.getClassInfo(ctClass, context.getLoader());
64              if (classFilter(definition, new ExpressionContext(PointcutType.HANDLER, null, classInfo), ctClass)) {
65                  continue;
66              }
67              ctClass.instrument(new ExprEditor() {
68                  public void edit(Handler handlerExpr) throws CannotCompileException {
69                      try {
70                          CtClass exceptionClass = null;
71                          try {
72                              exceptionClass = handlerExpr.getType();
73                          } catch (NullPointerException e) {
74                              return;
75                          }
76                          CtBehavior where = null;
77                          try {
78                              where = handlerExpr.where();
79                          } catch (RuntimeException e) {
80                              // <clinit> access leads to a bug in Javassist
81                              where = ctClass.getClassInitializer();
82                          }
83                          MemberInfo withinMethodInfo = null;
84                          if (where instanceof CtMethod) {
85                              withinMethodInfo = JavassistMethodInfo.getMethodInfo((CtMethod) where, context.getLoader());
86                          } else if (where instanceof CtConstructor) {
87                              withinMethodInfo = JavassistConstructorInfo.getConstructorInfo(
88                                  (CtConstructor) where,
89                                  context.getLoader());
90                          }
91                          ClassInfo exceptionClassInfo = JavassistClassInfo.getClassInfo(exceptionClass, context
92                                  .getLoader());
93                          ExpressionContext ctx = new ExpressionContext(
94                              PointcutType.HANDLER,
95                              exceptionClassInfo,
96                              withinMethodInfo);
97                          if (definition.hasPointcut(ctx)) {
98                              // call the wrapper method instead of the callee
99                              // method
100                             StringBuffer body = new StringBuffer();
101                             body.append(TransformationConstants.JOIN_POINT_MANAGER_FIELD);
102                             body.append('.');
103                             body.append(TransformationConstants.PROCEED_WITH_HANDLER_JOIN_POINT_METHOD);
104                             body.append('(');
105 
106                             // TODO: unique hash is needed, based on: executing
107                             // class, executing method, catch clause (and
108                             // sequence number?)
109                             body.append(JavassistHelper.calculateHash(exceptionClass));
110                             body.append(',');
111                             body.append(klass.getJoinPointIndex());
112                             if (Modifier.isStatic(where.getModifiers())) {
113                                 body.append(", $1, (Object)null, \"");
114                             } else {
115                                 body.append(", $1, this, \"");
116                             }
117 
118                             // TODO: use a better signature (or remove)
119                             body.append(exceptionClass.getName().replace('/', '.'));
120                             body.append("\");");
121                             handlerExpr.insertBefore(body.toString());
122                             context.markAsAdvised();
123                             klass.incrementJoinPointIndex();
124                         }
125                     } catch (NotFoundException nfe) {
126                         nfe.printStackTrace();
127                     }
128                 }
129             });
130         }
131 
132         //TransformationUtil.setJoinPointIndex(klass.getCtClass(),
133         // m_joinPointIndex);
134         klass.flushJoinPointIndex();
135     }
136 
137     /***
138      * Filters the classes to be transformed.
139      * 
140      * @param definition the definition
141      * @param ctx the context
142      * @param cg the class to filter
143      * @return boolean true if the method should be filtered away
144      */
145     public static boolean classFilter(final SystemDefinition definition, final ExpressionContext ctx, final CtClass cg) {
146         if (cg.isInterface()) {
147             return true;
148         }
149         String className = cg.getName().replace('/', '.');
150         if (definition.inExcludePackage(className)) {
151             return true;
152         }
153         if (!definition.inIncludePackage(className)) {
154             return true;
155         }
156         if (definition.isAdvised(ctx)) {
157             return false;
158         }
159         return true;
160     }
161 }