Mon, 07 Mar 2011 17:39:42 -0800
7021927: javac: regression in performance
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Mon Mar 07 13:45:06 2011 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Mon Mar 07 17:39:42 2011 -0800 1.3 @@ -89,7 +89,7 @@ 1.4 1.5 private FSInfo fsInfo; 1.6 1.7 - private boolean useZipFileIndex; 1.8 + private boolean contextUseOptimizedZip; 1.9 private ZipFileIndexCache zipFileIndexCache; 1.10 1.11 private final File uninited = new File("U N I N I T E D"); 1.12 @@ -164,8 +164,8 @@ 1.13 1.14 fsInfo = FSInfo.instance(context); 1.15 1.16 - useZipFileIndex = options.isSet("useOptimizedZip"); 1.17 - if (useZipFileIndex) 1.18 + contextUseOptimizedZip = options.getBoolean("useOptimizedZip", true); 1.19 + if (contextUseOptimizedZip) 1.20 zipFileIndexCache = ZipFileIndexCache.getSharedInstance(); 1.21 1.22 mmappedIO = options.isSet("mmappedIO"); 1.23 @@ -471,9 +471,27 @@ 1.24 private static final RelativeDirectory symbolFilePrefix 1.25 = new RelativeDirectory("META-INF/sym/rt.jar/"); 1.26 1.27 + /* 1.28 + * This method looks for a ZipFormatException and takes appropriate 1.29 + * evasive action. If there is a failure in the fast mode then we 1.30 + * fail over to the platform zip, and allow it to deal with a potentially 1.31 + * non compliant zip file. 1.32 + */ 1.33 + protected Archive openArchive(File zipFilename) throws IOException { 1.34 + try { 1.35 + return openArchive(zipFilename, contextUseOptimizedZip); 1.36 + } catch (IOException ioe) { 1.37 + if (ioe instanceof ZipFileIndex.ZipFormatException) { 1.38 + return openArchive(zipFilename, false); 1.39 + } else { 1.40 + throw ioe; 1.41 + } 1.42 + } 1.43 + } 1.44 + 1.45 /** Open a new zip file directory, and cache it. 1.46 */ 1.47 - protected Archive openArchive(File zipFileName) throws IOException { 1.48 + private Archive openArchive(File zipFileName, boolean useOptimizedZip) throws IOException { 1.49 File origZipFileName = zipFileName; 1.50 if (!ignoreSymbolFile && paths.isDefaultBootClassPathRtJar(zipFileName)) { 1.51 File file = zipFileName.getParentFile().getParentFile(); // ${java.home} 1.52 @@ -495,7 +513,7 @@ 1.53 boolean usePreindexedCache = false; 1.54 String preindexCacheLocation = null; 1.55 1.56 - if (!useZipFileIndex) { 1.57 + if (!useOptimizedZip) { 1.58 zdir = new ZipFile(zipFileName); 1.59 } else { 1.60 usePreindexedCache = options.isSet("usezipindex"); 1.61 @@ -524,23 +542,22 @@ 1.62 } 1.63 1.64 if (origZipFileName == zipFileName) { 1.65 - if (!useZipFileIndex) { 1.66 + if (!useOptimizedZip) { 1.67 archive = new ZipArchive(this, zdir); 1.68 } else { 1.69 archive = new ZipFileIndexArchive(this, 1.70 - zipFileIndexCache.getZipFileIndex(zipFileName, 1.71 + zipFileIndexCache.getZipFileIndex(zipFileName, 1.72 null, 1.73 usePreindexedCache, 1.74 preindexCacheLocation, 1.75 options.isSet("writezipindexfiles"))); 1.76 } 1.77 } else { 1.78 - if (!useZipFileIndex) { 1.79 + if (!useOptimizedZip) { 1.80 archive = new SymbolArchive(this, origZipFileName, zdir, symbolFilePrefix); 1.81 - } 1.82 - else { 1.83 + } else { 1.84 archive = new ZipFileIndexArchive(this, 1.85 - zipFileIndexCache.getZipFileIndex(zipFileName, 1.86 + zipFileIndexCache.getZipFileIndex(zipFileName, 1.87 symbolFilePrefix, 1.88 usePreindexedCache, 1.89 preindexCacheLocation, 1.90 @@ -549,6 +566,8 @@ 1.91 } 1.92 } catch (FileNotFoundException ex) { 1.93 archive = new MissingArchive(zipFileName); 1.94 + } catch (ZipFileIndex.ZipFormatException zfe) { 1.95 + throw zfe; 1.96 } catch (IOException ex) { 1.97 if (zipFileName.exists()) 1.98 log.error("error.reading.file", zipFileName, getMessage(ex));
2.1 --- a/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Mon Mar 07 13:45:06 2011 -0800 2.2 +++ b/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Mon Mar 07 17:39:42 2011 -0800 2.3 @@ -492,8 +492,30 @@ 2.4 public ZipDirectory(RandomAccessFile zipRandomFile, long start, long end, ZipFileIndex index) throws IOException { 2.5 this.zipRandomFile = zipRandomFile; 2.6 this.zipFileIndex = index; 2.7 + hasValidHeader(); 2.8 + findCENRecord(start, end); 2.9 + } 2.10 2.11 - findCENRecord(start, end); 2.12 + /* 2.13 + * the zip entry signature should be at offset 0, otherwise allow the 2.14 + * calling logic to take evasive action by throwing ZipFormatException. 2.15 + */ 2.16 + private boolean hasValidHeader() throws IOException { 2.17 + final long pos = zipRandomFile.getFilePointer(); 2.18 + try { 2.19 + if (zipRandomFile.read() == 'P') { 2.20 + if (zipRandomFile.read() == 'K') { 2.21 + if (zipRandomFile.read() == 0x03) { 2.22 + if (zipRandomFile.read() == 0x04) { 2.23 + return true; 2.24 + } 2.25 + } 2.26 + } 2.27 + } 2.28 + } finally { 2.29 + zipRandomFile.seek(pos); 2.30 + } 2.31 + throw new ZipFormatException("invalid zip magic"); 2.32 } 2.33 2.34 /* 2.35 @@ -529,7 +551,13 @@ 2.36 zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2]; 2.37 zipDir[0] = endbuf[i + 10]; 2.38 zipDir[1] = endbuf[i + 11]; 2.39 - zipRandomFile.seek(start + get4ByteLittleEndian(endbuf, i + 16)); 2.40 + int sz = get4ByteLittleEndian(endbuf, i + 16); 2.41 + // a negative offset or the entries field indicates a 2.42 + // potential zip64 archive 2.43 + if (sz < 0 || get2ByteLittleEndian(zipDir, 0) == 0xffff) { 2.44 + throw new ZipFormatException("detected a zip64 archive"); 2.45 + } 2.46 + zipRandomFile.seek(start + sz); 2.47 zipRandomFile.readFully(zipDir, 2, zipDir.length - 2); 2.48 return; 2.49 } else { 2.50 @@ -1127,4 +1155,18 @@ 2.51 } 2.52 } 2.53 2.54 + /* 2.55 + * Exception primarily used to implement a failover, used exclusively here. 2.56 + */ 2.57 + 2.58 + static final class ZipFormatException extends IOException { 2.59 + private static final long serialVersionUID = 8000196834066748623L; 2.60 + protected ZipFormatException(String message) { 2.61 + super(message); 2.62 + } 2.63 + 2.64 + protected ZipFormatException(String message, Throwable cause) { 2.65 + super(message, cause); 2.66 + } 2.67 + } 2.68 }
3.1 --- a/src/share/classes/com/sun/tools/javac/util/Options.java Mon Mar 07 13:45:06 2011 -0800 3.2 +++ b/src/share/classes/com/sun/tools/javac/util/Options.java Mon Mar 07 17:39:42 2011 -0800 3.3 @@ -76,6 +76,22 @@ 3.4 } 3.5 3.6 /** 3.7 + * Get the boolean value for an option, patterned after Boolean.getBoolean, 3.8 + * essentially will return true, iff the value exists and is set to "true". 3.9 + */ 3.10 + public boolean getBoolean(String name) { 3.11 + return getBoolean(name, false); 3.12 + } 3.13 + 3.14 + /** 3.15 + * Get the boolean with a default value if the option is not set. 3.16 + */ 3.17 + public boolean getBoolean(String name, boolean defaultValue) { 3.18 + String value = get(name); 3.19 + return (value == null) ? defaultValue : Boolean.parseBoolean(value); 3.20 + } 3.21 + 3.22 + /** 3.23 * Check if the value for an undocumented option has been set. 3.24 */ 3.25 public boolean isSet(String name) {
4.1 --- a/test/tools/javac/6508981/TestInferBinaryName.java Mon Mar 07 13:45:06 2011 -0800 4.2 +++ b/test/tools/javac/6508981/TestInferBinaryName.java Mon Mar 07 17:39:42 2011 -0800 4.3 @@ -139,9 +139,8 @@ 4.4 throws IOException { 4.5 Context ctx = new Context(); 4.6 Options options = Options.instance(ctx); 4.7 - // uugh, ugly back door, should be cleaned up, someday 4.8 - if (zipFileIndexKind == USE_ZIP_FILE_INDEX) 4.9 - options.put("useOptimizedZip", "true"); 4.10 + options.put("useOptimizedZip", 4.11 + Boolean.toString(zipFileIndexKind == USE_ZIP_FILE_INDEX)); 4.12 4.13 if (symFileKind == IGNORE_SYMBOL_FILE) 4.14 options.put("ignore.symbol.file", "true");
5.1 --- a/test/tools/javac/api/6411310/Test.java Mon Mar 07 13:45:06 2011 -0800 5.2 +++ b/test/tools/javac/api/6411310/Test.java Mon Mar 07 17:39:42 2011 -0800 5.3 @@ -153,14 +153,12 @@ 5.4 Context c = new Context(); 5.5 Options options = Options.instance(c); 5.6 5.7 - if (useOptimizedZip) { 5.8 - options.put("useOptimizedZip", "true"); 5.9 - } 5.10 + options.put("useOptimizedZip", Boolean.toString(useOptimizedZip)); 5.11 5.12 - if (!useSymbolFile) { 5.13 - options.put("ignore.symbol.file", "true"); 5.14 - } 5.15 - return new JavacFileManager(c, false, null); 5.16 + if (!useSymbolFile) { 5.17 + options.put("ignore.symbol.file", "true"); 5.18 + } 5.19 + return new JavacFileManager(c, false, null); 5.20 } 5.21 5.22 File createDir(String name, String... entries) throws Exception {
6.1 --- a/test/tools/javac/api/T6838467.java Mon Mar 07 13:45:06 2011 -0800 6.2 +++ b/test/tools/javac/api/T6838467.java Mon Mar 07 17:39:42 2011 -0800 6.3 @@ -178,12 +178,10 @@ 6.4 return fm; 6.5 } 6.6 6.7 - JavacFileManager createFileManager(boolean useOptimedZipIndex) { 6.8 + JavacFileManager createFileManager(boolean useOptimizedZip) { 6.9 Context ctx = new Context(); 6.10 - if (useOptimedZipIndex) { 6.11 - Options options = Options.instance(ctx); 6.12 - options.put("useOptimizedZip", "true"); 6.13 - } 6.14 + Options options = Options.instance(ctx); 6.15 + options.put("useOptimizedZip", Boolean.toString(useOptimizedZip)); 6.16 return new JavacFileManager(ctx, false, null); 6.17 } 6.18
7.1 --- a/test/tools/javac/api/T6877206.java Mon Mar 07 13:45:06 2011 -0800 7.2 +++ b/test/tools/javac/api/T6877206.java Mon Mar 07 17:39:42 2011 -0800 7.3 @@ -168,9 +168,7 @@ 7.4 JavacFileManager createFileManager(boolean useOptimizedZip, boolean useSymbolFile) { 7.5 Context ctx = new Context(); 7.6 Options options = Options.instance(ctx); 7.7 - if (useOptimizedZip) { 7.8 - options.put("useOptimizedZip", "true"); 7.9 - } 7.10 + options.put("useOptimizedZip", Boolean.toString(useOptimizedZip)); 7.11 if (!useSymbolFile) { 7.12 options.put("ignore.symbol.file", "true"); 7.13 }
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/test/tools/javac/file/zip/T6836682.java Mon Mar 07 17:39:42 2011 -0800 8.3 @@ -0,0 +1,156 @@ 8.4 +/* 8.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 8.7 + * 8.8 + * This code is free software; you can redistribute it and/or modify it 8.9 + * under the terms of the GNU General Public License version 2 only, as 8.10 + * published by the Free Software Foundation. 8.11 + * 8.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 8.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 8.15 + * version 2 for more details (a copy is included in the LICENSE file that 8.16 + * accompanied this code). 8.17 + * 8.18 + * You should have received a copy of the GNU General Public License version 8.19 + * 2 along with this work; if not, write to the Free Software Foundation, 8.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 8.21 + * 8.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 8.23 + * or visit www.oracle.com if you need additional information or have any 8.24 + * questions. 8.25 + */ 8.26 + 8.27 +/* 8.28 + * @test 8.29 + * @bug 6836682 8.30 + * @summary JavacFileManager handles zip64 archives (64K+ entries and large file support) 8.31 + * @compile -XDignore.symbol.file T6836682.java Utils.java 8.32 + * @run main T6836682 8.33 + */ 8.34 +import java.io.BufferedOutputStream; 8.35 +import java.io.File; 8.36 +import java.io.FileInputStream; 8.37 +import java.io.FileOutputStream; 8.38 +import java.io.IOException; 8.39 +import java.nio.file.Files; 8.40 +import java.nio.file.Path; 8.41 +import java.util.jar.JarOutputStream; 8.42 +import java.util.zip.ZipEntry; 8.43 + 8.44 +public class T6836682 { 8.45 + 8.46 + private static final long GIGA = 1024 * 1024 * 1024; 8.47 + 8.48 + static void createLargeFile(File outFile, long minlength) throws IOException { 8.49 + FileOutputStream fos = null; 8.50 + BufferedOutputStream bos = null; 8.51 + byte[] buffer = new byte[Short.MAX_VALUE * 2]; 8.52 + try { 8.53 + fos = new FileOutputStream(outFile); 8.54 + bos = new BufferedOutputStream(fos); 8.55 + long count = minlength / ( Short.MAX_VALUE * 2) + 1; 8.56 + for (long i = 0 ; i < count ; i++) { 8.57 + bos.write(buffer); 8.58 + } 8.59 + } finally { 8.60 + Utils.close(bos); 8.61 + Utils.close(fos); 8.62 + } 8.63 + if (outFile.length() < minlength) { 8.64 + throw new RuntimeException("could not create large file " + outFile.getAbsolutePath()); 8.65 + } 8.66 + } 8.67 + 8.68 + static void createJarWithLargeFile(File jarFile, File javaFile, 8.69 + long minlength) throws IOException { 8.70 + Utils.createClassFile(javaFile, null, true); 8.71 + File largeFile = new File("large.data"); 8.72 + createLargeFile(largeFile, minlength); 8.73 + String[] jarArgs = { 8.74 + "0cvf", 8.75 + jarFile.getAbsolutePath(), 8.76 + largeFile.getName(), 8.77 + Utils.getClassFileName(javaFile) 8.78 + }; 8.79 + Utils.jarTool.run(jarArgs); 8.80 + // deleted to prevent accidental linkage 8.81 + new File(Utils.getClassFileName(javaFile)).delete(); 8.82 + } 8.83 + 8.84 + static void createLargeJar(File jarFile, File javaFile) throws IOException { 8.85 + File classFile = new File(Utils.getClassFileName(javaFile)); 8.86 + Utils.createClassFile(javaFile, null, true); 8.87 + JarOutputStream jos = null; 8.88 + FileInputStream fis = null; 8.89 + try { 8.90 + jos = new JarOutputStream(new FileOutputStream(jarFile)); 8.91 + 8.92 + for (int i = 0; i < Short.MAX_VALUE * 2 + 10; i++) { 8.93 + jos.putNextEntry(new ZipEntry("X" + i + ".txt")); 8.94 + } 8.95 + jos.putNextEntry(new ZipEntry(classFile.getName())); 8.96 + fis = new FileInputStream(classFile); 8.97 + Utils.copyStream(fis, jos); 8.98 + } finally { 8.99 + Utils.close(jos); 8.100 + Utils.close(fis); 8.101 + } 8.102 + // deleted to prevent accidental linkage 8.103 + new File(Utils.getClassFileName(javaFile)).delete(); 8.104 + } 8.105 + 8.106 + // a jar with entries exceeding 64k + a class file for the existential test 8.107 + public static void testLargeJar(String... args) throws IOException { 8.108 + File largeJar = new File("large.jar"); 8.109 + File javaFile = new File("Foo.java"); 8.110 + createLargeJar(largeJar, javaFile); 8.111 + 8.112 + File testFile = new File("Bar.java"); 8.113 + try { 8.114 + Utils.createJavaFile(testFile, javaFile); 8.115 + if (!Utils.compile("-doe", "-verbose", "-cp", 8.116 + largeJar.getAbsolutePath(), testFile.getAbsolutePath())) { 8.117 + throw new IOException("test failed"); 8.118 + } 8.119 + } finally { 8.120 + Utils.deleteFile(largeJar); 8.121 + } 8.122 + } 8.123 + 8.124 + // a jar with an enormous file + a class file for the existential test 8.125 + public static void testHugeJar(String... args) throws IOException { 8.126 + final File largeJar = new File("huge.jar"); 8.127 + final File javaFile = new File("Foo.java"); 8.128 + 8.129 + final Path path = largeJar.getAbsoluteFile().getParentFile().toPath(); 8.130 + final long available = Files.getFileStore(path).getUsableSpace(); 8.131 + final long MAX_VALUE = 0xFFFF_FFFFL; 8.132 + 8.133 + final long absolute = MAX_VALUE + 1L; 8.134 + final long required = (long)(absolute * 1.1); // pad for sundries 8.135 + System.out.println("\tavailable: " + available / GIGA + " GB"); 8.136 + System.out.println("\required: " + required / GIGA + " GB"); 8.137 + 8.138 + if (available > required) { 8.139 + createJarWithLargeFile(largeJar, javaFile, absolute); 8.140 + File testFile = new File("Bar.java"); 8.141 + Utils.createJavaFile(testFile, javaFile); 8.142 + try { 8.143 + if (!Utils.compile("-doe", "-verbose", "-cp", 8.144 + largeJar.getAbsolutePath(), testFile.getAbsolutePath())) { 8.145 + throw new IOException("test failed"); 8.146 + } 8.147 + } finally { 8.148 + Utils.deleteFile(largeJar); 8.149 + } 8.150 + } else { 8.151 + System.out.println("Warning: test passes vacuously, requirements exceeds available space"); 8.152 + } 8.153 + } 8.154 + 8.155 + public static void main(String... args) throws IOException { 8.156 + testLargeJar(); 8.157 + testHugeJar(); 8.158 + } 8.159 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/test/tools/javac/file/zip/T6865530.java Mon Mar 07 17:39:42 2011 -0800 9.3 @@ -0,0 +1,66 @@ 9.4 +/* 9.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.7 + * 9.8 + * This code is free software; you can redistribute it and/or modify it 9.9 + * under the terms of the GNU General Public License version 2 only, as 9.10 + * published by the Free Software Foundation. 9.11 + * 9.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 9.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 9.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 9.15 + * version 2 for more details (a copy is included in the LICENSE file that 9.16 + * accompanied this code). 9.17 + * 9.18 + * You should have received a copy of the GNU General Public License version 9.19 + * 2 along with this work; if not, write to the Free Software Foundation, 9.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 9.21 + * 9.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 9.23 + * or visit www.oracle.com if you need additional information or have any 9.24 + * questions. 9.25 + */ 9.26 + 9.27 +/* 9.28 + * @test 9.29 + * @bug 6865530 9.30 + * @summary ensure JavacFileManager handles non-standard zipfiles. 9.31 + * @compile -XDignore.symbol.file T6865530.java 9.32 + * @run main T6865530 9.33 + */ 9.34 + 9.35 + 9.36 +import java.io.File; 9.37 + 9.38 + 9.39 +public class T6865530 { 9.40 + 9.41 + public static void main(String... args) throws Exception { 9.42 + File badFile = new File("bad.exe"); 9.43 + File testJar = new File("test.jar"); 9.44 + File fooJava = new File("Foo.java"); 9.45 + File barJava = new File("Bar.java"); 9.46 + 9.47 + // create a jar by compiling a file, and append the jar to some 9.48 + // arbitrary data to offset the start of the zip/jar archive 9.49 + Utils.createJavaFile(fooJava); 9.50 + Utils.compile("-doe", "-verbose", fooJava.getName()); 9.51 + String[] jarArgs = { 9.52 + "cvf", testJar.getAbsolutePath(), "Foo.class" 9.53 + }; 9.54 + Utils.jarTool.run(jarArgs); 9.55 + Utils.cat(badFile, fooJava, testJar); 9.56 + 9.57 + // create test file and use the above file as a classpath 9.58 + Utils.createJavaFile(barJava); 9.59 + try { 9.60 + if (!Utils.compile("-doe", "-verbose", "-cp", badFile.getAbsolutePath(), "Bar.java")) { 9.61 + throw new RuntimeException("test fails javac did not compile"); 9.62 + } 9.63 + } finally { 9.64 + Utils.deleteFile(badFile); 9.65 + Utils.deleteFile(testJar); 9.66 + } 9.67 + } 9.68 +} 9.69 +
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/test/tools/javac/file/zip/Utils.java Mon Mar 07 17:39:42 2011 -0800 10.3 @@ -0,0 +1,131 @@ 10.4 +/* 10.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10.7 + * 10.8 + * This code is free software; you can redistribute it and/or modify it 10.9 + * under the terms of the GNU General Public License version 2 only, as 10.10 + * published by the Free Software Foundation. 10.11 + * 10.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 10.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 10.15 + * version 2 for more details (a copy is included in the LICENSE file that 10.16 + * accompanied this code). 10.17 + * 10.18 + * You should have received a copy of the GNU General Public License version 10.19 + * 2 along with this work; if not, write to the Free Software Foundation, 10.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 10.21 + * 10.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 10.23 + * or visit www.oracle.com if you need additional information or have any 10.24 + * questions. 10.25 + */ 10.26 + 10.27 +import java.io.BufferedInputStream; 10.28 +import java.io.BufferedOutputStream; 10.29 +import java.io.Closeable; 10.30 +import java.io.File; 10.31 +import java.io.FileInputStream; 10.32 +import java.io.FileOutputStream; 10.33 +import java.io.IOException; 10.34 +import java.io.InputStream; 10.35 +import java.io.OutputStream; 10.36 +import java.io.PrintStream; 10.37 + 10.38 +public class Utils { 10.39 + 10.40 + static final sun.tools.jar.Main jarTool = 10.41 + new sun.tools.jar.Main(System.out, System.err, "jar-tool"); 10.42 + 10.43 + static final com.sun.tools.javac.Main javac = 10.44 + new com.sun.tools.javac.Main(); 10.45 + 10.46 + private Utils(){} 10.47 + 10.48 + public static boolean compile(String... args) { 10.49 + return javac.compile(args) == 0; 10.50 + } 10.51 + 10.52 + public static void createClassFile(File javaFile, File superClass, 10.53 + boolean delete) throws IOException { 10.54 + createJavaFile(javaFile, superClass); 10.55 + if (!compile(javaFile.getName())) { 10.56 + throw new RuntimeException("compile failed unexpectedly"); 10.57 + } 10.58 + if (delete) javaFile.delete(); 10.59 + } 10.60 + 10.61 + public static void createJavaFile(File outFile) throws IOException { 10.62 + createJavaFile(outFile, null); 10.63 + } 10.64 + 10.65 + public static void createJavaFile(File outFile, File superClass) throws IOException { 10.66 + PrintStream ps = null; 10.67 + String srcStr = "public class " + getSimpleName(outFile) + " "; 10.68 + if (superClass != null) { 10.69 + srcStr = srcStr.concat("extends " + getSimpleName(superClass) + " "); 10.70 + } 10.71 + srcStr = srcStr.concat("{}"); 10.72 + try { 10.73 + FileOutputStream fos = new FileOutputStream(outFile); 10.74 + ps = new PrintStream(fos); 10.75 + ps.println(srcStr); 10.76 + } finally { 10.77 + close(ps); 10.78 + } 10.79 + } 10.80 + 10.81 + static String getClassFileName(File javaFile) { 10.82 + return javaFile.getName().endsWith(".java") 10.83 + ? javaFile.getName().replace(".java", ".class") 10.84 + : null; 10.85 + } 10.86 + 10.87 + static String getSimpleName(File inFile) { 10.88 + String fname = inFile.getName(); 10.89 + return fname.substring(0, fname.indexOf(".")); 10.90 + } 10.91 + 10.92 + public static void copyStream(InputStream in, OutputStream out) throws IOException { 10.93 + byte[] buf = new byte[8192]; 10.94 + int n = in.read(buf); 10.95 + while (n > 0) { 10.96 + out.write(buf, 0, n); 10.97 + n = in.read(buf); 10.98 + } 10.99 + } 10.100 + 10.101 + public static void close(Closeable c) { 10.102 + if (c != null) { 10.103 + try { 10.104 + c.close(); 10.105 + } catch (IOException ignore) {} 10.106 + } 10.107 + } 10.108 + 10.109 + public static void deleteFile(File f) { 10.110 + if (!f.delete()) { 10.111 + throw new RuntimeException("could not delete file: " + f.getAbsolutePath()); 10.112 + } 10.113 + } 10.114 + 10.115 + public static void cat(File output, File... files) throws IOException { 10.116 + BufferedInputStream bis = null; 10.117 + BufferedOutputStream bos = null; 10.118 + FileOutputStream fos = null; 10.119 + try { 10.120 + fos = new FileOutputStream(output); 10.121 + bos = new BufferedOutputStream(fos); 10.122 + for (File x : files) { 10.123 + FileInputStream fis = new FileInputStream(x); 10.124 + bis = new BufferedInputStream(fis); 10.125 + copyStream(bis, bos); 10.126 + Utils.close(bis); 10.127 + } 10.128 + } finally { 10.129 + Utils.close(bis); 10.130 + Utils.close(bos); 10.131 + Utils.close(fos); 10.132 + } 10.133 + } 10.134 +}