KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > compiler > AspectWerkzC


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.compiler;
5
6
7 import com.tc.aspectwerkz.aspect.AdviceInfo;
8 import com.tc.aspectwerkz.cflow.CflowBinding;
9 import com.tc.aspectwerkz.cflow.CflowCompiler;
10 import com.tc.aspectwerkz.definition.SystemDefinitionContainer;
11 import com.tc.aspectwerkz.joinpoint.management.AdviceInfoContainer;
12 import com.tc.aspectwerkz.joinpoint.management.JoinPointManager;
13 import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint;
14 import com.tc.aspectwerkz.util.ContextClassLoader;
15
16 import java.io.ByteArrayOutputStream JavaDoc;
17 import java.io.File JavaDoc;
18 import java.io.FileInputStream JavaDoc;
19 import java.io.FileOutputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.net.URLClassLoader JavaDoc;
24 import java.text.SimpleDateFormat JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30
31 /**
32  * AspectWerkzC allow for precompilation of class / jar / zip given a class preprocessor. <p/>
33  * <h2>Usage</h2>
34  * <p/>
35  * <pre>
36  * java [-Daspectwerkz.classloader.preprocessor={ClassPreProcessorImpl}] -cp [...]
37  * com.tc.aspectwerkz.compiler.AspectWerkzC [-verbose] [-haltOnError] [-verify] [-genjp] [-details] [-cp {additional cp i}]* {target
38  * 1} .. {target n}
39  * {ClassPreProcessorImpl} : full qualified name of the ClassPreProcessor implementation (must be in classpath)
40  * defaults to com.tc.aspectwerkz.transform.AspectWerkzPreProcessor
41  * {additional cp i} : additionnal classpath needed at compile time (eg: myaspect.jar)
42  * use as many -cp options as needed
43  * supports java classpath syntax for classpath separator: ; on windows, : on others
44  * {target i} : exploded dir, jar, zip files to compile
45  * Ant 1.5 must be in the classpath
46  * </pre>
47  * <p/>
48  * <p/>
49  * <h2>Classpath note</h2>
50  * At the beginning of the compilation, all {target i} are added to the classpath automatically. <br/>This is required
51  * to support caller side advices. <p/>
52  * <h2>Error handling</h2>
53  * For each target i, a backup copy is written in ./_aspectwerkzc/i/target <br/>Transformation occurs on original target
54  * class/dir/jar/zip file <br/>On failure, target backup is restored and stacktrace is given <br/><br/>If
55  * <i>-haltOnError </i> was set, compilations ends and a <b>complete </b> rollback occurs on all targets, else a status
56  * report is printed at the end of the compilation, indicating SUCCESS or ERROR for each given target. <br/>If
57  * <i>-verify </i> was set, all compiled class are verified during the compilation and an error is generated if the
58  * compiled class bytecode is corrupted. The error is then handled according to the <i>-haltOnError </i> option. <br/>
59  * <p/>
60  * <h2>Manifest.mf update</h2>
61  * The Manifest.mf if present is updated wit the following:
62  * <ul>
63  * <li>AspectWerkzC-created: date of the compilation</li>
64  * <li>AspectWerkzC-preprocessor: full qualified classname of the preprocessor used</li>
65  * <li>AspectWerkzC-comment: comments</li>
66  * </ul>
67  *
68  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
69  */

70 public class AspectWerkzC {
71   // COMMAND LINE OPTIONS
72
private static final String JavaDoc COMMAND_LINE_OPTION_DASH = "-";
73   private static final String JavaDoc COMMAND_LINE_OPTION_VERBOSE = "-verbose";
74   private static final String JavaDoc COMMAND_LINE_OPTION_DETAILS = "-details";
75   private static final String JavaDoc COMMAND_LINE_OPTION_GENJP = "-genjp";
76   private static final String JavaDoc COMMAND_LINE_OPTION_HALT = "-haltOnError";
77   private static final String JavaDoc COMMAND_LINE_OPTION_VERIFY = "-verify";
78   private static final String JavaDoc COMMAND_LINE_OPTION_CLASSPATH = "-cp";
79   private static final String JavaDoc COMMAND_LINE_OPTION_TARGETS = "compile.targets";
80
81   /**
82    * option used to defined the class preprocessor
83    */

84   private static final String JavaDoc PRE_PROCESSOR_CLASSNAME_PROPERTY = "aspectwerkz.classloader.preprocessor";
85
86   private final static String JavaDoc AW_TRANSFORM_DETAILS = "aspectwerkz.transform.details";
87
88   /**
89    * default class preprocessor
90    */

91   private static final String JavaDoc PRE_PROCESSOR_CLASSNAME_DEFAULT = "com.tc.aspectwerkz.transform.AspectWerkzPreProcessor";
92
93   private final static String JavaDoc MF_CUSTOM_DATE = "X-AspectWerkzC-created";
94
95   private final static String JavaDoc MF_CUSTOM_PP = "X-AspectWerkzC-preprocessor";
96
97   private final static String JavaDoc MF_CUSTOM_COMMENT = "X-AspectWerkzC-comment";
98
99   private final static String JavaDoc MF_CUSTOM_COMMENT_VALUE = "AspectWerkzC - AspectWerkz compiler, aspectwerkz.codehaus.org";
100
101   private final static SimpleDateFormat JavaDoc DF = new SimpleDateFormat JavaDoc("yyyy-MM-dd HH:mm:ss");
102
103   private final static String JavaDoc BACKUP_DIR = "_aspectwerkzc";
104
105   private boolean verify = false;
106
107   private boolean genJp = false;
108
109   private boolean haltOnError = false;
110
111   private String JavaDoc backupDir = BACKUP_DIR;
112
113   /**
114    * class loader in which the effective compilation occurs, child of system classloader
115    */

116   private URLClassLoader JavaDoc compilationLoader = null;
117
118   /**
119    * class preprocessor instance used to compile targets
120    */

121 // private ClassPreProcessor preprocessor = null;
122
private boolean isAspectWerkzPreProcessor = false;
123
124   /**
125    * index to keep track of {target i} backups
126    */

127   private int sourceIndex;
128
129   /**
130    * Maps the target file to the target backup file
131    */

132   private Map JavaDoc backupMap = new HashMap JavaDoc();
133
134   /**
135    * Maps the target file to a status indicating compilation was successfull
136    */

137   private Map JavaDoc successMap = new HashMap JavaDoc();
138
139   private long timer;
140
141   /**
142    * Utility for file manipulation
143    */

144   private Utility utility;
145
146   /**
147    * Construct a new Utility, restore the index for backup
148    */

149   public AspectWerkzC() {
150     //@todo check for multiple transformation in compiler or in preprocessor ?
151
sourceIndex = 0;
152     utility = new Utility();
153     timer = System.currentTimeMillis();
154   }
155
156   /*
157   * public void log(String msg) { utility.log(msg); } public void log(String msg, Throwable t) { utility.log(msg);
158   * t.printStackTrace(); }
159   */

160   public void setVerbose(boolean verbose) {
161     utility.setVerbose(verbose);
162   }
163
164   public void setGenJp(boolean genpJp) {
165     this.genJp = genpJp;
166   }
167
168   public void setHaltOnError(boolean haltOnError) {
169     this.haltOnError = haltOnError;
170   }
171
172   public void setVerify(boolean verify) {
173     this.verify = verify;
174   }
175
176   public void setDetails(boolean details) {
177     if (details) {
178       System.setProperty(AW_TRANSFORM_DETAILS, "true");
179     }
180   }
181
182   public void setBackupDir(String JavaDoc backup) {
183     this.backupDir = backup;
184   }
185
186   public Utility getUtility() {
187     return utility;
188   }
189
190   /**
191    * Sets the ClassPreProcessor implementation to use. <p/>The ClassLoader will be set to System ClassLoader when
192    * transform(className, byteCode, callerClassLoader) will be called to compile a class.
193    */

194   public void setPreprocessor(String JavaDoc preprocessor) throws CompileException {
195 // try {
196
// Class pp = Class.forName(preprocessor);
197
// this.preprocessor = (ClassPreProcessor) pp.newInstance();
198
// this.preprocessor.initialize();
199
//
200
// if (this.preprocessor instanceof AspectWerkzPreProcessor) {
201
// isAspectWerkzPreProcessor = true;
202
// }
203
// } catch (Exception e) {
204
// throw new CompileException("failed to instantiate preprocessor " + preprocessor, e);
205
// }
206
}
207
208   /**
209    * Backup source file in backup_dir/index/file. The backupMap is updated for further rollback
210    */

211   public void backup(File JavaDoc source, int index) {
212     // backup source in BACKUP/index dir
213
File JavaDoc dest = new File JavaDoc(this.backupDir + File.separator + index + File.separator + source.getName());
214     utility.backupFile(source, dest);
215
216     // add to backupMap in case of rollback
217
backupMap.put(source, dest);
218   }
219
220   /**
221    * Restore the backup registered
222    */

223   public void restoreBackup() {
224     for (Iterator JavaDoc i = backupMap.keySet().iterator(); i.hasNext();) {
225       File JavaDoc source = (File JavaDoc) i.next();
226       if (!successMap.containsKey(source)) {
227         File JavaDoc dest = (File JavaDoc) backupMap.get(source);
228         utility.backupFile(dest, source);
229       }
230     }
231   }
232
233   /**
234    * Delete backup dir at the end of all compilation
235    */

236   public void postCompile(String JavaDoc message) {
237     restoreBackup();
238     utility.log(" [backup] removing backup");
239     utility.deleteDir(new File JavaDoc(this.backupDir));
240     long ms = Math.max(System.currentTimeMillis() - timer, 1 * 1000);
241     System.out.println("( " + (int) (ms / 1000) + " s ) " + message);
242     if (!haltOnError) {
243       for (Iterator JavaDoc i = backupMap.keySet().iterator(); i.hasNext();) {
244         File JavaDoc source = (File JavaDoc) i.next();
245         if (successMap.containsKey(source)) {
246           System.out.println("SUCCESS: " + source);
247         } else {
248           System.out.println("FAILED : " + source);
249         }
250       }
251     }
252   }
253
254   /**
255    * Compile sourceFile. If prefixPackage is not null, assumes it is the class package information. <p/>Handles :
256    * <ul>
257    * <li>directory recursively (exploded jar)</li>
258    * <li>jar / zip file</li>
259    * </ul>
260    */

261   public void doCompile(File JavaDoc sourceFile, String JavaDoc prefixPackage) throws CompileException {
262     if (sourceFile.isDirectory()) {
263       File JavaDoc[] classes = sourceFile.listFiles();
264       for (int i = 0; i < classes.length; i++) {
265         if (classes[i].isDirectory() && !(this.backupDir.equals(classes[i].getName()))) {
266           String JavaDoc packaging = (prefixPackage != null) ? (prefixPackage + "." + classes[i]
267                   .getName()) : classes[i].getName();
268           doCompile(classes[i], packaging);
269         } else if (classes[i].getName().toLowerCase().endsWith(".class")) {
270           compileClass(classes[i], prefixPackage);
271         } else if (isJarFile(classes[i])) {
272           //@todo: jar encountered in a dir - use case ??
273
compileJar(classes[i]);
274         }
275       }
276     } else if (sourceFile.getName().toLowerCase().endsWith(".class")) {
277       compileClass(sourceFile, null);
278     } else if (isJarFile(sourceFile)) {
279       compileJar(sourceFile);
280     }
281   }
282
283   /**
284    * Compiles .class file using fileName as className and given packaging as package name
285    */

286   public void compileClass(File JavaDoc file, String JavaDoc packaging) throws CompileException {
287     InputStream JavaDoc in = null;
288     FileOutputStream JavaDoc fos = null;
289     try {
290       utility.log(" [compile] " + file.getCanonicalPath());
291
292       // dump bytecode in byte[]
293
ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
294       in = new FileInputStream JavaDoc(file);
295       byte[] buffer = new byte[1024];
296       while (in.available() > 0) {
297         int length = in.read(buffer);
298         if (length == -1) {
299           break;
300         }
301         bos.write(buffer, 0, length);
302       }
303
304       // rebuild className
305
String JavaDoc className = file.getName().substring(0, file.getName().length() - 6);
306       if (packaging != null) {
307         className = packaging + '.' + className;
308       }
309
310       // transform
311
// AspectWerkzPreProcessor.Output out = null;
312
// try {
313
// out = preProcess(preprocessor, className, bos.toByteArray(), compilationLoader);
314
// } catch (Throwable t) {
315
// throw new CompileException("weaver failed for class: " + className, t);
316
// }
317

318       // override file
319
// fos = new FileOutputStream(file);
320
// fos.write(out.bytecode);
321
// fos.close();
322
//
323
// // if AW and genjp
324
// if (out.emittedJoinPoints != null && genJp) {
325
// for (int i = 0; i < out.emittedJoinPoints.length; i++) {
326
// EmittedJoinPoint emittedJoinPoint = out.emittedJoinPoints[i];
327
// //TODO we assume same package here.. make more generic
328
// String jpClassNoPackage = emittedJoinPoint.getJoinPointClassName();
329
// if (jpClassNoPackage.indexOf('/')>0) {
330
// jpClassNoPackage = jpClassNoPackage.substring(jpClassNoPackage.lastIndexOf('/'));
331
// }
332
// File jpFile = new File(file.getParent(), jpClassNoPackage+".class");
333
// utility.log(" [genjp] " + jpFile.getCanonicalPath());
334
// FileOutputStream jpFos = new FileOutputStream(jpFile);
335
// JoinPointManager.CompiledJoinPoint compiledJp = compileJoinPoint(emittedJoinPoint, compilationLoader);
336
// jpFos.write(compiledJp.bytecode);
337
// jpFos.close();
338
//
339
// // handle cflow if any
340
// CflowCompiler.CompiledCflowAspect[] compiledCflowAspects = compileCflows(compiledJp);
341
// if (compiledCflowAspects.length > 0) {
342
// String baseDirAbsolutePath = getBaseDir(file.getCanonicalPath(), className);
343
// for (int j = 0; j < compiledCflowAspects.length; j++) {
344
// CflowCompiler.CompiledCflowAspect compiledCflowAspect = compiledCflowAspects[j];
345
// File cflowFile = new File(baseDirAbsolutePath + File.separatorChar + compiledCflowAspect.className.replace('/', File.separatorChar) + ".class");
346
// (new File(cflowFile.getParent())).mkdirs();
347
// utility.log(" [genjp] (cflow) " + cflowFile.getCanonicalPath());
348
// FileOutputStream cflowFos = new FileOutputStream(cflowFile);
349
// cflowFos.write(compiledCflowAspect.bytecode);
350
// cflowFos.close();
351
// }
352
// }
353
// }
354
// }
355

356       // verify modified class
357
if (verify) {
358         URLClassLoader JavaDoc verifier = new VerifierClassLoader(
359                 compilationLoader.getURLs(),
360                 ClassLoader.getSystemClassLoader()
361         );
362         try {
363           utility.log(" [verify] " + className);
364           Class.forName(className, false, verifier);
365         } catch (Throwable JavaDoc t) {
366           utility.log(" [verify] corrupted class: " + className);
367           throw new CompileException("corrupted class: " + className, t);
368         }
369       }
370     } catch (IOException JavaDoc e) {
371       throw new CompileException("compile " + file.getAbsolutePath() + " failed", e);
372     } finally {
373       try {
374         in.close();
375       } catch (Throwable JavaDoc e) {
376         ;
377       }
378       try {
379         fos.close();
380       } catch (Throwable JavaDoc e) {
381         ;
382       }
383     }
384   }
385
386   /**
387    * Compile all .class encountered in the .jar/.zip file. <p/>The target.jar is compiled in the
388    * target.jar.aspectwerkzc and the target.jar.aspectwerkzc then overrides target.jar on success.
389    */

390   public void compileJar(File JavaDoc file) throws CompileException {
391     utility.log(" [compilejar] " + file.getAbsolutePath());
392
393     // create an empty jar target.jar.aspectwerkzc
394
// File workingFile = new File(file.getAbsolutePath() + ".aspectwerkzc");
395
// if (workingFile.exists()) {
396
// workingFile.delete();
397
// }
398
// ZipFile zip = null;
399
// ZipOutputStream zos = null;
400
// try {
401
// zip = new ZipFile(file);
402
// zos = new ZipOutputStream(new FileOutputStream(workingFile));
403
// for (Enumeration e = zip.entries(); e.hasMoreElements();) {
404
// ZipEntry ze = (ZipEntry) e.nextElement();
405
//
406
// // dump bytes read in byte[]
407
// InputStream in = zip.getInputStream(ze);
408
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
409
// byte[] buffer = new byte[1024];
410
// while (in.available() > 0) {
411
// int length = in.read(buffer);
412
// if (length == -1) {
413
// break;
414
// }
415
// bos.write(buffer, 0, length);
416
// }
417
// in.close();
418
//
419
// transform only .class file
420
// AspectWerkzPreProcessor.Output out = null;
421
// byte[] transformed = null;
422
// if (ze.getName().toLowerCase().endsWith(".class")) {
423
// utility.log(" [compilejar] compile " + file.getName() + ":" + ze.getName());
424
// String className = ze.getName().substring(0, ze.getName().length() - 6);
425
// try {
426
// out = preProcess(preprocessor, className, bos.toByteArray(), compilationLoader);
427
// transformed = out.bytecode;
428
// } catch (Throwable t) {
429
// throw new CompileException("weaver failed for class: " + className, t);
430
// }
431
// } else {
432
// out = null;
433
// transformed = bos.toByteArray();
434
// }
435

436     // customize Manifest.mf
437
// if (ze.getName().toLowerCase().equals("meta-inf/manifest.mf")) {
438
// try {
439
// Manifest mf = new Manifest(new ByteArrayInputStream(transformed));
440
// Attributes at = mf.getMainAttributes();
441
// at.putValue(MF_CUSTOM_DATE, DF.format(new Date()));
442
// at.putValue(MF_CUSTOM_PP, preprocessor.getClass().getName());
443
// at.putValue(MF_CUSTOM_COMMENT, MF_CUSTOM_COMMENT_VALUE);
444
//
445
// // re read the updated manifest
446
// bos.reset();
447
// mf.write(bos);
448
// transformed = bos.toByteArray();
449
// } catch (Exception emf) {
450
// emf.printStackTrace();
451
// }
452
// }
453
//
454
// // update target.jar.aspectwerkzc working file
455
// ZipEntry transformedZe = new ZipEntry(ze.getName());
456
// transformedZe.setSize(transformed.length);
457
// CRC32 crc = new CRC32();
458
// crc.update(transformed);
459
// transformedZe.setCrc(crc.getValue());
460
// transformedZe.setMethod(ze.getMethod());
461
// zos.putNextEntry(transformedZe);
462
// zos.write(transformed, 0, transformed.length);
463
//
464
// // if AW and genjp
465
// if (genJp && out != null && out.emittedJoinPoints!=null) {
466
// for (int i = 0; i < out.emittedJoinPoints.length; i++) {
467
// EmittedJoinPoint emittedJoinPoint = out.emittedJoinPoints[i];
468
// JoinPointManager.CompiledJoinPoint compiledJp = compileJoinPoint(emittedJoinPoint, compilationLoader);
469
// utility.log(" [compilejar] (genjp) " + file.getName() + ":" + emittedJoinPoint.getJoinPointClassName());
470
// ZipEntry jpZe = new ZipEntry(emittedJoinPoint.getJoinPointClassName()+".class");
471
// jpZe.setSize(compiledJp.bytecode.length);
472
// CRC32 jpCrc = new CRC32();
473
// jpCrc.update(compiledJp.bytecode);
474
// jpZe.setCrc(jpCrc.getValue());
475
// jpZe.setMethod(ze.getMethod());
476
// zos.putNextEntry(jpZe);
477
// zos.write(compiledJp.bytecode, 0, compiledJp.bytecode.length);
478
//
479
// CflowCompiler.CompiledCflowAspect[] compiledCflowAspects = compileCflows(compiledJp);
480
// if (compiledCflowAspects.length > 0) {
481
// for (int j = 0; j < compiledCflowAspects.length; j++) {
482
// CflowCompiler.CompiledCflowAspect compiledCflowAspect = compiledCflowAspects[j];
483
// utility.log(" [compilejar] (genjp) (cflow) " + file.getName() + ":" + compiledCflowAspect.className);
484
// ZipEntry cflowZe = new ZipEntry(compiledCflowAspect.className+".class");
485
// cflowZe.setSize(compiledCflowAspect.bytecode.length);
486
// CRC32 cflowCrc = new CRC32();
487
// cflowCrc.update(compiledCflowAspect.bytecode);
488
// cflowZe.setCrc(cflowCrc.getValue());
489
// cflowZe.setMethod(ze.getMethod());
490
// zos.putNextEntry(cflowZe);
491
// zos.write(compiledCflowAspect.bytecode, 0, compiledCflowAspect.bytecode.length);
492
// }
493
// }
494
// }
495
// }
496
// }
497
// zip.close();
498
// zos.close();
499
//
500
// // replace file by workingFile
501
// File swap = new File(file.getAbsolutePath() + ".swap.aspectwerkzc");
502
// utility.backupFile(file, swap);
503
// try {
504
// utility.backupFile(workingFile, new File(file.getAbsolutePath()));
505
// workingFile.delete();
506
// swap.delete();
507
// } catch (Exception e) {
508
// // restore swapFile
509
// utility.backupFile(swap, new File(file.getAbsolutePath()));
510
// workingFile.delete();
511
// throw new CompileException("compile " + file.getAbsolutePath() + " failed", e);
512
// }
513
// } catch (IOException e) {
514
// throw new CompileException("compile " + file.getAbsolutePath() + " failed", e);
515
// } finally {
516
// try {
517
// zos.close();
518
// } catch (Throwable e) {
519
// ;
520
// }
521
// try {
522
// zip.close();
523
// } catch (Throwable e) {
524
// ;
525
// }
526
// }
527
}
528
529   /**
530    * Compile given target.
531    *
532    * @return false if process should stop
533    */

534   public boolean compile(File JavaDoc source) {
535     sourceIndex++;
536     backup(source, sourceIndex);
537     try {
538       doCompile(source, null);
539     } catch (CompileException e) {
540       utility.log(" [aspectwerkzc] compilation encountered an error");
541       e.printStackTrace();
542       return (!haltOnError);
543     }
544
545     // compile sucessfull
546
successMap.put(source, Boolean.TRUE);
547     return true;
548   }
549
550   /**
551    * Set up the compilation path by building a URLClassLoader with all targets in
552    *
553    * @param targets to add to compilationLoader classpath
554    * @param parentLoader the parent ClassLoader used by the new one
555    */

556   public void setCompilationPath(File JavaDoc[] targets, ClassLoader JavaDoc parentLoader) {
557     URL JavaDoc[] urls = new URL JavaDoc[targets.length];
558     int j = 0;
559     for (int i = 0; i < targets.length; i++) {
560       try {
561         urls[j] = targets[i].getCanonicalFile().toURL();
562         j++;
563       } catch (IOException JavaDoc e) {
564         System.err.println("bad target " + targets[i]);
565       }
566     }
567
568     compilationLoader = new URLClassLoader JavaDoc(urls, parentLoader);
569   }
570
571   /**
572    * Test if file is a zip/jar file
573    */

574   public static boolean isJarFile(File JavaDoc source) {
575     return (source.isFile() && (source.getName().toLowerCase().endsWith(".jar") || source
576             .getName().toLowerCase().endsWith(".zip")));
577   }
578
579   /**
580    * Usage message
581    */

582   public static void doHelp() {
583     System.out.println("--- AspectWerkzC compiler ---");
584     System.out.println("Usage:");
585     System.out
586             .println(
587                     "java -cp ... com.tc.aspectwerkz.compiler.AspectWerkzC [-verbose] [-haltOnError] [-verify] <target 1> .. <target n>"
588             );
589     System.out.println(" <target i> : exploded dir, jar, zip files to compile");
590   }
591
592   /**
593    * Creates and configures an AspectWerkzC compiler.
594    *
595    * @param params a map containing the compiler parameters
596    * @return a new and configured <CODE>AspectWerkzC</CODE>
597    */

598   private static AspectWerkzC createCompiler(Map JavaDoc params) {
599     AspectWerkzC compiler = new AspectWerkzC();
600
601     for (Iterator JavaDoc it = params.entrySet().iterator(); it.hasNext();) {
602       Map.Entry JavaDoc param = (Map.Entry JavaDoc) it.next();
603
604       if (COMMAND_LINE_OPTION_VERBOSE.equals(param.getKey())) {
605         compiler.setVerbose(Boolean.TRUE.equals(param.getValue()));
606       } else if (COMMAND_LINE_OPTION_HALT.equals(param.getKey())) {
607         compiler.setHaltOnError(Boolean.TRUE.equals(param.getValue()));
608       } else if (COMMAND_LINE_OPTION_VERIFY.equals(param.getKey())) {
609         compiler.setVerify(Boolean.TRUE.equals(param.getValue()));
610       } else if (COMMAND_LINE_OPTION_GENJP.equals(param.getKey())) {
611         compiler.setGenJp(Boolean.TRUE.equals(param.getValue()));
612       } else if (COMMAND_LINE_OPTION_DETAILS.equals(param.getKey())) {
613         compiler.setDetails(Boolean.TRUE.equals(param.getValue()));
614       }
615     }
616
617     return compiler;
618   }
619
620   /**
621    * Runs the AspectWerkzC compiler for the <tt>targets</tt> files.
622    *
623    * @param compiler a configured <CODE>AspectWerkzC</CODE>
624    * @param classLoader the class loader to be used
625    * @param preProcessor fully qualified name of the preprocessor class.
626    * If <tt>null</tt> than the default is used
627    * (<CODE>com.tc.aspectwerkz.transform.AspectWerkzPreProcessor</CODE>)
628    * @param classpath list of Files representing the classpath (List<File>)
629    * @param targets the list of target files (List<File>)
630    */

631   public static void compile(AspectWerkzC compiler,
632                              ClassLoader JavaDoc classLoader,
633                              String JavaDoc preProcessor,
634                              List JavaDoc classpath,
635                              List JavaDoc targets) {
636     List JavaDoc fullPath = new ArrayList JavaDoc();
637     if (classpath != null) {
638       fullPath.addAll(classpath);
639     }
640
641     fullPath.addAll(targets);
642
643     compiler.setCompilationPath((File JavaDoc[]) fullPath.toArray(new File JavaDoc[fullPath.size()]), classLoader);
644
645     Thread.currentThread().setContextClassLoader(compiler.compilationLoader);
646
647     // AOPC special fix
648
// turn off -Daspectwerkz.definition.file registration and register it at the
649
// compilationLoader level instead
650
SystemDefinitionContainer.disableSystemWideDefinition();
651     SystemDefinitionContainer.deployDefinitions(
652             compiler.compilationLoader,
653             SystemDefinitionContainer.getDefaultDefinition(compiler.compilationLoader)
654     );
655
656     String JavaDoc preprocessorFqn = preProcessor == null ? PRE_PROCESSOR_CLASSNAME_DEFAULT
657             : preProcessor;
658
659     try {
660       compiler.setPreprocessor(preprocessorFqn);
661     } catch (CompileException e) {
662       System.err.println("Cannot instantiate ClassPreProcessor: " + preprocessorFqn);
663       e.printStackTrace();
664       System.exit(-1);
665     }
666
667     cleanBackupDir(compiler);
668
669     for (Iterator JavaDoc i = targets.iterator(); i.hasNext();) {
670       if (!compiler.compile((File JavaDoc) i.next())) {
671         compiler.postCompile("*** An error occured ***");
672         System.exit(-1);
673       }
674     }
675     compiler.postCompile("");
676   }
677
678   private static void cleanBackupDir(AspectWerkzC compiler) {
679     // prepare backup directory
680
try {
681       File JavaDoc temp = new File JavaDoc(compiler.backupDir);
682       if (temp.exists()) {
683         compiler.getUtility().deleteDir(temp);
684       }
685       temp.mkdir();
686       (new File JavaDoc(temp, "" + System.currentTimeMillis() + ".timestamp")).createNewFile();
687     } catch (Exception JavaDoc e) {
688       System.err.println("failed to prepare backup dir: " + compiler.backupDir);
689       e.printStackTrace();
690       System.exit(-1);
691     }
692   }
693
694   public static void main(String JavaDoc[] args) {
695     if (args.length <= 0) {
696       doHelp();
697       return; //stop here
698
}
699
700     Map JavaDoc options = parseOptions(args);
701     AspectWerkzC compiler = createCompiler(options);
702
703     compiler.setBackupDir(BACKUP_DIR);
704
705     compile(
706             compiler,
707             ClassLoader.getSystemClassLoader(),
708             System.getProperty(
709                     PRE_PROCESSOR_CLASSNAME_PROPERTY,
710                     PRE_PROCESSOR_CLASSNAME_DEFAULT
711             ),
712             (List JavaDoc) options.get(COMMAND_LINE_OPTION_CLASSPATH),
713             (List JavaDoc) options.get(COMMAND_LINE_OPTION_TARGETS)
714     );
715   }
716
717   private static Map JavaDoc parseOptions(String JavaDoc[] args) {
718     Map JavaDoc options = new HashMap JavaDoc();
719     List JavaDoc targets = new ArrayList JavaDoc();
720
721     for (int i = 0; i < args.length; i++) {
722       if (COMMAND_LINE_OPTION_VERBOSE.equals(args[i])) {
723         options.put(COMMAND_LINE_OPTION_VERBOSE, Boolean.TRUE);
724       } else if (COMMAND_LINE_OPTION_GENJP.equals(args[i])) {
725         options.put(COMMAND_LINE_OPTION_GENJP, Boolean.TRUE);
726       } else if (COMMAND_LINE_OPTION_DETAILS.equals(args[i])) {
727         options.put(COMMAND_LINE_OPTION_DETAILS, Boolean.TRUE);
728       } else if (COMMAND_LINE_OPTION_HALT.equals(args[i])) {
729         options.put(COMMAND_LINE_OPTION_HALT, Boolean.TRUE);
730       } else if (COMMAND_LINE_OPTION_VERIFY.equals(args[i])) {
731         options.put(COMMAND_LINE_OPTION_VERIFY, Boolean.TRUE);
732       } else if (COMMAND_LINE_OPTION_CLASSPATH.equals(args[i])) {
733         if (i == (args.length - 1)) {
734           continue;
735         } else {
736           options.put(
737                   COMMAND_LINE_OPTION_CLASSPATH,
738                   toFileArray(args[++i], File.pathSeparator)
739           );
740         }
741       } else if (args[i].startsWith(COMMAND_LINE_OPTION_DASH)) {
742         ; // nothing to be done about it
743
} else {
744         File JavaDoc file = toFile(args[i]);
745         if (file == null) {
746           System.err.println("Ignoring inexistant target: " + args[i]);
747         } else {
748           targets.add(file);
749         }
750       }
751     }
752
753     options.put(COMMAND_LINE_OPTION_TARGETS, targets);
754
755     return options;
756   }
757
758   private static List JavaDoc toFileArray(String JavaDoc str, String JavaDoc sep) {
759     if (str == null || str.length() == 0) {
760       return new ArrayList JavaDoc();
761     }
762
763     List JavaDoc files = new ArrayList JavaDoc();
764     int start = 0;
765     int idx = str.indexOf(sep, start);
766     int len = sep.length();
767
768     while (idx != -1) {
769       files.add(new File JavaDoc(str.substring(start, idx)));
770       start = idx + len;
771       idx = str.indexOf(sep, start);
772     }
773
774     files.add(new File JavaDoc(str.substring(start)));
775
776     return files;
777   }
778
779   private static File JavaDoc toFile(String JavaDoc path) {
780     File JavaDoc file = new File JavaDoc(path);
781
782     return file.exists() ? file : null;
783   }
784
785   /**
786    * Helper method to have the emitted joinpoint back when dealing with AspectWerkz pp
787    * @param preProcessor
788    * @param className
789    * @param bytecode
790    * @param compilationLoader
791    * @return
792    */

793 // private AspectWerkzPreProcessor.Output preProcess(ClassPreProcessor preProcessor, String className, byte[] bytecode, ClassLoader compilationLoader) {
794
// if (isAspectWerkzPreProcessor) {
795
// return ((AspectWerkzPreProcessor)preProcessor).preProcessWithOutput(className, bytecode, compilationLoader);
796
// } else {
797
// byte[] newBytes = preProcessor.preProcess(className, bytecode, compilationLoader);
798
// AspectWerkzPreProcessor.Output out = new AspectWerkzPreProcessor.Output();
799
// out.bytecode = newBytes;
800
// return out;
801
// }
802
// }
803

804   /**
805    * Handles the compilation of the given emitted joinpoint
806    *
807    * @param emittedJoinPoint
808    * @param loader
809    * @return
810    * @throws IOException
811    */

812   private JoinPointManager.CompiledJoinPoint compileJoinPoint(EmittedJoinPoint emittedJoinPoint, ClassLoader JavaDoc loader) throws IOException JavaDoc {
813     try {
814       Class JavaDoc callerClass = ContextClassLoader.forName(emittedJoinPoint.getCallerClassName().replace('/', '.'));
815       Class JavaDoc calleeClass = ContextClassLoader.forName(emittedJoinPoint.getCalleeClassName().replace('/', '.'));
816       JoinPointManager.CompiledJoinPoint jp = JoinPointManager.compileJoinPoint(
817               emittedJoinPoint.getJoinPointType(),
818               callerClass,
819               emittedJoinPoint.getCallerMethodName(),
820               emittedJoinPoint.getCallerMethodDesc(),
821               emittedJoinPoint.getCallerMethodModifiers(),
822               emittedJoinPoint.getCalleeClassName(),
823               emittedJoinPoint.getCalleeMemberName(),
824               emittedJoinPoint.getCalleeMemberDesc(),
825               emittedJoinPoint.getCalleeMemberModifiers(),
826               emittedJoinPoint.getJoinPointHash(),
827               emittedJoinPoint.getJoinPointClassName(),
828               calleeClass,
829               loader,
830               null
831       );
832       return jp;
833     } catch (ClassNotFoundException JavaDoc e) {
834       throw new IOException JavaDoc("Could not compile joinpoint : " + e.toString());
835     }
836   }
837
838   /**
839    * Handles the compilation of the possible cflowAspect associated to the advices that affects the given
840    * joinpoint
841    *
842    * @param jp
843    * @return
844    */

845   private CflowCompiler.CompiledCflowAspect[] compileCflows(JoinPointManager.CompiledJoinPoint jp) {
846     List JavaDoc allCflowBindings = new ArrayList JavaDoc();
847     AdviceInfoContainer adviceInfoContainer = jp.compilationInfo.getInitialModel().getAdviceInfoContainer();
848
849     AdviceInfo[] advices = adviceInfoContainer.getAllAdviceInfos();
850     for (int i = 0; i < advices.length; i++) {
851       AdviceInfo adviceInfo = advices[i];
852       List JavaDoc cflowBindings = CflowBinding.getCflowBindingsForCflowOf(adviceInfo.getExpressionInfo());
853       allCflowBindings.addAll(cflowBindings);
854     }
855
856     List JavaDoc compiledCflows = new ArrayList JavaDoc();
857     for (Iterator JavaDoc iterator = allCflowBindings.iterator(); iterator.hasNext();) {
858       CflowBinding cflowBinding = (CflowBinding) iterator.next();
859       compiledCflows.add(CflowCompiler.compileCflowAspect(cflowBinding.getCflowID()));
860     }
861
862     return (CflowCompiler.CompiledCflowAspect[]) compiledCflows.toArray(new CflowCompiler.CompiledCflowAspect[0]);
863   }
864
865   /**
866    * Given a path d/e/a/b/C.class and a class a.b.C, returns the base dir /d/e
867    *
868    * @param weavedClassFileFullPath
869    * @param weavedClassName
870    * @return
871    */

872   private static String JavaDoc getBaseDir(String JavaDoc weavedClassFileFullPath, String JavaDoc weavedClassName) {
873     String JavaDoc baseDirAbsolutePath = weavedClassFileFullPath;
874     int parentEndIndex = baseDirAbsolutePath.lastIndexOf(File.separatorChar);
875     for (int j = weavedClassName.toCharArray().length - 1; j >= 0; j--) {
876       char c = weavedClassName.toCharArray()[j];
877       if (c == '.') {
878         if (parentEndIndex > 0) {
879           baseDirAbsolutePath = baseDirAbsolutePath.substring(0, parentEndIndex);
880           parentEndIndex = baseDirAbsolutePath.lastIndexOf(File.separatorChar);
881         }
882       }
883     }
884     if (parentEndIndex > 0) {
885       baseDirAbsolutePath = baseDirAbsolutePath.substring(0, parentEndIndex);
886     }
887     return baseDirAbsolutePath;
888   }
889 }
Popular Tags