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;
005:
006: import java.util.HashSet;
007: import java.util.Iterator;
008: import java.util.Set;
009:
010: import com.tc.asm.ClassReader;
011: import com.tc.asm.ClassVisitor;
012: import com.tc.asm.ClassWriter;
013:
014: import com.tc.aspectwerkz.definition.SystemDefinition;
015: import com.tc.aspectwerkz.exception.WrappedRuntimeException;
016: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
017: import com.tc.aspectwerkz.reflect.ClassInfo;
018: import com.tc.aspectwerkz.transform.InstrumentationContext;
019: import com.tc.aspectwerkz.transform.WeavingStrategy;
020: import com.tc.aspectwerkz.transform.inlining.weaver.AddInterfaceVisitor;
021: import com.tc.aspectwerkz.transform.inlining.weaver.AddMixinMethodsVisitor;
022: import com.tc.aspectwerkz.transform.inlining.weaver.AddWrapperVisitor;
023: import com.tc.aspectwerkz.transform.inlining.weaver.JoinPointInitVisitor;
024: import com.tc.aspectwerkz.transform.inlining.weaver.MethodExecutionVisitor;
025: import com.tc.aspectwerkz.expression.ExpressionContext;
026: import com.tc.aspectwerkz.expression.PointcutType;
027:
028: /**
029: * A weaving strategy implementing a weaving scheme based on statical compilation, and no reflection.
030: *
031: * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
032: */
033: public class ProxyWeavingStrategy implements WeavingStrategy {
034:
035: /**
036: * Performs the weaving of the target class.
037: *
038: * @param className
039: * @param context
040: */
041: public void transform(String className,
042: final InstrumentationContext context) {
043: try {
044: final byte[] bytecode = context.getInitialBytecode();
045: final ClassLoader loader = context.getLoader();
046:
047: ClassInfo classInfo = AsmClassInfo.getClassInfo(className,
048: bytecode, loader);
049:
050: final Set definitions = context.getDefinitions();
051: final ExpressionContext[] ctxs = new ExpressionContext[] { new ExpressionContext(
052: PointcutType.EXECUTION, classInfo, classInfo) };
053:
054: // has AW aspects?
055: final boolean isAdvisable = !classFilter(definitions, ctxs,
056: classInfo);
057:
058: if (!isAdvisable) {
059: context
060: .setCurrentBytecode(context
061: .getInitialBytecode());
062: return;
063: }
064:
065: // prepare ctor call jp
066: Set addedMethods = new HashSet();
067: // final ClassReader crLookahead = new ClassReader(bytecode);
068: // crLookahead.accept(new AlreadyAddedMethodAdapter(addedMethods), true);
069:
070: // ------------------------------------------------
071: // -- Phase 1 -- type change (ITDs)
072: final ClassReader readerPhase1 = new ClassReader(bytecode);
073: final ClassWriter writerPhase1 = new ClassWriter(
074: readerPhase1, ClassWriter.COMPUTE_MAXS);
075: ClassVisitor reversedChainPhase1 = writerPhase1;
076: reversedChainPhase1 = new AddMixinMethodsVisitor(
077: reversedChainPhase1, classInfo, context,
078: addedMethods);
079: reversedChainPhase1 = new AddInterfaceVisitor(
080: reversedChainPhase1, classInfo, context);
081: readerPhase1.accept(reversedChainPhase1,
082: ClassReader.SKIP_FRAMES);
083: context.setCurrentBytecode(writerPhase1.toByteArray());
084:
085: // ------------------------------------------------
086: // update the class info with new ITDs
087: classInfo = AsmClassInfo.newClassInfo(context
088: .getCurrentBytecode(), loader);
089:
090: // ------------------------------------------------
091: // -- Phase 2 -- advice
092: final ClassReader readerPhase2 = new ClassReader(context
093: .getCurrentBytecode());
094: final ClassWriter writerPhase2 = new ClassWriter(
095: readerPhase2, ClassWriter.COMPUTE_MAXS);
096: ClassVisitor reversedChainPhase2 = writerPhase2;
097: // reversedChainPhase2 = new InstanceLevelAspectVisitor(reversedChainPhase2, classInfo, context);
098: reversedChainPhase2 = new MethodExecutionVisitor(
099: reversedChainPhase2, classInfo, context,
100: addedMethods);
101: // reversedChainPhase2 = new LabelToLineNumberVisitor(reversedChainPhase2, context);
102: readerPhase2.accept(reversedChainPhase2, 0);
103: context.setCurrentBytecode(writerPhase2.toByteArray());
104:
105: // ------------------------------------------------
106: // -- AW Finalization -- JP init code and wrapper methods
107: if (context.isAdvised()) {
108: ClassReader readerPhase3 = new ClassReader(context
109: .getCurrentBytecode());
110: final ClassWriter writerPhase3 = new ClassWriter(
111: readerPhase3, ClassWriter.COMPUTE_MAXS);
112: ClassVisitor reversedChainPhase3 = writerPhase3;
113: reversedChainPhase3 = new AddWrapperVisitor(
114: reversedChainPhase3, context, addedMethods);
115: reversedChainPhase3 = new JoinPointInitVisitor(
116: reversedChainPhase3, context);
117: readerPhase3.accept(reversedChainPhase3, 0);
118: context.setCurrentBytecode(writerPhase3.toByteArray());
119: }
120: } catch (Throwable t) {
121: t.printStackTrace();
122: throw new WrappedRuntimeException(t);
123: }
124: }
125:
126: /**
127: * Filters out the classes that are not eligible for transformation.
128: *
129: * @param definitions the definitions
130: * @param ctxs an array with the contexts
131: * @param classInfo the class to filter
132: * @return boolean true if the class should be filtered out
133: */
134: private static boolean classFilter(final Set definitions,
135: final ExpressionContext[] ctxs, final ClassInfo classInfo) {
136: if (classInfo.isInterface()) {
137: return true;
138: }
139: for (Iterator defs = definitions.iterator(); defs.hasNext();) {
140: if (classFilter((SystemDefinition) defs.next(), ctxs,
141: classInfo)) {
142: continue;
143: } else {
144: return false;
145: }
146: }
147: return true;
148: }
149:
150: /**
151: * Filters out the classes that are not eligible for transformation.
152: *
153: * @param definition the definition
154: * @param ctxs an array with the contexts
155: * @param classInfo the class to filter
156: * @return boolean true if the class should be filtered out
157: * @TODO: when a class had execution pointcut that were removed it must be unweaved, thus not filtered out How to
158: * handle that? cache lookup? or custom class level attribute ?
159: */
160: private static boolean classFilter(
161: final SystemDefinition definition,
162: final ExpressionContext[] ctxs, final ClassInfo classInfo) {
163:
164: if (classInfo.isInterface()) {
165: return true;
166: }
167: String className = classInfo.getName();
168: if (definition.inExcludePackage(className)) {
169: return true;
170: }
171: if (!definition.inIncludePackage(className)) {
172: return true;
173: }
174: if (definition.isAdvised(ctxs)) {
175: return false;
176: }
177: if (definition.hasMixin(ctxs)) {
178: return false;
179: }
180: if (definition.hasIntroducedInterface(ctxs)) {
181: return false;
182: }
183: if (definition.inPreparePackage(className)) {
184: return false;
185: }
186: return true;
187: }
188:
189: // private static boolean classFilterFor(final Set definitions, final ExpressionContext[] ctxs) {
190: // for (Iterator defs = definitions.iterator(); defs.hasNext();) {
191: // if (classFilterFor((SystemDefinition) defs.next(), ctxs)) {
192: // continue;
193: // } else {
194: // return false;
195: // }
196: // }
197: // return true;
198: // }
199: //
200: // private static boolean classFilterFor(final SystemDefinition definition, final ExpressionContext[] ctxs) {
201: // if (definition.isAdvised(ctxs)) {
202: // return false;
203: // }
204: // return true;
205: // }
206: //
207: // private static boolean hasPointcut(final Set definitions, final ExpressionContext ctx) {
208: // for (Iterator defs = definitions.iterator(); defs.hasNext();) {
209: // if (hasPointcut((SystemDefinition) defs.next(), ctx)) {
210: // return true;
211: // } else {
212: // continue;
213: // }
214: // }
215: // return false;
216: // }
217: //
218: // private static boolean hasPointcut(final SystemDefinition definition, final ExpressionContext ctx) {
219: // if (definition.hasPointcut(ctx)) {
220: // return true;
221: // }
222: // return false;
223: // }
224: }
|