KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > transform > AspectWerkzPreProcessor


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.transform;
5
6 import com.tc.aspectwerkz.expression.SubtypePatternType;
7 import com.tc.aspectwerkz.expression.regexp.Pattern;
8 import com.tc.aspectwerkz.expression.regexp.TypePattern;
9 import com.tc.aspectwerkz.hook.ClassPreProcessor;
10 import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint;
11 import com.tc.aspectwerkz.util.Util;
12 // import com.tc.object.bytecode.hook.ClassProcessor;
13

14 /**
15  * AspectWerkzPreProcessor is the entry point of the AspectWerkz layer 2. <p/>It implements the ClassPreProcessor
16  * interface defined in layer 1. <p/>Available options are:
17  * <ul>
18  * <li><code>-Daspectwerkz.transform.verbose=yes</code> turns on verbose mode: print on stdout all non filtered class
19  * names and which transformation are applied</li>
20  * <li><code>-Daspectwerkz.transform.dump=org.myapp.*</code> dumps transformed class matching pattern <i>org.myapp.*
21  * </i>(even unmodified ones) in <i>./_dump </i> directory (relative to where applications starts). The syntax
22  * <code>-Daspectwerkz.transform.dump=*</code> matchs all classes. The pattern language is the same as pointcut
23  * pattern language.</li>
24  * <li>else <code>-Daspectwerkz.transform.dump=org.myapp.*,before</code> dumps class before and after the
25  * transformation whose name starts with <i>org.myapp. </i>(even unmodified ones) in <i>./_dump/before </i> and
26  * <i>./_dump/after </i> directories (relative to where application starts)</li>
27  * <li><code>-Daspectwerkz.transform.filter=no</code> (or false) disables filtering of
28  * <code>com.tc.aspectwerkz</code> and related classes (trove, dom4j etc.). This should only be used in offline
29  * mode where weaving of those classes is needed. Setting this option in online mode will lead to
30  * <code>ClassCircularityError</code>.</li>
31  * </ul>
32  *
33  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
34  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
35  */

36 public class AspectWerkzPreProcessor implements ClassPreProcessor {
37
38   private final static String JavaDoc AW_TRANSFORM_FILTER = "aspectwerkz.transform.filter";
39
40   private final static String JavaDoc AW_TRANSFORM_VERBOSE = "aspectwerkz.transform.verbose";
41
42   private final static String JavaDoc AW_TRANSFORM_DETAILS = "aspectwerkz.transform.details";
43
44   private final static String JavaDoc AW_TRANSFORM_GENJP = "aspectwerkz.transform.genjp";
45
46   private final static String JavaDoc AW_TRANSFORM_DUMP = "aspectwerkz.transform.dump";
47
48   public final static TypePattern DUMP_PATTERN;
49
50   private final static boolean NOFILTER; // TODO: not used, remove?
51

52   public final static boolean DUMP_BEFORE;
53
54   public final static boolean DUMP_AFTER;
55
56   public static final String JavaDoc DUMP_DIR_BEFORE;
57
58   public static final String JavaDoc DUMP_DIR_AFTER;
59
60   public final static boolean VERBOSE;
61
62   public final static boolean DETAILS;
63
64   public final static boolean GENJP;
65
66   static {
67     // define the tracing and dump options
68
String JavaDoc verbose = System.getProperty(AW_TRANSFORM_VERBOSE, null);
69     VERBOSE = "yes".equalsIgnoreCase(verbose) || "true".equalsIgnoreCase(verbose);
70     String JavaDoc details = System.getProperty(AW_TRANSFORM_DETAILS, null);
71     DETAILS = "yes".equalsIgnoreCase(details) || "true".equalsIgnoreCase(details);
72     String JavaDoc genjp = System.getProperty(AW_TRANSFORM_GENJP, null);
73     GENJP = "yes".equalsIgnoreCase(genjp) || "true".equalsIgnoreCase(genjp);
74     String JavaDoc filter = System.getProperty(AW_TRANSFORM_FILTER, null);
75     NOFILTER = "no".equalsIgnoreCase(filter) || "false".equalsIgnoreCase(filter);
76     String JavaDoc dumpPattern = System.getProperty(AW_TRANSFORM_DUMP, null);
77     if (dumpPattern == null) {
78       DUMP_BEFORE = false;
79       DUMP_AFTER = false;
80       DUMP_PATTERN = null;
81     } else {
82       dumpPattern = dumpPattern.trim();
83       DUMP_AFTER = true;
84       DUMP_BEFORE = dumpPattern.indexOf(",before") > 0;
85       if (DUMP_BEFORE) {
86         DUMP_PATTERN = Pattern.compileTypePattern(dumpPattern.substring(0, dumpPattern.indexOf(',')),
87                 SubtypePatternType.NOT_HIERARCHICAL);
88       } else {
89         DUMP_PATTERN = Pattern.compileTypePattern(dumpPattern, SubtypePatternType.NOT_HIERARCHICAL);
90       }
91     }
92     DUMP_DIR_BEFORE = "_dump/before";
93     DUMP_DIR_AFTER = AspectWerkzPreProcessor.DUMP_BEFORE ? "_dump/after" : "_dump";
94   }
95
96   /**
97    * Marks the pre-processor as initialized.
98    */

99   private boolean m_initialized = false;
100
101   /**
102    * Pre processor weaving strategy.
103    */

104   // private ClassProcessor m_classProcessor;
105

106   /**
107    * Initializes the transformer stack.
108    */

109   public void initialize() {
110 // try {
111
// m_classProcessor = DSOContextImpl.createGlobalContext();
112
// m_initialized = true;
113
// } catch (ConfigurationSetupException e) {
114
// throw new WrappedRuntimeException(e);
115
// }
116
throw new RuntimeException JavaDoc("NOT merged with the changed code yet");
117   }
118
119   /**
120    * Transform bytecode according to the transformer stack Adapted for embedded modes, that will filter out framework
121    * classes See preProcessWithOutput for a tool entry point.
122    *
123    * @param name class name
124    * @param bytecode bytecode to transform
125    * @param loader classloader loading the class
126    * @return modified (or not) bytecode
127    */

128   public byte[] preProcess(final String JavaDoc name, final byte[] bytecode, final ClassLoader JavaDoc loader) {
129     // filter out ExtClassLoader and BootClassLoader
130
if (!NOFILTER) {
131       if ((loader == null) || (loader.getParent() == null)) {
132         return bytecode;
133       }
134     }
135
136     // needed for JRockit (as well as all in all TFs)
137
final String JavaDoc className = (name != null) ? name.replace('/', '.') : null;
138
139     // will filter null named classes
140
if (filter(className) || !m_initialized) {
141       return bytecode;
142     }
143     if (VERBOSE) {
144       log(Util.classLoaderToString(loader) + ':' + className + '[' + Thread.currentThread().getName() + ']');
145     }
146
147     try {
148       InstrumentationContext context = _preProcess(className, bytecode, loader);
149       return context.getCurrentBytecode();
150     } catch (Exception JavaDoc e) {
151       log("failed " + className);
152       e.printStackTrace();
153       return bytecode;
154     }
155   }
156
157   /**
158    * Weaving of the class
159    *
160    * @param className
161    * @param bytecode
162    * @param loader
163    * @return the weaving context, where getCurrentBytecode is the resulting bytecode
164    */

165   public InstrumentationContext _preProcess(final String JavaDoc className, final byte[] bytecode, final ClassLoader JavaDoc loader) {
166
167     // FIXME now I am creating 2 contexts: one here and one directly in the preProcess method - FIX
168
final InstrumentationContext context = new InstrumentationContext(className, bytecode, loader);
169
170     // dump before (not compliant with multiple CL weaving same class differently, since based
171
// on class FQN className)
172
dumpBefore(className, context);
173
174     // do the transformation
175
final byte[] transformedBytes = bytecode; // m_classProcessor.preProcess(className, bytecode, 0, bytecode.length, loader);
176

177     context.setCurrentBytecode(transformedBytes);
178
179     // FIXME when and how to call the postProcess????
180

181     // dump after as required
182
dumpAfter(className, context);
183
184     // return the transformed bytecode
185
return context;
186   }
187
188   /**
189    * Weaving without filtering any class and returning a rich object with emitted joinpoints
190    *
191    * @param name
192    * @param bytecode
193    * @param loader
194    * @return
195    */

196   public Output preProcessWithOutput(final String JavaDoc name, final byte[] bytecode, final ClassLoader JavaDoc loader) {
197     // needed for JRockit (as well as all in all TFs)
198
final String JavaDoc className = name.replace('/', '.');
199
200     // we do not filter anything except JP in this mode
201
if (name.endsWith((TransformationConstants.JOIN_POINT_CLASS_SUFFIX))) {
202       Output output = new Output();
203       output.bytecode = bytecode;
204       output.emittedJoinPoints = null;
205       return output;
206     }
207
208     InstrumentationContext context = _preProcess(className, bytecode, loader);
209     Output output = new Output();
210     output.bytecode = context.getCurrentBytecode();
211     output.emittedJoinPoints = (EmittedJoinPoint[]) context.getEmittedJoinPoints()
212             .toArray(new EmittedJoinPoint[0]);
213
214     // resolve line numbers
215
for (int i = 0; i < output.emittedJoinPoints.length; i++) {
216       EmittedJoinPoint emittedJoinPoint = output.emittedJoinPoints[i];
217       emittedJoinPoint.resolveLineNumber(context);
218     }
219     return output;
220   }
221
222   /**
223    * Logs a message.
224    *
225    * @param msg the message to log
226    */

227   public static void log(final String JavaDoc msg) {
228     if (VERBOSE) {
229       System.out.println(msg);
230     }
231   }
232
233   /**
234    * Excludes instrumentation for the class used during the instrumentation
235    *
236    * @param klass the AspectWerkz class
237    */

238   private static boolean filter(final String JavaDoc klass) {
239     return (klass == null) || klass.endsWith("_AWFactory")// TODO AVF refactor
240
|| klass.endsWith(TransformationConstants.JOIN_POINT_CLASS_SUFFIX)
241             || klass.startsWith("com.tc.aspectwerkz.")
242             || klass.startsWith("com.tc.asm.")
243             || klass.startsWith("com.tc.jrexx.")
244             || klass.startsWith("com.bluecast.")
245             || klass.startsWith("gnu.trove.")
246             || klass.startsWith("org.dom4j.")
247             || klass.startsWith("org.xml.sax.")
248             || klass.startsWith("javax.xml.parsers.")
249             || klass.startsWith("sun.reflect.Generated")// issue on J2SE 5 reflection - AW-245
250
|| klass.startsWith("EDU.oswego.cs.dl.util.concurrent");
251   }
252
253   /**
254    * Dumps class before weaving.
255    *
256    * @param className
257    * @param context
258    */

259   public static void dumpBefore(final String JavaDoc className, final InstrumentationContext context) {
260     if (DUMP_BEFORE) {
261       if (DUMP_PATTERN.matches(className)) {
262         context.dump("_dump/before/");
263       }
264     }
265   }
266
267   /**
268    * Dumps class after weaving.
269    *
270    * @param className
271    * @param context
272    */

273   public static void dumpAfter(final String JavaDoc className, final InstrumentationContext context) {
274     if (DUMP_AFTER) {
275       if (DUMP_PATTERN.matches(className)) {
276         context.dump("_dump/" + (DUMP_BEFORE ? "after/" : ""));
277       }
278     }
279   }
280
281   /**
282    * Structure build when invoking tool weaving
283    */

284   public static class Output {
285     public byte[] bytecode;
286     public EmittedJoinPoint[] emittedJoinPoints;
287   }
288 }
Popular Tags