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.ConstructorInfo;
15  import org.codehaus.aspectwerkz.reflect.impl.javassist.JavassistClassInfo;
16  import org.codehaus.aspectwerkz.reflect.impl.javassist.JavassistConstructorInfo;
17  import org.codehaus.aspectwerkz.transform.Context;
18  import org.codehaus.aspectwerkz.transform.TransformationUtil;
19  import org.codehaus.aspectwerkz.transform.Transformer;
20  import org.codehaus.aspectwerkz.transform.TransformationConstants;
21  import org.codehaus.aspectwerkz.transform.TransformationConstants;
22  
23  import java.util.Iterator;
24  import java.util.List;
25  
26  import javassist.CannotCompileException;
27  import javassist.CtClass;
28  import javassist.CtConstructor;
29  import javassist.CtMethod;
30  import javassist.CtNewConstructor;
31  import javassist.NotFoundException;
32  import javassist.bytecode.CodeAttribute;
33  
34  /***
35   * Advises constructor EXECUTION join points.
36   * 
37   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
38   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
39   */
40  public class ConstructorExecutionTransformer implements Transformer {
41      /***
42       * The join point index.
43       */
44  
45      //AXprivate int m_joinPointIndex;
46      /***
47       * Makes the member method transformations.
48       * 
49       * @param context the transformation context
50       * @param klass the class set.
51       */
52      public void transform(final Context context, final Klass klass) throws Exception {
53          List definitions = context.getDefinitions();
54  
55          //AXm_joinPointIndex =
56          // TransformationUtil.getJoinPointIndex(klass.getCtClass()); //TODO
57          // thread safe and reentrant
58          for (Iterator it = definitions.iterator(); it.hasNext();) {
59              SystemDefinition definition = (SystemDefinition) it.next();
60              final CtClass ctClass = klass.getCtClass();
61              ClassInfo classInfo = JavassistClassInfo.getClassInfo(ctClass, context.getLoader());
62              if (classFilter(definition, new ExpressionContext(PointcutType.EXECUTION, classInfo, classInfo), ctClass)) {
63                  continue;
64              }
65              final CtConstructor[] constructors = ctClass.getConstructors();
66              for (int i = 0; i < constructors.length; i++) {
67                  CtConstructor constructor = constructors[i];
68                  ConstructorInfo constructorInfo = JavassistConstructorInfo.getConstructorInfo(constructor, context
69                          .getLoader());
70                  ExpressionContext ctx = new ExpressionContext(PointcutType.EXECUTION, constructorInfo, constructorInfo);
71                  if (constructorFilter(definition, ctx)) {
72                      continue;
73                  }
74                  if (addPrefixToConstructor(ctClass, constructor)) {
75                      context.markAsAdvised();
76                      int constructorHash = JavassistHelper.calculateHash(constructor);
77                      createWrapperConstructor(constructor, constructorHash, klass);
78                  }
79              }
80          }
81  
82          //AXTransformationUtil.setJoinPointIndex(klass.getCtClass(),
83          // m_joinPointIndex);
84          klass.flushJoinPointIndex();
85      }
86  
87      /***
88       * Creates a wrapper constructor for the original constructor specified. This constructor has the same signature as
89       * the original constructor and catches the invocation for further processing by the framework before redirecting to
90       * the original constructor.
91       * 
92       * @param originalConstructor the original constructor
93       * @param constructorHash the constructor hash
94       */
95      private void createWrapperConstructor(
96          final CtConstructor originalConstructor,
97          final int constructorHash,
98          final Klass klass) throws CannotCompileException, NotFoundException {
99          StringBuffer body = new StringBuffer();
100         body.append('{');
101         if (originalConstructor.getParameterTypes().length > 0) {
102             body.append("Object[] args = $args; ");
103         } else {
104             body.append("Object[] args = null; ");
105         }
106         body.append("Object nullObject = null;");
107         body.append("return ($r)");
108         body.append(TransformationConstants.JOIN_POINT_MANAGER_FIELD);
109         body.append('.');
110         body.append(TransformationConstants.PROCEED_WITH_EXECUTION_JOIN_POINT_METHOD);
111         body.append('(');
112         body.append(constructorHash);
113         body.append(',');
114         body.append(klass.getJoinPointIndex());
115         body.append(',');
116         body.append("args, this,");
117         body.append(TransformationConstants.JOIN_POINT_TYPE_CONSTRUCTOR_EXECUTION);
118         body.append("); }");
119         klass.incrementJoinPointIndex();
120         originalConstructor.setBody(body.toString());
121     }
122 
123     /***
124      * @param ctClass the class
125      * @param constructor the current method
126      * @return the new prefixed constructor
127      */
128 
129     //    private void createStaticMethodWithConstructorBody(
130     //            final CtClass ctClass,
131     //            final CtConstructor constructor,
132     //            final int methodSequence) throws NotFoundException,
133     // CannotCompileException {
134     //
135     //        String prefixedMethodName = TransformationUtil.getPrefixedOriginalMethodName(
136     //                constructor.getName(), methodSequence, ctClass.getName()
137     //        );
138     //
139     //        CtMethod method = CtNewMethod.make(
140     //                CtClass.voidType, prefixedMethodName, constructor.getParameterTypes(),
141     //                constructor.getExceptionTypes(), null, ctClass
142     //        );
143     //        method.setModifiers(Modifier.STATIC | Modifier.FINAL);
144     //
145     //        CodeAttribute codeAttribute =
146     // constructor.getMethodInfo().getCodeAttribute();
147     //        method.getMethodInfo().setCodeAttribute(codeAttribute);
148     //
149     //// CodeAttribute codeAttribute =
150     // method.getMethodInfo().getCodeAttribute();
151     //// codeAttribute.setMaxLocals(codeAttribute.getMaxLocals() + 1);
152     //
153     //        ctClass.addMethod(method);
154     //    }
155     /***
156      * Adds a prefix to the original constructor. To make it callable only from within the framework itself.
157      * 
158      * @param ctClass the class
159      * @param constructor the current method
160      * @return false if the prefixed constructor was already existing
161      */
162     private boolean addPrefixToConstructor(final CtClass ctClass, final CtConstructor constructor) throws NotFoundException,
163             CannotCompileException {
164         int accessFlags = constructor.getModifiers();
165         CtClass[] parameterTypes = constructor.getParameterTypes();
166         CtClass[] newParameterTypes = new CtClass[parameterTypes.length + 1];
167         for (int i = 0; i < parameterTypes.length; i++) {
168             newParameterTypes[i] = parameterTypes[i];
169         }
170         newParameterTypes[parameterTypes.length] = ctClass.getClassPool().get(
171             TransformationConstants.JOIN_POINT_MANAGER_CLASS);
172         if (!JavassistHelper.hasConstructor(ctClass, newParameterTypes)) {
173             CtConstructor newConstructor = CtNewConstructor.make(
174                 newParameterTypes,
175                 constructor.getExceptionTypes(),
176                 CtNewConstructor.PASS_NONE,
177                 null,
178                 CtMethod.ConstParameter.string(constructor.getSignature()),
179                 ctClass);
180             newConstructor.setBody(constructor, null);
181             newConstructor.setModifiers(accessFlags);
182             CodeAttribute codeAttribute = newConstructor.getMethodInfo().getCodeAttribute();
183             codeAttribute.setMaxLocals(codeAttribute.getMaxLocals() + 1);
184             JavassistHelper.copyCustomAttributes(constructor, newConstructor);
185             ctClass.addConstructor(newConstructor);
186             return true;
187         } else {
188             return false;
189         }
190     }
191 
192     /***
193      * Filters the classes to be transformed.
194      * 
195      * @param definition the definition
196      * @param ctx the context
197      * @param ctClass the class to filter
198      * @return boolean true if the method should be filtered away
199      */
200     public static boolean classFilter(
201         final SystemDefinition definition,
202         final ExpressionContext ctx,
203         final CtClass ctClass) {
204         if (ctClass.isInterface()) {
205             return true;
206         }
207         String className = ctClass.getName().replace('/', '.');
208         if (definition.inExcludePackage(className)) {
209             return true;
210         }
211         if (!definition.inIncludePackage(className)) {
212             return true;
213         }
214         if (definition.isAdvised(ctx)) {
215             return false;
216         }
217         return true;
218     }
219 
220     /***
221      * Filters the methods to be transformed.
222      * 
223      * @param definition the definition
224      * @param ctx the context
225      * @return boolean
226      */
227     public static boolean constructorFilter(final SystemDefinition definition, final ExpressionContext ctx) {
228         if (definition.hasPointcut(ctx)) {
229             return false;
230         } else {
231             return true;
232         }
233     }
234 }