1 4 5 9 10 package org.openlaszlo.cm; 11 import java.io.InputStream ; 12 import java.io.File ; 13 import java.io.FileOutputStream ; 14 import java.io.FilterOutputStream ; 15 import java.io.FileInputStream ; 16 import java.io.PrintWriter ; 17 import java.io.FileNotFoundException ; 18 import java.io.IOException ; 19 import java.io.Serializable ; 20 import java.util.*; 21 import org.openlaszlo.compiler.*; 22 import org.openlaszlo.server.LPS; 23 import org.openlaszlo.server.Configuration; 24 import org.openlaszlo.servlets.KrankListener; 25 import org.openlaszlo.utils.FileUtils; 26 import org.openlaszlo.utils.LZHttpUtils; 27 import org.openlaszlo.cache.Cache; 28 import org.apache.log4j.*; 29 30 55 public class CompilationManager extends Cache { 56 57 private static Logger mLogger = Logger.getLogger(CompilationManager.class); 58 59 60 protected File mSourceDirectory; 61 62 protected File mCacheDirectory; 63 64 protected CompilerMediaCache mMediaCache; 65 66 protected Properties mProperties = null; 67 68 public static KrankListener sKrankListener = null; 69 70 protected File mLPSJarFile = null; 71 72 public static final String RECOMPILE = "lzrecompile"; 73 74 87 public CompilationManager(File sourceDirectory, File cacheDirectory, Properties props) 88 throws IOException { 89 super("cache", cacheDirectory, props); 90 this.mSourceDirectory = sourceDirectory; 91 this.mCacheDirectory = cacheDirectory; 92 try { 93 cacheDirectory.mkdirs(); 94 } catch (SecurityException se) { 95 } 96 if (!cacheDirectory.exists()) { 97 throw new FileNotFoundException (cacheDirectory.getAbsolutePath() + " does not exist"); 98 } 99 if (!cacheDirectory.canRead()) { 100 throw new IOException ("can't read " + cacheDirectory.getAbsolutePath()); 101 } 102 String p = cacheDirectory.getAbsolutePath() + File.separator + "media"; 103 this.mMediaCache = new CompilerMediaCache(new File (p), props); 104 this.mProperties = props; 105 106 String jd = LPS.getProperty("compMgr.lps.jar.dependency", "true"); 107 if ("true".equals(jd)) { 108 mLPSJarFile = LPS.getLPSJarFile(); 109 } 110 } 111 112 115 public CompilerMediaCache getCompilerMediaCache() { 116 return mMediaCache; 117 } 118 119 123 public void setSourceDirectory(File sourceDirectory) { 124 this.mSourceDirectory = sourceDirectory; 125 } 126 127 130 public boolean clearCacheDirectory() { 131 return mMediaCache.clearCache() && clearCache(); 132 } 133 134 154 public Properties getProperties() { 155 return mProperties; 156 } 157 158 public void setProperty(String key, String value) { 159 mProperties.setProperty(key, value); 160 } 161 162 protected void afterCacheRead(Object metaData) { 163 CachedInfo ci = (CachedInfo)metaData; 164 DependencyTracker dt = ci.getDependencyTracker(); 165 166 dt.updateWebappPath(); 168 169 Canvas canvas = ci.getCanvas(); 171 LPS.configuration.setApplicationOptions 172 (canvas.getFilePath(), canvas.getSecurityOptions()); 173 } 174 175 186 public synchronized File getObjectFile(String pathname, Properties props) 187 throws CompilationError, IOException 188 { 189 mLogger.debug("getObjectFile for " + pathname.toString()); 190 return getItem(pathname, props).getFile(); 191 } 192 193 196 public synchronized static void abortKrankProcess () { 197 KrankListener kt = sKrankListener; 198 mLogger.info("called abortKrankProcess()"); 199 if (kt != null) { 201 kt.setState(KrankListener.ABORTED); 202 try { 203 kt.closeSocket(); 208 kt.interrupt(); 209 } catch (Exception e) { 210 mLogger.debug("abortKrankProcess exception while killing thread: "+e.getMessage()); 211 } 212 } 213 214 } 215 216 230 public synchronized InputStream getObjectStream(String pathname, Properties props) 231 throws CompilationError, IOException 232 { 233 boolean kranking = "true".equals(props.get("krank")); 236 if (kranking) { 237 startKrankWorkflow(pathname, props); 238 } 239 return getItem(pathname, props).getStream(); 240 } 241 242 249 protected void startKrankWorkflow (String pathname, Properties props) { 250 File srcfile = new File (pathname); 251 String fname = new File (pathname).getName(); 253 String prefix; 254 int idx = fname.indexOf("."); 255 if (idx != -1) { 256 prefix = fname.substring(0, idx); 257 } else { 258 prefix = fname; 259 } 260 261 mLogger.debug("getObjectStream pathname= " + pathname.toString()); 263 mLogger.debug("krank prefix= "+prefix); 264 265 269 File xmlFile = new File (srcfile.getParent(), prefix + "obj__.xml"); 270 File krankedSWFfilecopy = new File (srcfile.getParent(), prefix + "__.swf"); 271 272 String myfileName = pathname; 273 Properties myprops = (Properties) props.clone(); 274 mLogger.debug("myprops = "+myprops.toString()); 275 String myprefix = prefix; 276 277 File basepath = new File (srcfile.getParent(), myprefix); 279 File targetSWF = new File (basepath.getAbsolutePath()+".lzo"); 280 File targetSWFgz = new File (basepath.getAbsolutePath()+".lzo.gz"); 281 282 try { 283 targetSWF.delete(); 284 } catch (SecurityException e) { 285 mLogger.error("Could not delete old .lzo file at" + targetSWF.getAbsolutePath()); 286 throw new CompilationError("Could not delete old .lzo file at" + targetSWF.getAbsolutePath()); 287 } 288 289 try { 290 krankedSWFfilecopy.delete(); 291 } catch (SecurityException e) { 292 mLogger.error("Could not delete old swf file at" + krankedSWFfilecopy.getAbsolutePath()); 293 throw new CompilationError("Could not delete old swf file at" + krankedSWFfilecopy.getAbsolutePath()); 294 } 295 296 297 try { 298 targetSWFgz.delete(); 299 } catch (SecurityException e) { 300 mLogger.error("Could not delete old gzipped .lzo file at" + targetSWFgz.getAbsolutePath()); 301 throw new CompilationError("Could not delete gzipped .lzo file at" + targetSWFgz.getAbsolutePath()); 302 } 303 304 try { 305 xmlFile.delete(); 306 } catch (SecurityException e) { 307 mLogger.error("Could not delete old xml data file at" + xmlFile.getAbsolutePath()); 308 throw new CompilationError("Could not delete old xml data file at" + xmlFile.getAbsolutePath()); 309 } 310 311 mLogger.debug("Krank xml data file is " + xmlFile.getAbsolutePath()); 312 313 abortKrankProcess(); 315 316 myprops.remove("Content-Encoding"); 319 File krankedSWF; 320 try { 321 krankedSWF = getObjectFile(myfileName, myprops); 322 } catch (IOException e) { 323 throw new CompilationError("IOException could not locate kranked swf file for "+myfileName+" "+ myprops+": "+e.getMessage()); 324 } 325 326 sKrankListener = new KrankListener( 327 prefix, 328 xmlFile, 329 krankedSWF, 330 krankedSWFfilecopy, 331 basepath, 332 targetSWF, 333 targetSWFgz, 334 myprops); 335 336 sKrankListener.start(); 337 } 338 339 342 public synchronized Canvas getCanvas(String pathname) 343 throws CompilationError, IOException { 344 return getCanvas(pathname, new Properties()); 345 } 346 347 356 public synchronized Canvas getCanvas(String pathname, Properties props) 357 throws CompilationError, IOException { 358 359 mLogger.debug("getCanvas for " + pathname.toString()); 360 CachedInfo info = (CachedInfo)getItem(pathname, props).getMetaData(); 361 return info.getCanvas(); 362 } 363 364 367 public synchronized String getInfoXML(String pathname, Properties props) 368 throws CompilationError, IOException { 369 370 if (pathname == null) { 371 return ""; 372 } 373 374 Properties altProps = (Properties)props.clone(); 375 Item item = getItem(pathname, props); 376 String enc = props.getProperty(LZHttpUtils.CONTENT_ENCODING); 377 long size = item.getSize(); 378 if (enc == null) { 379 enc = ""; 380 } 381 382 boolean isDebug = "true".equals(props.getProperty("debug")); 383 boolean debugExists = isDebug; 384 boolean nondebugExists = !isDebug; 385 boolean debugUptodate = false; 386 boolean nondebugUptodate = false; 387 Properties alt = null; 388 389 if (isDebug) { 390 alt = (Properties)props.clone(); 391 alt.setProperty("debug", "false"); 392 nondebugExists = (getItem(computeKey(pathname, alt)) != null); 393 } else { 394 alt = (Properties)props.clone(); 395 alt.setProperty("debug", "true"); 396 debugExists = (getItem(computeKey(pathname, alt)) != null); 397 } 398 399 if (debugExists) { 400 Properties p; 401 if (!isDebug) { 402 item = getItem(computeKey(pathname, alt)); 403 p = (Properties)alt.clone(); 404 } else { 405 p = (Properties)props.clone(); 406 } 407 CachedInfo info = (CachedInfo)item.getMetaData(); 408 if (info != null) { 409 DependencyTracker tracker = info.getDependencyTracker(); 410 debugUptodate = tracker.isUpToDate(p); 411 } 412 } 413 414 if (nondebugExists) { 415 Properties p; 416 if (isDebug) { 417 item = getItem(computeKey(pathname, alt)); 418 p = (Properties)alt.clone(); 419 } else { 420 item = getItem(computeKey(pathname, props)); 421 p = (Properties)props.clone(); 422 } 423 CachedInfo info = (CachedInfo)item.getMetaData(); 424 if (info != null) { 425 DependencyTracker tracker = info.getDependencyTracker(); 426 nondebugUptodate = tracker.isUpToDate(p); 427 } 428 } 429 430 long gzsize = 0; 431 long ungzsize = 0; 432 433 String version = props.getProperty(CompilationEnvironment.SWFVERSION_PROPERTY); 436 if ("swf5".equals(version)) { 437 if (enc.equals("gzip")) { 438 altProps.setProperty(LZHttpUtils.CONTENT_ENCODING, ""); 439 ungzsize = getItem(pathname, altProps).getSize(); 440 gzsize = size; 441 } else { 442 altProps.setProperty(LZHttpUtils.CONTENT_ENCODING, "gzip"); 443 gzsize = getItem(pathname, altProps).getSize(); 444 ungzsize = size; 445 } 446 } else { 447 ungzsize = size; 448 } 449 450 return "<info size=\"" + ungzsize + 451 "\" gz-size=\"" + gzsize + 452 "\" debug=\"" + isDebug + 453 "\" encoding=\"" + enc + 454 "\" debug-exists=\"" + debugExists + 455 "\" debug-up-to-date=\"" + debugUptodate + 456 "\" nondebug-exists=\"" + nondebugExists + 457 "\" nondebug-up-to-date=\"" + nondebugUptodate + 458 "\" runtime=\"" + version + 459 "\" />"; 460 } 461 462 471 public synchronized long getLastModified(String pathname, Properties props) 472 throws CompilationError, IOException { 473 mLogger.debug("getLastModified for " + pathname.toString()); 474 File file = new File (getItem(pathname, props).getPathName()); 476 return file.lastModified(); 477 } 478 479 485 public synchronized Item getItem(String pathname, Properties props) 486 throws IOException { 487 488 Serializable key = computeKey(pathname, props); 489 String enc = props.getProperty(LZHttpUtils.CONTENT_ENCODING); 490 boolean lockit = false; 491 Item item = findItem(key, enc, lockit); 492 Properties compilationProperties = (Properties) props.clone(); 494 if (!isItemUpToDate(item, pathname, compilationProperties)) { 495 496 Properties props2 = (Properties) props.clone(); 497 if (enc == null || enc.equals("")) { 498 props2.setProperty(LZHttpUtils.CONTENT_ENCODING, "gzip"); 499 } else { 500 props2.setProperty(LZHttpUtils.CONTENT_ENCODING, ""); 501 } 502 Serializable key2 = computeKey(pathname, props2); 503 Item item2 = getItem(key2); 504 if (item2 != null && isItemUpToDate(item2, pathname, props2)) { 505 convertItemEncoding(item2, item, pathname, enc, compilationProperties); 506 } else { 507 compileItem(item, pathname, compilationProperties); 508 } 509 } 510 updateCache(item); 511 return item; 512 } 513 514 525 public synchronized void convertItemEncoding(Item src, Item dest, 526 String pathname, String enc, Properties props) { 527 528 File srcFile = src.getFile(); 529 File destFile = new File (dest.getPathName()); 530 CachedInfo srcInfo = (CachedInfo)src.getMetaData(); 531 try { 532 533 dest.markDirty(); 534 535 File tempFile = null; 536 FileInputStream tempFileStream = null; 537 try { 538 tempFile = File.createTempFile("lzc-", null); 539 mLogger.debug("Temporary file is " + tempFile.getAbsolutePath()); 540 541 mLogger.debug("Re-encoding from " + srcFile.toString() + " to " 542 + tempFile.toString()); 543 544 if (enc != null && enc.equals("gzip")) { 545 FileUtils.encode(srcFile, tempFile, enc); 547 } else { 548 FileUtils.decode(srcFile, tempFile, "gzip"); 550 } 551 552 tempFileStream = new FileInputStream (tempFile); 553 554 dest.update(tempFileStream); 555 556 DependencyTracker dependencyTracker = new DependencyTracker(props); 557 dependencyTracker.copyFiles(srcInfo.getDependencyTracker(), srcFile); 558 dependencyTracker.addFile(destFile); 559 560 CachedInfo info = new CachedInfo(dependencyTracker, srcInfo.getCanvas(), enc); 564 dest.getInfo().setLastModified(destFile.lastModified()); 565 dest.update(info); 566 dest.markClean(); 567 568 } finally { 569 if (tempFileStream != null) { 570 FileUtils.close(tempFileStream); 571 } 572 if (tempFile != null) { 573 tempFile.delete(); 574 } 575 576 mLogger.debug("starting gc"); 578 System.gc(); 579 mLogger.debug("finished gc"); 580 } 581 582 583 } catch (IOException ioe) { 584 CompilationError e = new CompilationError(ioe); 585 e.initPathname(pathname); 586 throw e; 587 } 588 } 589 590 606 public boolean isItemUpToDate(Item item, String pathname, Properties props) 607 throws CompilationError { 608 609 File sourceFile = new File (mSourceDirectory, pathname); 610 File objectFile = new File (item.getPathName()); 611 612 boolean recompile = props.getProperty(RECOMPILE) != null; 613 props.remove(RECOMPILE); 614 615 boolean upToDate = false; 616 617 try { 618 String recompileSwitch = 619 mProperties.getProperty("recompile", "check").intern(); 620 621 if (pathname.endsWith(".lzo")) { 622 return true; } else if (recompile) { 624 mLogger.info("forcing a recompile"); 625 return false; 626 } else if (recompileSwitch == "always") { 627 return false; 628 } else if (recompileSwitch == "never") { 629 return objectFile.exists(); 630 } else if (recompileSwitch == "check") { 631 CachedInfo info = (CachedInfo)item.getMetaData(); 632 DependencyTracker tracker = null; 633 if (info != null) { 634 tracker = info.getDependencyTracker(); 635 } 636 props = (Properties) props.clone(); 638 return (tracker != null) && tracker.isUpToDate(props); 639 } else { 640 throw new IllegalArgumentException ( 641 "invalid value for 'recompile' property"); 642 } 643 } catch (Exception ex) { 644 CompilationError e = new CompilationError(ex); 645 e.initPathname(sourceFile.getPath()); 646 throw e; 647 } 648 } 649 650 668 public synchronized void compileItem(Item item, String pathname, 669 Properties compilationProperties) 670 throws CompilationError 671 { 672 File sourceFile = new File (mSourceDirectory, pathname); 673 File objectFile = new File (item.getPathName()); 674 675 try { 676 677 item.markDirty(); 678 679 org.openlaszlo.compiler.Compiler compiler = 680 new org.openlaszlo.compiler.Compiler(); 681 for (java.util.Enumeration e = getProperties().propertyNames(); 685 e.hasMoreElements(); ) { 686 String key = (String ) e.nextElement(); 687 if (key.startsWith("compiler.")) { 688 compiler.setProperty( 689 key.substring("compiler.".length()), 690 getProperties().getProperty(key)); 691 } 692 } 693 DependencyTracker dependencyTracker = 694 new DependencyTracker(compilationProperties); 695 TrackingFileResolver resolver = 696 new TrackingFileResolver(compiler.getFileResolver(), 697 dependencyTracker); 698 dependencyTracker.addFile(sourceFile); 699 if (mLPSJarFile != null) { 700 dependencyTracker.addFile(mLPSJarFile); 701 } 702 compiler.setFileResolver(resolver); 703 compiler.setMediaCache(mMediaCache); 704 705 Canvas canvas = null; 706 707 File tempFile = null; 708 FileInputStream tempFileStream = null; 709 try { 710 tempFile = File.createTempFile("lzc-", null); 711 mLogger.debug("Temporary file is " + tempFile.getAbsolutePath()); 712 713 mLogger.debug("Compiling " + sourceFile.toString() + " to " 714 + tempFile.toString()); 715 canvas = compiler.compile(sourceFile, tempFile, 716 compilationProperties); 717 718 mLogger.debug("Canvas size is " + canvas.getWidth() + " by " 719 + canvas.getHeight()); 720 721 tempFileStream = new FileInputStream (tempFile); 722 723 item.update(tempFileStream); 724 dependencyTracker.addFile(objectFile); 725 String encoding = compilationProperties.getProperty(LZHttpUtils.CONTENT_ENCODING); 726 CachedInfo info = new CachedInfo(dependencyTracker, canvas, encoding); 730 item.getInfo().setLastModified(objectFile.lastModified()); 731 item.update(info); 732 item.markClean(); 733 734 LPS.configuration.setApplicationOptions(FileUtils.relativePath(pathname, LPS.HOME()), 736 canvas.getSecurityOptions()); 737 738 } finally { 739 if (tempFileStream != null) { 740 FileUtils.close(tempFileStream); 741 } 742 if (tempFile != null) { 743 tempFile.delete(); 744 } 745 746 mLogger.debug("starting gc"); 748 System.gc(); 749 mLogger.debug("finished gc"); 750 } 751 } catch (IOException ioe) { 752 CompilationError e = new CompilationError(ioe); 753 e.initPathname(sourceFile.getPath()); 754 throw e; 755 } 756 } 757 758 761 static Serializable computeKey(String pathname, Properties props) { 762 763 TreeSet sorted = new TreeSet (); 764 for (java.util.Enumeration e = props.propertyNames(); 765 e.hasMoreElements(); ) { 766 String key = (String ) e.nextElement(); 767 if (key.equalsIgnoreCase(RECOMPILE)) 769 continue; 770 771 String value = props.getProperty(key); 772 StringBuffer buf = new StringBuffer (); 773 buf.append(key); 774 buf.append(' '); 775 buf.append(value); 776 777 sorted.add(buf.toString()); 778 } 779 780 StringBuffer buf = new StringBuffer (FileUtils.relativePath(pathname, LPS.HOME())); 781 782 buf.append(' '); 783 for (java.util.Iterator e = sorted.iterator(); e.hasNext(); ) { 784 String str = (String ) e.next(); 785 buf.append(str); 786 } 787 788 mLogger.debug("computeKey: " + buf.toString()); 789 return buf.toString(); 790 } 791 792 798 public File getCacheSourcePath (String srcName, String webappPath) { 799 File src = new File (srcName); 801 if (src.getParentFile() != null) { 802 String baseParent = src.getParentFile().getAbsolutePath(); 803 if (baseParent != null && 804 baseParent.startsWith(mCacheDirectory.getAbsolutePath())) { 805 return new File (srcName); 806 } 807 } 808 if (webappPath == null || ! srcName.startsWith(webappPath)) 812 throw new RuntimeException (srcName + " doesn't begin with " + 813 webappPath); 814 String fixedName = srcName.substring(webappPath.length()); 815 return new File (mCacheDirectory, fixedName); 816 } 817 } 818 819 820 824 class TrackingFileResolver implements FileResolver { 825 private final FileResolver mBaseResolver; 826 private final DependencyTracker mDependencies; 827 828 TrackingFileResolver(FileResolver baseResolver, 829 DependencyTracker tracker) { 830 this.mBaseResolver = baseResolver; 831 this.mDependencies = tracker; 832 } 833 834 842 public File resolve(String pathname, String base) 843 throws FileNotFoundException 844 { 845 File file = mBaseResolver.resolve(pathname, base); 846 mDependencies.addFile(file); 847 return file; 848 } 849 850 851 859 } 860 | Popular Tags |