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.InterfaceIntroductionDefinition;
11  import org.codehaus.aspectwerkz.definition.IntroductionDefinition;
12  import org.codehaus.aspectwerkz.definition.SystemDefinition;
13  import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
14  import org.codehaus.aspectwerkz.expression.ExpressionContext;
15  import org.codehaus.aspectwerkz.expression.PointcutType;
16  import org.codehaus.aspectwerkz.reflect.ClassInfo;
17  import org.codehaus.aspectwerkz.reflect.impl.javassist.JavassistClassInfo;
18  import org.codehaus.aspectwerkz.transform.Context;
19  import org.codehaus.aspectwerkz.transform.Transformer;
20  
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import javassist.CtClass;
25  import javassist.NotFoundException;
26  
27  /***
28   * Adds an interfaces to classes.
29   * 
30   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
31   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
32   */
33  public final class AddInterfaceTransformer implements Transformer {
34      /***
35       * Adds an interfaces to the classes specified.
36       * 
37       * @param context the transformation context
38       * @param klass the class
39       */
40      public void transform(final Context context, final Klass klass) {
41          List definitions = context.getDefinitions();
42  
43          // loop over all the definitions
44          for (Iterator it = definitions.iterator(); it.hasNext();) {
45              SystemDefinition definition = (SystemDefinition) it.next();
46              final CtClass ctClass = klass.getCtClass();
47              ClassInfo classInfo = JavassistClassInfo.getClassInfo(ctClass, context.getLoader());
48              ExpressionContext ctx = new ExpressionContext(PointcutType.WITHIN, classInfo, classInfo);
49              if (classFilter(ctClass, ctx, definition)) {
50                  continue;
51              }
52              addInterfaceIntroductions(definition, ctClass, context, ctx);
53          }
54      }
55  
56      /***
57       * Adds the interface introductions to the class.
58       * 
59       * @param definition the definition
60       * @param ctClass the class
61       * @param context the TF context
62       * @param ctx the context
63       */
64      private void addInterfaceIntroductions(
65          final SystemDefinition definition,
66          final CtClass ctClass,
67          final Context context,
68          final ExpressionContext ctx) {
69          boolean isClassAdvised = false;
70          List interfaceIntroDefs = definition.getInterfaceIntroductionDefinitions(ctx);
71          for (Iterator it = interfaceIntroDefs.iterator(); it.hasNext();) {
72              InterfaceIntroductionDefinition introductionDef = (InterfaceIntroductionDefinition) it.next();
73              List interfaceClassNames = introductionDef.getInterfaceClassNames();
74              if (addInterfaces(interfaceClassNames, ctClass)) {
75                  isClassAdvised = true;
76              }
77          }
78          List introDefs = definition.getIntroductionDefinitions(ctx);
79          for (Iterator it = introDefs.iterator(); it.hasNext();) {
80              IntroductionDefinition introductionDef = (IntroductionDefinition) it.next();
81              List interfaceClassNames = introductionDef.getInterfaceClassNames();
82              if (addInterfaces(interfaceClassNames, ctClass)) {
83                  isClassAdvised = true;
84              }
85          }
86          if (isClassAdvised) {
87              context.markAsAdvised();
88  
89              // weaved class might use the added interface to match pointcuts so mark the class info as dirty
90              JavassistClassInfo.markDirty(ctClass, context.getLoader());
91          }
92      }
93  
94      /***
95       * Adds the interfaces to the to target class.
96       * 
97       * @param interfaceClassNames
98       * @param ctClass
99       * @return
100      */
101     private boolean addInterfaces(final List interfaceClassNames, final CtClass ctClass) {
102         boolean isClassAdvised = false;
103         for (Iterator it = interfaceClassNames.iterator(); it.hasNext();) {
104             String className = (String) it.next();
105             if (implementsInterface(ctClass, className)) {
106                 continue;
107             }
108             if (className != null) {
109                 try {
110                     ctClass.addInterface(ctClass.getClassPool().get(className));
111                 } catch (NotFoundException e) {
112                     throw new WrappedRuntimeException(e);
113                 }
114                 isClassAdvised = true;
115             }
116         }
117         return isClassAdvised;
118     }
119 
120     /***
121      * Checks if a class implements an interface.
122      * 
123      * @param ctClass ConstantUtf8 constant
124      * @return true if the class implements the interface
125      */
126     private boolean implementsInterface(final CtClass ctClass, final String interfaceName) {
127         try {
128             CtClass[] interfaces = ctClass.getInterfaces();
129             for (int i = 0; i < interfaces.length; i++) {
130                 if (interfaces[i].getName().replace('/', '.').equals(interfaceName)) {
131                     return true;
132                 }
133             }
134             return false;
135         } catch (NotFoundException e) {
136             throw new WrappedRuntimeException(e);
137         }
138     }
139 
140     /***
141      * Filters the classes to be transformed.
142      * 
143      * @param ctClass the class to filter
144      * @param ctx the context
145      * @param definition the definition
146      * @return boolean true if the method should be filtered away
147      */
148     public static boolean classFilter(
149         final CtClass ctClass,
150         final ExpressionContext ctx,
151         final SystemDefinition definition) {
152         if (ctClass.isInterface()) {
153             return true;
154         }
155         String className = ctClass.getName().replace('/', '.');
156         if (definition.inExcludePackage(className)) {
157             return true;
158         }
159         if (!definition.inIncludePackage(className)) {
160             return true;
161         }
162         if (definition.isIntroduced(ctx) || definition.isInterfaceIntroduced(ctx)) {
163             return false;
164         }
165         return true;
166     }
167 }