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
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
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 }