001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.transform.inlining.weaver;
005:
006: import com.tc.asm.ClassAdapter;
007: import com.tc.asm.ClassVisitor;
008:
009: import com.tc.aspectwerkz.definition.InterfaceIntroductionDefinition;
010: import com.tc.aspectwerkz.definition.MixinDefinition;
011: import com.tc.aspectwerkz.definition.SystemDefinition;
012: import com.tc.aspectwerkz.transform.InstrumentationContext;
013: import com.tc.aspectwerkz.transform.TransformationConstants;
014: import com.tc.aspectwerkz.reflect.ClassInfo;
015: import com.tc.aspectwerkz.expression.ExpressionContext;
016: import com.tc.aspectwerkz.expression.PointcutType;
017:
018: import java.util.HashSet;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Set;
022:
023: /**
024: * Adds an interface to the target class.
025: *
026: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
027: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
028: */
029: public class AddInterfaceVisitor extends ClassAdapter implements
030: TransformationConstants {
031:
032: private final static String ADVISABLE_MIXIN_IMPL_NAME = "com.tc.aspectwerkz.intercept.AdvisableImpl";
033:
034: private final InstrumentationContext m_ctx;
035: private final ClassInfo m_classInfo;
036:
037: /**
038: * Creates a new add interface class adapter.
039: *
040: * @param cv
041: * @param classInfo
042: * @param ctx
043: */
044: public AddInterfaceVisitor(final ClassVisitor cv,
045: final ClassInfo classInfo, final InstrumentationContext ctx) {
046: super (cv);
047: m_classInfo = classInfo;
048: m_ctx = (InstrumentationContext) ctx;
049: }
050:
051: /**
052: * Visits the class.
053: *
054: * @param access
055: * @param name
056: * @param signature
057: * @param superName
058: * @param interfaces
059: */
060: public void visit(final int version, final int access,
061: final String name, final String signature,
062: final String super Name, final String[] interfaces) {
063: ExpressionContext ctx = new ExpressionContext(
064: PointcutType.WITHIN, m_classInfo, m_classInfo);
065: if (classFilter(m_classInfo, ctx, m_ctx.getDefinitions())) {
066: super .visit(version, access, name, signature, super Name,
067: interfaces);
068: return;
069: }
070:
071: // javaclass names of interface to have
072: // use a Set to avoid doublons
073: final Set interfacesToAdd = new HashSet();
074:
075: // already there interface javaclass names
076: for (int i = 0; i < interfaces.length; i++) {
077: interfacesToAdd.add(interfaces[i].replace('/', '.'));
078: }
079:
080: // add new ones
081: final Set systemDefinitions = m_ctx.getDefinitions();
082: for (Iterator it = systemDefinitions.iterator(); it.hasNext();) {
083: SystemDefinition systemDefinition = (SystemDefinition) it
084: .next();
085: final List interfaceIntroDefs = systemDefinition
086: .getInterfaceIntroductionDefinitions(ctx);
087: for (Iterator it2 = interfaceIntroDefs.iterator(); it2
088: .hasNext();) {
089: final InterfaceIntroductionDefinition interfaceIntroDef = (InterfaceIntroductionDefinition) it2
090: .next();
091: interfacesToAdd.addAll(interfaceIntroDef
092: .getInterfaceClassNames());
093: }
094: final List mixinDefinitions = systemDefinition
095: .getMixinDefinitions(ctx);
096: for (Iterator it2 = mixinDefinitions.iterator(); it2
097: .hasNext();) {
098: final MixinDefinition mixinDef = (MixinDefinition) it2
099: .next();
100: if (ADVISABLE_MIXIN_IMPL_NAME.equals(mixinDef
101: .getMixinImpl().getName())) {
102: // mark it as made advisable
103: m_ctx.markMadeAdvisable();
104: }
105: final List interfaceList = mixinDef
106: .getInterfaceClassNames();
107: for (Iterator it3 = interfaceList.iterator(); it3
108: .hasNext();) {
109: interfacesToAdd.add(it3.next());
110: }
111: }
112: }
113:
114: //TODO refactor to handle precedence injection
115: // if (ClassInfoHelper.hasMethodClash(interfacesToAdd, m_ctx.getLoader())) {
116: // super.visit(version, access, name, superName, interfaces, sourceFile);
117: // return;
118: // }
119:
120: int i = 0;
121: final String[] newInterfaceArray = new String[interfacesToAdd
122: .size()];
123: for (Iterator it = interfacesToAdd.iterator(); it.hasNext();) {
124: newInterfaceArray[i++] = (String) it.next();
125: }
126:
127: for (int j = 0; j < newInterfaceArray.length; j++) {
128: newInterfaceArray[j] = newInterfaceArray[j].replace('.',
129: '/');
130:
131: }
132: super .visit(version, access, name, signature, super Name,
133: newInterfaceArray);
134: m_ctx.markAsAdvised();
135: }
136:
137: /**
138: * Filters the classes to be transformed.
139: *
140: * @param classInfo the class to filter
141: * @param ctx the context
142: * @param definitions a set with the definitions
143: * @return boolean true if the method should be filtered away
144: */
145: public static boolean classFilter(final ClassInfo classInfo,
146: final ExpressionContext ctx, final Set definitions) {
147: for (Iterator it = definitions.iterator(); it.hasNext();) {
148: SystemDefinition systemDef = (SystemDefinition) it.next();
149: if (classInfo.isInterface()) {
150: return true;
151: }
152: String className = classInfo.getName().replace('/', '.');
153: if (systemDef.inExcludePackage(className)) {
154: return true;
155: }
156: if (!systemDef.inIncludePackage(className)) {
157: return true;
158: }
159: if (systemDef.hasMixin(ctx)
160: || systemDef.hasIntroducedInterface(ctx)) {
161: return false;
162: }
163: }
164: return true;
165: }
166: }
|