KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > compiler > AspectWerkzC


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

86 public class AspectWerkzC {
87     // COMMAND LINE OPTIONS
88
private static final String JavaDoc COMMAND_LINE_OPTION_DASH = "-";
89     private static final String JavaDoc COMMAND_LINE_OPTION_VERBOSE = "-verbose";
90     private static final String JavaDoc COMMAND_LINE_OPTION_DETAILS = "-details";
91     private static final String JavaDoc COMMAND_LINE_OPTION_GENJP = "-genjp";
92     private static final String JavaDoc COMMAND_LINE_OPTION_HALT = "-haltOnError";
93     private static final String JavaDoc COMMAND_LINE_OPTION_VERIFY = "-verify";
94     private static final String JavaDoc COMMAND_LINE_OPTION_CLASSPATH = "-cp";
95     private static final String JavaDoc COMMAND_LINE_OPTION_TARGETS = "compile.targets";
96
97     /**
98      * option used to defined the class preprocessor
99      */

100     private static final String JavaDoc PRE_PROCESSOR_CLASSNAME_PROPERTY = "aspectwerkz.classloader.preprocessor";
101
102     private final static String JavaDoc AW_TRANSFORM_DETAILS = "aspectwerkz.transform.details";
103
104     /**
105      * default class preprocessor
106      */

107     private static final String JavaDoc PRE_PROCESSOR_CLASSNAME_DEFAULT = "org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor";
108
109     private final static String JavaDoc MF_CUSTOM_DATE = "X-AspectWerkzC-created";
110
111     private final static String JavaDoc MF_CUSTOM_PP = "X-AspectWerkzC-preprocessor";
112
113     private final static String JavaDoc MF_CUSTOM_COMMENT = "X-AspectWerkzC-comment";
114
115     private final static String JavaDoc MF_CUSTOM_COMMENT_VALUE = "AspectWerkzC - AspectWerkz compiler, aspectwerkz.codehaus.org";
116
117     private final static SimpleDateFormat JavaDoc DF = new SimpleDateFormat JavaDoc("yyyy-MM-dd HH:mm:ss");
118
119     private final static String JavaDoc BACKUP_DIR = "_aspectwerkzc";
120
121     private boolean verify = false;
122
123     private boolean genJp = false;
124
125     private boolean haltOnError = false;
126
127     private String JavaDoc backupDir = BACKUP_DIR;
128
129     /**
130      * class loader in which the effective compilation occurs, child of system classloader
131      */

132     private URLClassLoader JavaDoc compilationLoader = null;
133
134     /**
135      * class preprocessor instance used to compile targets
136      */

137     private ClassPreProcessor preprocessor = null;
138     private boolean isAspectWerkzPreProcessor = false;
139
140     /**
141      * index to keep track of {target i} backups
142      */

143     private int sourceIndex;
144
145     /**
146      * Maps the target file to the target backup file
147      */

148     private Map JavaDoc backupMap = new HashMap JavaDoc();
149
150     /**
151      * Maps the target file to a status indicating compilation was successfull
152      */

153     private Map JavaDoc successMap = new HashMap JavaDoc();
154
155     private long timer;
156
157     /**
158      * Utility for file manipulation
159      */

160     private Utility utility;
161
162     /**
163      * Construct a new Utility, restore the index for backup
164      */

165     public AspectWerkzC() {
166         //@todo check for multiple transformation in compiler or in preprocessor ?
167
sourceIndex = 0;
168         utility = new Utility();
169         timer = System.currentTimeMillis();
170     }
171
172     /*
173      * public void log(String msg) { utility.log(msg); } public void log(String msg, Throwable t) { utility.log(msg);
174      * t.printStackTrace(); }
175      */

176     public void setVerbose(boolean verbose) {
177         utility.setVerbose(verbose);
178     }
179
180     public void setGenJp(boolean genpJp) {
181         this.genJp = genpJp;
182     }
183
184     public void setHaltOnError(boolean haltOnError) {
185         this.haltOnError = haltOnError;
186     }
187
188     public void setVerify(boolean verify) {
189         this.verify = verify;
190     }
191
192     public void setDetails(boolean details) {
193         if (details) {
194             System.setProperty(AW_TRANSFORM_DETAILS, "true");
195         }
196     }
197
198     public void setBackupDir(String JavaDoc backup) {
199         this.backupDir = backup;
200     }
201
202     public Utility getUtility() {
203         return utility;
204     }
205
206     /**
207      * Sets the ClassPreProcessor implementation to use. <p/>The ClassLoader will be set to System ClassLoader when
208      * transform(className, byteCode, callerClassLoader) will be called to compile a class.
209      */

210     public void setPreprocessor(String JavaDoc preprocessor) throws CompileException {
211         try {
212             Class JavaDoc pp = Class.forName(preprocessor);
213             this.preprocessor = (ClassPreProcessor) pp.newInstance();
214             this.preprocessor.initialize();
215
216             if (this.preprocessor instanceof AspectWerkzPreProcessor) {
217                 isAspectWerkzPreProcessor = true;
218             }
219         } catch (Exception JavaDoc e) {
220             throw new CompileException("failed to instantiate preprocessor " + preprocessor, e);
221         }
222     }
223
224     /**
225      * Backup source file in backup_dir/index/file. The backupMap is updated for further rollback
226      */

227     public void backup(File JavaDoc source, int index) {
228         // backup source in BACKUP/index dir
229
File JavaDoc dest = new File JavaDoc(this.backupDir + File.separator + index + File.separator + source.getName());
230         utility.backupFile(source, dest);
231
232         // add to backupMap in case of rollback
233
backupMap.put(source, dest);
234     }
235
236     /**
237      * Restore the backup registered
238      */

239     public void restoreBackup() {
240         for (Iterator JavaDoc i = backupMap.keySet().iterator(); i.hasNext();) {
241             File JavaDoc source = (File JavaDoc) i.next();
242             if (!successMap.containsKey(source)) {
243                 File JavaDoc dest = (File JavaDoc) backupMap.get(source);
244                 utility.backupFile(dest, source);
245             }
246         }
247     }
248
249     /**
250      * Delete backup dir at the end of all compilation
251      */

252     public void postCompile(String JavaDoc message) {
253         restoreBackup();
254         utility.log(" [backup] removing backup");
255         utility.deleteDir(new File JavaDoc(this.backupDir));
256         long ms = Math.max(System.currentTimeMillis() - timer, 1 * 1000);
257         System.out.println("( " + (int) (ms / 1000) + " s ) " + message);
258         if (!haltOnError) {
259             for (Iterator JavaDoc i = backupMap.keySet().iterator(); i.hasNext();) {
260                 File JavaDoc source = (File JavaDoc) i.next();
261                 if (successMap.containsKey(source)) {
262                     System.out.println("SUCCESS: " + source);
263                 } else {
264                     System.out.println("FAILED : " + source);
265                 }
266             }
267         }
268     }
269
270     /**
271      * Compile sourceFile. If prefixPackage is not null, assumes it is the class package information. <p/>Handles :
272      * <ul>
273      * <li>directory recursively (exploded jar)</li>
274      * <li>jar / zip file</li>
275      * </ul>
276      */

277     public void doCompile(File JavaDoc sourceFile, String JavaDoc prefixPackage) throws CompileException {
278         if (sourceFile.isDirectory()) {
279             File JavaDoc[] classes = sourceFile.listFiles();
280             for (int i = 0; i < classes.length; i++) {
281                 if (classes[i].isDirectory() && !(this.backupDir.equals(classes[i].getName()))) {
282                     String JavaDoc packaging = (prefixPackage != null) ? (prefixPackage + "." + classes[i]
283                             .getName()) : classes[i].getName();
284                     doCompile(classes[i], packaging);
285                 } else if (classes[i].getName().toLowerCase().endsWith(".class")) {
286                     compileClass(classes[i], prefixPackage);
287                 } else if (isJarFile(classes[i])) {
288                     //@todo: jar encountered in a dir - use case ??
289
compileJar(classes[i]);
290                 }
291             }
292         } else if (sourceFile.getName().toLowerCase().endsWith(".class")) {
293             compileClass(sourceFile, null);
294         } else if (isJarFile(sourceFile)) {
295             compileJar(sourceFile);
296         }
297     }
298
299     /**
300      * Compiles .class file using fileName as className and given packaging as package name
301      */

302     public void compileClass(File JavaDoc file, String JavaDoc packaging) throws CompileException {
303         InputStream JavaDoc in = null;
304         FileOutputStream JavaDoc fos = null;
305         try {
306             utility.log(" [compile] " + file.getCanonicalPath());
307
308             // dump bytecode in byte[]
309
ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
310             in = new FileInputStream JavaDoc(file);
311             byte[] buffer = new byte[1024];
312             while (in.available() > 0) {
313                 int length = in.read(buffer);
314                 if (length == -1) {
315                     break;
316                 }
317                 bos.write(buffer, 0, length);
318             }
319
320             // rebuild className
321
String JavaDoc className = file.getName().substring(0, file.getName().length() - 6);
322             if (packaging != null) {
323                 className = packaging + '.' + className;
324             }
325
326             // transform
327
AspectWerkzPreProcessor.Output out = null;
328             try {
329                 out = preProcess(preprocessor, className, bos.toByteArray(), compilationLoader);
330             } catch (Throwable JavaDoc t) {
331                 throw new CompileException("weaver failed for class: " + className, t);
332             }
333
334             // override file
335
fos = new FileOutputStream JavaDoc(file);
336             fos.write(out.bytecode);
337             fos.close();
338
339             // if AW and genjp
340
if (out.emittedJoinPoints != null && genJp) {
341                 for (int i = 0; i < out.emittedJoinPoints.length; i++) {
342                     EmittedJoinPoint emittedJoinPoint = out.emittedJoinPoints[i];
343                     //TODO we assume same package here.. make more generic
344
String JavaDoc jpClassNoPackage = emittedJoinPoint.getJoinPointClassName();
345                     if (jpClassNoPackage.indexOf('/')>0) {
346                         jpClassNoPackage = jpClassNoPackage.substring(jpClassNoPackage.lastIndexOf('/'));
347                     }
348                     File JavaDoc jpFile = new File JavaDoc(file.getParent(), jpClassNoPackage+".class");
349                     utility.log(" [genjp] " + jpFile.getCanonicalPath());
350                     FileOutputStream JavaDoc jpFos = new FileOutputStream JavaDoc(jpFile);
351                     JoinPointManager.CompiledJoinPoint compiledJp = compileJoinPoint(emittedJoinPoint, compilationLoader);
352                     jpFos.write(compiledJp.bytecode);
353                     jpFos.close();
354
355                     // handle cflow if any
356
CflowCompiler.CompiledCflowAspect[] compiledCflowAspects = compileCflows(compiledJp);
357                     if (compiledCflowAspects.length > 0) {
358                         String JavaDoc baseDirAbsolutePath = getBaseDir(file.getCanonicalPath(), className);
359                         for (int j = 0; j < compiledCflowAspects.length; j++) {
360                             CflowCompiler.CompiledCflowAspect compiledCflowAspect = compiledCflowAspects[j];
361                             File JavaDoc cflowFile = new File JavaDoc(baseDirAbsolutePath + File.separatorChar + compiledCflowAspect.className.replace('/', File.separatorChar) + ".class");
362                             (new File JavaDoc(cflowFile.getParent())).mkdirs();
363                             utility.log(" [genjp] (cflow) " + cflowFile.getCanonicalPath());
364                             FileOutputStream JavaDoc cflowFos = new FileOutputStream JavaDoc(cflowFile);
365                             cflowFos.write(compiledCflowAspect.bytecode);
366                             cflowFos.close();
367                         }
368                     }
369                 }
370             }
371
372             // verify modified class
373
if (verify) {
374                 URLClassLoader JavaDoc verifier = new VerifierClassLoader(
375                         compilationLoader.getURLs(),
376                         ClassLoader.getSystemClassLoader()
377                 );
378                 try {
379                     utility.log(" [verify] " + className);
380                     Class.forName(className, false, verifier);
381                 } catch (Throwable JavaDoc t) {
382                     utility.log(" [verify] corrupted class: " + className);
383                     throw new CompileException("corrupted class: " + className, t);
384                 }
385             }
386         } catch (IOException JavaDoc e) {
387             throw new CompileException("compile " + file.getAbsolutePath() + " failed", e);
388         } finally {
389             try {
390                 in.close();
391             } catch (Throwable JavaDoc e) {
392                 ;
393             }
394             try {
395                 fos.close();
396             } catch (Throwable JavaDoc e) {
397                 ;
398             }
399         }
400     }
401
402     /**
403      * Compile all .class encountered in the .jar/.zip file. <p/>The target.jar is compiled in the
404      * target.jar.aspectwerkzc and the target.jar.aspectwerkzc then overrides target.jar on success.
405      */

406     public void compileJar(File JavaDoc file) throws CompileException {
407         utility.log(" [compilejar] " + file.getAbsolutePath());
408
409         // create an empty jar target.jar.aspectwerkzc
410
File JavaDoc workingFile = new File JavaDoc(file.getAbsolutePath() + ".aspectwerkzc");
411         if (workingFile.exists()) {
412             workingFile.delete();
413         }
414         ZipFile JavaDoc zip = null;
415         ZipOutputStream JavaDoc zos = null;
416         try {
417             zip = new ZipFile JavaDoc(file);
418             zos = new ZipOutputStream JavaDoc(new FileOutputStream JavaDoc(workingFile));
419             for (Enumeration JavaDoc e = zip.entries(); e.hasMoreElements();) {
420                 ZipEntry JavaDoc ze = (ZipEntry JavaDoc) e.nextElement();
421
422                 // dump bytes read in byte[]
423
InputStream JavaDoc in = zip.getInputStream(ze);
424                 ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
425                 byte[] buffer = new byte[1024];
426                 while (in.available() > 0) {
427                     int length = in.read(buffer);
428                     if (length == -1) {
429                         break;
430                     }
431                     bos.write(buffer, 0, length);
432                 }
433                 in.close();
434
435                 // transform only .class file
436
AspectWerkzPreProcessor.Output out = null;
437                 byte[] transformed = null;
438                 if (ze.getName().toLowerCase().endsWith(".class")) {
439                     utility.log(" [compilejar] compile " + file.getName() + ":" + ze.getName());
440                     String JavaDoc className = ze.getName().substring(0, ze.getName().length() - 6);
441                     try {
442                         out = preProcess(preprocessor, className, bos.toByteArray(), compilationLoader);
443                         transformed = out.bytecode;
444                     } catch (Throwable JavaDoc t) {
445                         throw new CompileException("weaver failed for class: " + className, t);
446                     }
447                 } else {
448                     out = null;
449                     transformed = bos.toByteArray();
450                 }
451
452                 // customize Manifest.mf
453
if (ze.getName().toLowerCase().equals("meta-inf/manifest.mf")) {
454                     try {
455                         Manifest JavaDoc mf = new Manifest JavaDoc(new ByteArrayInputStream JavaDoc(transformed));
456                         Attributes JavaDoc at = mf.getMainAttributes();
457                         at.putValue(MF_CUSTOM_DATE, DF.format(new Date JavaDoc()));
458                         at.putValue(MF_CUSTOM_PP, preprocessor.getClass().getName());
459                         at.putValue(MF_CUSTOM_COMMENT, MF_CUSTOM_COMMENT_VALUE);
460
461                         // re read the updated manifest
462
bos.reset();
463                         mf.write(bos);
464                         transformed = bos.toByteArray();
465                     } catch (Exception JavaDoc emf) {
466                         emf.printStackTrace();
467                     }
468                 }
469
470                 // update target.jar.aspectwerkzc working file
471
ZipEntry JavaDoc transformedZe = new ZipEntry JavaDoc(ze.getName());
472                 transformedZe.setSize(transformed.length);
473                 CRC32 JavaDoc crc = new CRC32 JavaDoc();
474                 crc.update(transformed);
475                 transformedZe.setCrc(crc.getValue());
476                 transformedZe.setMethod(ze.getMethod());
477                 zos.putNextEntry(transformedZe);
478                 zos.write(transformed, 0, transformed.length);
479
480                 // if AW and genjp
481
if (genJp && out != null && out.emittedJoinPoints!=null) {
482                     for (int i = 0; i < out.emittedJoinPoints.length; i++) {
483                         EmittedJoinPoint emittedJoinPoint = out.emittedJoinPoints[i];
484                         JoinPointManager.CompiledJoinPoint compiledJp = compileJoinPoint(emittedJoinPoint, compilationLoader);
485                         utility.log(" [compilejar] (genjp) " + file.getName() + ":" + emittedJoinPoint.getJoinPointClassName());
486                         ZipEntry JavaDoc jpZe = new ZipEntry JavaDoc(emittedJoinPoint.getJoinPointClassName()+".class");
487                         jpZe.setSize(compiledJp.bytecode.length);
488                         CRC32 JavaDoc jpCrc = new CRC32 JavaDoc();
489                         jpCrc.update(compiledJp.bytecode);
490                         jpZe.setCrc(jpCrc.getValue());
491                         jpZe.setMethod(ze.getMethod());
492                         zos.putNextEntry(jpZe);
493                         zos.write(compiledJp.bytecode, 0, compiledJp.bytecode.length);
494
495                         CflowCompiler.CompiledCflowAspect[] compiledCflowAspects = compileCflows(compiledJp);
496                         if (compiledCflowAspects.length > 0) {
497                             for (int j = 0; j < compiledCflowAspects.length; j++) {
498                                 CflowCompiler.CompiledCflowAspect compiledCflowAspect = compiledCflowAspects[j];
499                                 utility.log(" [compilejar] (genjp) (cflow) " + file.getName() + ":" + compiledCflowAspect.className);
500                                 ZipEntry JavaDoc cflowZe = new ZipEntry JavaDoc(compiledCflowAspect.className+".class");
501                                 cflowZe.setSize(compiledCflowAspect.bytecode.length);
502                                 CRC32 JavaDoc cflowCrc = new CRC32 JavaDoc();
503                                 cflowCrc.update(compiledCflowAspect.bytecode);
504                                 cflowZe.setCrc(cflowCrc.getValue());
505                                 cflowZe.setMethod(ze.getMethod());
506                                 zos.putNextEntry(cflowZe);
507                                 zos.write(compiledCflowAspect.bytecode, 0, compiledCflowAspect.bytecode.length);
508                             }
509                         }
510                     }
511                 }
512             }
513             zip.close();
514             zos.close();
515
516             // replace file by workingFile
517
File JavaDoc swap = new File JavaDoc(file.getAbsolutePath() + ".swap.aspectwerkzc");
518             utility.backupFile(file, swap);
519             try {
520                 utility.backupFile(workingFile, new File JavaDoc(file.getAbsolutePath()));
521                 workingFile.delete();
522                 swap.delete();
523             } catch (Exception JavaDoc e) {
524                 // restore swapFile
525
utility.backupFile(swap, new File JavaDoc(file.getAbsolutePath()));
526                 workingFile.delete();
527                 throw new CompileException("compile " + file.getAbsolutePath() + " failed", e);
528             }
529         } catch (IOException JavaDoc e) {
530             throw new CompileException("compile " + file.getAbsolutePath() + " failed", e);
531         } finally {
532             try {
533                 zos.close();
534             } catch (Throwable JavaDoc e) {
535                 ;
536             }
537             try {
538                 zip.close();
539             } catch (Throwable JavaDoc e) {
540                 ;
541             }
542         }
543     }
544
545     /**
546      * Compile given target.
547      *
548      * @return false if process should stop
549      */

550     public boolean compile(File JavaDoc source) {
551         sourceIndex++;
552         backup(source, sourceIndex);
553         try {
554             doCompile(source, null);
555         } catch (CompileException e) {
556             utility.log(" [aspectwerkzc] compilation encountered an error");
557             e.printStackTrace();
558             return (!haltOnError);
559         }
560
561         // compile sucessfull
562
successMap.put(source, Boolean.TRUE);
563         return true;
564     }
565
566     /**
567      * Set up the compilation path by building a URLClassLoader with all targets in
568      *
569      * @param targets to add to compilationLoader classpath
570      * @param parentLoader the parent ClassLoader used by the new one
571      */

572     public void setCompilationPath(File JavaDoc[] targets, ClassLoader JavaDoc parentLoader) {
573         URL JavaDoc[] urls = new URL JavaDoc[targets.length];
574         int j = 0;
575         for (int i = 0; i < targets.length; i++) {
576             try {
577                 urls[j] = targets[i].getCanonicalFile().toURL();
578                 j++;
579             } catch (IOException JavaDoc e) {
580                 System.err.println("bad target " + targets[i]);
581             }
582         }
583
584         compilationLoader = new URLClassLoader JavaDoc(urls, parentLoader);
585     }
586
587     /**
588      * Test if file is a zip/jar file
589      */

590     public static boolean isJarFile(File JavaDoc source) {
591         return (source.isFile() && (source.getName().toLowerCase().endsWith(".jar") || source
592                 .getName().toLowerCase().endsWith(".zip")));
593     }
594
595     /**
596      * Usage message
597      */

598     public static void doHelp() {
599         System.out.println("--- AspectWerkzC compiler ---");
600         System.out.println("Usage:");
601         System.out
602                 .println(
603                         "java -cp ... org.codehaus.aspectwerkz.compiler.AspectWerkzC [-verbose] [-haltOnError] [-verify] <target 1> .. <target n>"
604                 );
605         System.out.println(" <target i> : exploded dir, jar, zip files to compile");
606     }
607
608     /**
609      * Creates and configures an AspectWerkzC compiler.
610      *
611      * @param params a map containing the compiler parameters
612      * @return a new and configured <CODE>AspectWerkzC</CODE>
613      */

614     private static AspectWerkzC createCompiler(Map JavaDoc params) {
615         AspectWerkzC compiler = new AspectWerkzC();
616
617         for (Iterator JavaDoc it = params.entrySet().iterator(); it.hasNext();) {
618             Map.Entry JavaDoc param = (Map.Entry JavaDoc) it.next();
619
620             if (COMMAND_LINE_OPTION_VERBOSE.equals(param.getKey())) {
621                 compiler.setVerbose(Boolean.TRUE.equals(param.getValue()));
622             } else if (COMMAND_LINE_OPTION_HALT.equals(param.getKey())) {
623                 compiler.setHaltOnError(Boolean.TRUE.equals(param.getValue()));
624             } else if (COMMAND_LINE_OPTION_VERIFY.equals(param.getKey())) {
625                 compiler.setVerify(Boolean.TRUE.equals(param.getValue()));
626             } else if (COMMAND_LINE_OPTION_GENJP.equals(param.getKey())) {
627                 compiler.setGenJp(Boolean.TRUE.equals(param.getValue()));
628             } else if (COMMAND_LINE_OPTION_DETAILS.equals(param.getKey())) {
629                 compiler.setDetails(Boolean.TRUE.equals(param.getValue()));
630             }
631         }
632
633         return compiler;
634     }
635
636     /**
637      * Runs the AspectWerkzC compiler for the <tt>targets</tt> files.
638      *
639      * @param compiler a configured <CODE>AspectWerkzC</CODE>
640      * @param classLoader the class loader to be used
641      * @param preProcessor fully qualified name of the preprocessor class.
642      * If <tt>null</tt> than the default is used
643      * (<CODE>org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor</CODE>)
644      * @param classpath list of Files representing the classpath (List<File>)
645      * @param targets the list of target files (List<File>)
646      */

647     public static void compile(AspectWerkzC compiler,
648                                ClassLoader JavaDoc classLoader,
649                                String JavaDoc preProcessor,
650                                List JavaDoc classpath,
651                                List JavaDoc targets) {
652         List JavaDoc fullPath = new