| 1 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 ; 23 import java.io.ByteArrayOutputStream ; 24 import java.io.File ; 25 import java.io.FileInputStream ; 26 import java.io.FileOutputStream ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.net.URL ; 30 import java.net.URLClassLoader ; 31 import java.text.SimpleDateFormat ; 32 import java.util.ArrayList ; 33 import java.util.Date ; 34 import java.util.Enumeration ; 35 import java.util.HashMap ; 36 import java.util.Hashtable ; 37 import java.util.Iterator ; 38 import java.util.List ; 39 import java.util.Map ; 40 import java.util.jar.Attributes ; 41 import java.util.jar.Manifest ; 42 import java.util.zip.CRC32 ; 43 import java.util.zip.ZipEntry ; 44 import java.util.zip.ZipFile ; 45 import java.util.zip.ZipOutputStream ; 46 47 86 public class AspectWerkzC { 87 private static final String COMMAND_LINE_OPTION_DASH = "-"; 89 private static final String COMMAND_LINE_OPTION_VERBOSE = "-verbose"; 90 private static final String COMMAND_LINE_OPTION_DETAILS = "-details"; 91 private static final String COMMAND_LINE_OPTION_GENJP = "-genjp"; 92 private static final String COMMAND_LINE_OPTION_HALT = "-haltOnError"; 93 private static final String COMMAND_LINE_OPTION_VERIFY = "-verify"; 94 private static final String COMMAND_LINE_OPTION_CLASSPATH = "-cp"; 95 private static final String COMMAND_LINE_OPTION_TARGETS = "compile.targets"; 96 97 100 private static final String PRE_PROCESSOR_CLASSNAME_PROPERTY = "aspectwerkz.classloader.preprocessor"; 101 102 private final static String AW_TRANSFORM_DETAILS = "aspectwerkz.transform.details"; 103 104 107 private static final String PRE_PROCESSOR_CLASSNAME_DEFAULT = "org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor"; 108 109 private final static String MF_CUSTOM_DATE = "X-AspectWerkzC-created"; 110 111 private final static String MF_CUSTOM_PP = "X-AspectWerkzC-preprocessor"; 112 113 private final static String MF_CUSTOM_COMMENT = "X-AspectWerkzC-comment"; 114 115 private final static String MF_CUSTOM_COMMENT_VALUE = "AspectWerkzC - AspectWerkz compiler, aspectwerkz.codehaus.org"; 116 117 private final static SimpleDateFormat DF = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); 118 119 private final static String 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 backupDir = BACKUP_DIR; 128 129 132 private URLClassLoader compilationLoader = null; 133 134 137 private ClassPreProcessor preprocessor = null; 138 private boolean isAspectWerkzPreProcessor = false; 139 140 143 private int sourceIndex; 144 145 148 private Map backupMap = new HashMap (); 149 150 153 private Map successMap = new HashMap (); 154 155 private long timer; 156 157 160 private Utility utility; 161 162 165 public AspectWerkzC() { 166 sourceIndex = 0; 168 utility = new Utility(); 169 timer = System.currentTimeMillis(); 170 } 171 172 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 backup) { 199 this.backupDir = backup; 200 } 201 202 public Utility getUtility() { 203 return utility; 204 } 205 206 210 public void setPreprocessor(String preprocessor) throws CompileException { 211 try { 212 Class 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 e) { 220 throw new CompileException("failed to instantiate preprocessor " + preprocessor, e); 221 } 222 } 223 224 227 public void backup(File source, int index) { 228 File dest = new File (this.backupDir + File.separator + index + File.separator + source.getName()); 230 utility.backupFile(source, dest); 231 232 backupMap.put(source, dest); 234 } 235 236 239 public void restoreBackup() { 240 for (Iterator i = backupMap.keySet().iterator(); i.hasNext();) { 241 File source = (File ) i.next(); 242 if (!successMap.containsKey(source)) { 243 File dest = (File ) backupMap.get(source); 244 utility.backupFile(dest, source); 245 } 246 } 247 } 248 249 252 public void postCompile(String message) { 253 restoreBackup(); 254 utility.log(" [backup] removing backup"); 255 utility.deleteDir(new File (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 i = backupMap.keySet().iterator(); i.hasNext();) { 260 File source = (File ) 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 277 public void doCompile(File sourceFile, String prefixPackage) throws CompileException { 278 if (sourceFile.isDirectory()) { 279 File [] 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 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 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 302 public void compileClass(File file, String packaging) throws CompileException { 303 InputStream in = null; 304 FileOutputStream fos = null; 305 try { 306 utility.log(" [compile] " + file.getCanonicalPath()); 307 308 ByteArrayOutputStream bos = new ByteArrayOutputStream (); 310 in = new FileInputStream (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 String className = file.getName().substring(0, file.getName().length() - 6); 322 if (packaging != null) { 323 className = packaging + '.' + className; 324 } 325 326 AspectWerkzPreProcessor.Output out = null; 328 try { 329 out = preProcess(preprocessor, className, bos.toByteArray(), compilationLoader); 330 } catch (Throwable t) { 331 throw new CompileException("weaver failed for class: " + className, t); 332 } 333 334 fos = new FileOutputStream (file); 336 fos.write(out.bytecode); 337 fos.close(); 338 339 if (out.emittedJoinPoints != null && genJp) { 341 for (int i = 0; i < out.emittedJoinPoints.length; i++) { 342 EmittedJoinPoint emittedJoinPoint = out.emittedJoinPoints[i]; 343 String jpClassNoPackage = emittedJoinPoint.getJoinPointClassName(); 345 if (jpClassNoPackage.indexOf('/')>0) { 346 jpClassNoPackage = jpClassNoPackage.substring(jpClassNoPackage.lastIndexOf('/')); 347 } 348 File jpFile = new File (file.getParent(), jpClassNoPackage+".class"); 349 utility.log(" [genjp] " + jpFile.getCanonicalPath()); 350 FileOutputStream jpFos = new FileOutputStream (jpFile); 351 JoinPointManager.CompiledJoinPoint compiledJp = compileJoinPoint(emittedJoinPoint, compilationLoader); 352 jpFos.write(compiledJp.bytecode); 353 jpFos.close(); 354 355 CflowCompiler.CompiledCflowAspect[] compiledCflowAspects = compileCflows(compiledJp); 357 if (compiledCflowAspects.length > 0) { 358 String baseDirAbsolutePath = getBaseDir(file.getCanonicalPath(), className); 359 for (int j = 0; j < compiledCflowAspects.length; j++) { 360 CflowCompiler.CompiledCflowAspect compiledCflowAspect = compiledCflowAspects[j]; 361 File cflowFile = new File (baseDirAbsolutePath + File.separatorChar + compiledCflowAspect.className.replace('/', File.separatorChar) + ".class"); 362 (new File (cflowFile.getParent())).mkdirs(); 363 utility.log(" [genjp] (cflow) " + cflowFile.getCanonicalPath()); 364 FileOutputStream cflowFos = new FileOutputStream (cflowFile); 365 cflowFos.write(compiledCflowAspect.bytecode); 366 cflowFos.close(); 367 } 368 } 369 } 370 } 371 372 if (verify) { 374 URLClassLoader 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 t) { 382 utility.log(" [verify] corrupted class: " + className); 383 throw new CompileException("corrupted class: " + className, t); 384 } 385 } 386 } catch (IOException e) { 387 throw new CompileException("compile " + file.getAbsolutePath() + " failed", e); 388 } finally { 389 try { 390 in.close(); 391 } catch (Throwable e) { 392 ; 393 } 394 try { 395 fos.close(); 396 } catch (Throwable e) { 397 ; 398 } 399 } 400 } 401 402 406 public void compileJar(File file) throws CompileException { 407 utility.log(" [compilejar] " + file.getAbsolutePath()); 408 409 File workingFile = new File (file.getAbsolutePath() + ".aspectwerkzc"); 411 if (workingFile.exists()) { 412 workingFile.delete(); 413 } 414 ZipFile zip = null; 415 ZipOutputStream zos = null; 416 try { 417 zip = new ZipFile (file); 418 zos = new ZipOutputStream (new FileOutputStream (workingFile)); 419 for (Enumeration e = zip.entries(); e.hasMoreElements();) { 420 ZipEntry ze = (ZipEntry ) e.nextElement(); 421 422 InputStream in = zip.getInputStream(ze); 424 ByteArrayOutputStream bos = new ByteArrayOutputStream (); 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 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 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 t) { 445 throw new CompileException("weaver failed for class: " + className, t); 446 } 447 } else { 448 out = null; 449 transformed = bos.toByteArray(); 450 } 451 452 if (ze.getName().toLowerCase().equals("meta-inf/manifest.mf")) { 454 try { 455 Manifest mf = new Manifest (new ByteArrayInputStream (transformed)); 456 Attributes at = mf.getMainAttributes(); 457 at.putValue(MF_CUSTOM_DATE, DF.format(new Date ())); 458 at.putValue(MF_CUSTOM_PP, preprocessor.getClass().getName()); 459 at.putValue(MF_CUSTOM_COMMENT, MF_CUSTOM_COMMENT_VALUE); 460 461 bos.reset(); 463 mf.write(bos); 464 transformed = bos.toByteArray(); 465 } catch (Exception emf) { 466 emf.printStackTrace(); 467 } 468 } 469 470 ZipEntry transformedZe = new ZipEntry (ze.getName()); 472 transformedZe.setSize(transformed.length); 473 CRC32 crc = new CRC32 (); 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 (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 jpZe = new ZipEntry (emittedJoinPoint.getJoinPointClassName()+".class"); 487 jpZe.setSize(compiledJp.bytecode.length); 488 CRC32 jpCrc = new CRC32 (); 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 cflowZe = new ZipEntry (compiledCflowAspect.className+".class"); 501 cflowZe.setSize(compiledCflowAspect.bytecode.length); 502 CRC32 cflowCrc = new CRC32 (); 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 File swap = new File (file.getAbsolutePath() + ".swap.aspectwerkzc"); 518 utility.backupFile(file, swap); 519 try { 520 utility.backupFile(workingFile, new File (file.getAbsolutePath())); 521 workingFile.delete(); 522 swap.delete(); 523 } catch (Exception e) { 524 utility.backupFile(swap, new File (file.getAbsolutePath())); 526 workingFile.delete(); 527 throw new CompileException("compile " + file.getAbsolutePath() + " failed", e); 528 } 529 } catch (IOException e) { 530 throw new CompileException("compile " + file.getAbsolutePath() + " failed", e); 531 } finally { 532 try { 533 zos.close(); 534 } catch (Throwable e) { 535 ; 536 } 537 try { 538 zip.close(); 539 } catch (Throwable e) { 540 ; 541 } 542 } 543 } 544 545 550 public boolean compile(File 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 successMap.put(source, Boolean.TRUE); 563 return true; 564 } 565 566 572 public void setCompilationPath(File [] targets, ClassLoader parentLoader) { 573 URL [] urls = new URL [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 e) { 580 System.err.println("bad target " + targets[i]); 581 } 582 } 583 584 compilationLoader = new URLClassLoader (urls, parentLoader); 585 } 586 587 590 public static boolean isJarFile(File source) { 591 return (source.isFile() && (source.getName().toLowerCase().endsWith(".jar") || source 592 .getName().toLowerCase().endsWith(".zip"))); 593 } 594 595 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 614 private static AspectWerkzC createCompiler(Map params) { 615 AspectWerkzC compiler = new AspectWerkzC(); 616 617 for (Iterator it = params.entrySet().iterator(); it.hasNext();) { 618 Map.Entry param = (Map.Entry ) 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 647 public static void compile(AspectWerkzC compiler, 648 ClassLoader classLoader, 649 String preProcessor, 650 List classpath, 651 List targets) { 652 List fullPath = new |