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.inlining.weaver;
9
10 import java.util.Iterator;
11 import java.util.Set;
12 import java.util.HashSet;
13 import java.util.List;
14
15 import org.objectweb.asm.*;
16 import org.codehaus.aspectwerkz.transform.Context;
17 import org.codehaus.aspectwerkz.transform.TransformationConstants;
18 import org.codehaus.aspectwerkz.transform.TransformationUtil;
19 import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
20 import org.codehaus.aspectwerkz.definition.SystemDefinition;
21 import org.codehaus.aspectwerkz.definition.InterfaceIntroductionDefinition;
22 import org.codehaus.aspectwerkz.definition.MixinDefinition;
23 import org.codehaus.aspectwerkz.expression.ExpressionContext;
24 import org.codehaus.aspectwerkz.expression.PointcutType;
25 import org.codehaus.aspectwerkz.reflect.ClassInfo;
26 import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
27
28 /***
29 * Adds an interface to the target class.
30 *
31 * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
32 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
33 */
34 public class AddInterfaceVisitor extends ClassAdapter implements TransformationConstants {
35
36 private final static String ADVISABLE_MIXIN_IMPL_NAME = "org.codehaus.aspectwerkz.intercept.AdvisableImpl";
37
38 private final ContextImpl m_ctx;
39 private final ClassInfo m_classInfo;
40
41 /***
42 * Creates a new add interface class adapter.
43 *
44 * @param cv
45 * @param classInfo
46 * @param ctx
47 */
48 public AddInterfaceVisitor(final ClassVisitor cv,
49 final ClassInfo classInfo,
50 final Context ctx) {
51 super(cv);
52 m_classInfo = classInfo;
53 m_ctx = (ContextImpl) ctx;
54 }
55
56 /***
57 * Visits the class.
58 *
59 * @param access
60 * @param name
61 * @param superName
62 * @param interfaces
63 * @param sourceFile
64 */
65 public void visit(final int version,
66 final int access,
67 final String name,
68 final String superName,
69 final String[] interfaces,
70 final String sourceFile) {
71 ExpressionContext ctx = new ExpressionContext(PointcutType.WITHIN, m_classInfo, m_classInfo);
72 if (classFilter(m_classInfo, ctx, m_ctx.getDefinitions())) {
73 super.visit(version, access, name, superName, interfaces, sourceFile);
74 return;
75 }
76
77
78
79 final Set interfacesToAdd = new HashSet();
80
81
82 for (int i = 0; i < interfaces.length; i++) {
83 interfacesToAdd.add(interfaces[i].replace('/', '.'));
84 }
85
86
87 final Set systemDefinitions = m_ctx.getDefinitions();
88 for (Iterator it = systemDefinitions.iterator(); it.hasNext();) {
89 SystemDefinition systemDefinition = (SystemDefinition) it.next();
90 final List interfaceIntroDefs = systemDefinition.getInterfaceIntroductionDefinitions(ctx);
91 for (Iterator it2 = interfaceIntroDefs.iterator(); it2.hasNext();) {
92 final InterfaceIntroductionDefinition interfaceIntroDef = (InterfaceIntroductionDefinition) it2.next();
93 interfacesToAdd.addAll(interfaceIntroDef.getInterfaceClassNames());
94 }
95 final List mixinDefinitions = systemDefinition.getMixinDefinitions(ctx);
96 for (Iterator it2 = mixinDefinitions.iterator(); it2.hasNext();) {
97 final MixinDefinition mixinDef = (MixinDefinition) it2.next();
98 if (ADVISABLE_MIXIN_IMPL_NAME.equals(mixinDef.getMixinImpl().getName())) {
99
100 m_ctx.markMadeAdvisable();
101 }
102 final List interfaceList = mixinDef.getInterfaceClassNames();
103 for (Iterator it3 = interfaceList.iterator(); it3.hasNext();) {
104 interfacesToAdd.add(((String) it3.next()));
105 }
106 }
107 }
108
109 if (ClassInfoHelper.hasMethodClash(interfacesToAdd, m_ctx.getLoader())) {
110 super.visit(version, access, name, superName, interfaces, sourceFile);
111 return;
112 }
113
114 int i = 0;
115 final String[] newInterfaceArray = new String[interfacesToAdd.size()];
116 for (Iterator it = interfacesToAdd.iterator(); it.hasNext();) {
117 newInterfaceArray[i++] = (String) it.next();
118 }
119
120 for (int j = 0; j < newInterfaceArray.length; j++) {
121 newInterfaceArray[j] = newInterfaceArray[j].replace('.', '/');
122
123 }
124 super.visit(version, access, name, superName, newInterfaceArray, sourceFile);
125 m_ctx.markAsAdvised();
126 }
127
128 /***
129 * Filters the classes to be transformed.
130 *
131 * @param classInfo the class to filter
132 * @param ctx the context
133 * @param definitions a set with the definitions
134 * @return boolean true if the method should be filtered away
135 */
136 public static boolean classFilter(final ClassInfo classInfo,
137 final ExpressionContext ctx,
138 final Set definitions) {
139 for (Iterator it = definitions.iterator(); it.hasNext();) {
140 SystemDefinition systemDef = (SystemDefinition) it.next();
141 if (classInfo.isInterface()) {
142 return true;
143 }
144 String className = classInfo.getName().replace('/', '.');
145 if (systemDef.inExcludePackage(className)) {
146 return true;
147 }
148 if (!systemDef.inIncludePackage(className)) {
149 return true;
150 }
151 if (systemDef.hasMixin(ctx) || systemDef.hasIntroducedInterface(ctx)) {
152 return false;
153 }
154 }
155 return true;
156 }
157 }