--- old/make/src/classes/build/tools/module/ModuleArchive.java 2015-06-23 14:28:49.000000000 +0200 +++ new/make/src/classes/build/tools/module/ModuleArchive.java 2015-06-23 14:28:49.000000000 +0200 @@ -26,15 +26,17 @@ package build.tools.module; import jdk.internal.jimage.Archive; -import jdk.internal.jimage.Resource; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.function.Consumer; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.internal.jimage.Archive.Entry.EntryType; /** * An Archive backed by an exploded representation on disk. @@ -46,6 +48,8 @@ private final Path configs; private final String moduleName; + private final List opened = new ArrayList<>(); + public ModuleArchive(String moduleName, Path classes, Path cmds, Path libs, Path configs) { this.moduleName = moduleName; @@ -61,181 +65,118 @@ } @Override - public void visitResources(Consumer consumer) { - if (classes == null) - return; - try{ - Files.walk(classes) - .sorted() - .filter(p -> !Files.isDirectory(p) - && !classes.relativize(p).toString().startsWith("_the.") - && !classes.relativize(p).toString().equals("javac_state")) - .map(this::toResource) - .forEach(consumer::accept); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } + public void open() throws IOException { + // NOOP } - private Resource toResource(Path path) { - try { - return new Resource(classes.relativize(path).toString().replace('\\','/'), - Files.size(path), - 0 /* no compression support yet */); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); + @Override + public void close() throws IOException { + IOException e = null; + for (InputStream stream : opened) { + try { + stream.close(); + } catch (IOException ex) { + if (e == null) { + e = ex; + } else { + e.addSuppressed(ex); + } + } + } + if (e != null) { + throw e; } - } - - private enum Section { - CLASSES, - CMDS, - LIBS, - CONFIGS } @Override - public void visitEntries(Consumer consumer) { - try{ - if (classes != null) - Files.walk(classes) - .sorted() - .filter(p -> !Files.isDirectory(p) - && !classes.relativize(p).toString().startsWith("_the.") - && !classes.relativize(p).toString().equals("javac_state")) - .map(p -> toEntry(p, classes, Section.CLASSES)) - .forEach(consumer::accept); - if (cmds != null) - Files.walk(cmds) - .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, cmds, Section.CMDS)) - .forEach(consumer::accept); - if (libs != null) - Files.walk(libs) - .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, libs, Section.LIBS)) - .forEach(consumer::accept); - if (configs != null) - Files.walk(configs) + public Stream entries() { + List entries = new ArrayList<>(); + try { + /* + * This code should be revisited to avoid buffering of the entries. + * 1) Do we really need sorting classes? This force buffering of entries. + * libs, cmds and configs are not sorted. + * 2) I/O streams should be concatenated instead of buffering into + * entries list. + * 3) Close I/O streams in a close handler. + */ + if (classes != null) { + try (Stream stream = Files.walk(classes)) { + entries.addAll(stream + .filter(p -> !Files.isDirectory(p) + && !classes.relativize(p).toString().startsWith("_the.") + && !classes.relativize(p).toString().equals("javac_state")) + .sorted() + .map(p -> toEntry(p, classes, EntryType.CLASS_OR_RESOURCE)) + .collect(Collectors.toList())); + } + } + if (cmds != null) { + try (Stream stream = Files.walk(cmds)) { + entries.addAll(stream + .filter(p -> !Files.isDirectory(p)) + .map(p -> toEntry(p, cmds, EntryType.NATIVE_CMD)) + .collect(Collectors.toList())); + } + } + if (libs != null) { + try (Stream stream = Files.walk(libs)) { + entries.addAll(stream + .filter(p -> !Files.isDirectory(p)) + .map(p -> toEntry(p, libs, EntryType.NATIVE_LIB)) + .collect(Collectors.toList())); + } + } + if (configs != null) { + try (Stream stream = Files.walk(configs)) { + entries.addAll(stream .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, configs, Section.CONFIGS)) - .forEach(consumer::accept); + .map(p -> toEntry(p, configs, EntryType.CONFIG)) + .collect(Collectors.toList())); + } + } } catch (IOException ioe) { throw new UncheckedIOException(ioe); } + return entries.stream(); } - private static class FileEntry implements Entry { - private final String name; - private final InputStream is; + private class FileEntry extends Entry { private final boolean isDirectory; - private final Section section; - FileEntry(String name, InputStream is, - boolean isDirectory, Section section) { - this.name = name; - this.is = is; + private final long size; + private final Path entryPath; + FileEntry(Path entryPath, String path, EntryType type, + boolean isDirectory, long size) { + super(ModuleArchive.this, path, path, type); + this.entryPath = entryPath; this.isDirectory = isDirectory; - this.section = section; - } - public String getName() { - return name; - } - public Section getSection() { - return section; - } - public InputStream getInputStream() { - return is; + this.size = size; } + public boolean isDirectory() { return isDirectory; } - } - - private Entry toEntry(Path entryPath, Path basePath, Section section) { - try { - return new FileEntry(basePath.relativize(entryPath).toString().replace('\\', '/'), - Files.newInputStream(entryPath), false, - section); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public Consumer defaultImageWriter(Path path, OutputStream out) { - return new DefaultEntryWriter(path, out); - } - - private static class DefaultEntryWriter implements Consumer { - private final Path root; - private final OutputStream out; - - DefaultEntryWriter(Path root, OutputStream out) { - this.root = root; - this.out = out; - } @Override - public void accept(Archive.Entry entry) { - try { - FileEntry e = (FileEntry)entry; - Section section = e.getSection(); - String filename = e.getName(); - - try (InputStream in = entry.getInputStream()) { - switch (section) { - case CLASSES: - if (!filename.startsWith("_the.") && !filename.equals("javac_state")) - writeEntry(in); - break; - case LIBS: - writeEntry(in, destFile(nativeDir(filename), filename)); - break; - case CMDS: - Path path = destFile("bin", filename); - writeEntry(in, path); - path.toFile().setExecutable(true, false); - break; - case CONFIGS: - writeEntry(in, destFile("conf", filename)); - break; - default: - throw new InternalError("unexpected entry: " + filename); - } - } - } catch (IOException x) { - throw new UncheckedIOException(x); - } - } - - private Path destFile(String dir, String filename) { - return root.resolve(dir).resolve(filename); + public long size() { + return size; } - private static void writeEntry(InputStream in, Path dstFile) throws IOException { - if (Files.notExists(dstFile.getParent())) - Files.createDirectories(dstFile.getParent()); - Files.copy(in, dstFile); - } - - private void writeEntry(InputStream in) throws IOException { - byte[] buf = new byte[8192]; - int n; - while ((n = in.read(buf)) > 0) - out.write(buf, 0, n); + @Override + public InputStream stream() throws IOException { + InputStream stream = Files.newInputStream(entryPath); + opened.add(stream); + return stream; } + } - private static String nativeDir(String filename) { - if (System.getProperty("os.name").startsWith("Windows")) { - if (filename.endsWith(".dll") || filename.endsWith(".diz") - || filename.endsWith(".pdb") || filename.endsWith(".map")) { - return "bin"; - } else { - return "lib"; - } - } else { - return "lib"; - } + private Entry toEntry(Path entryPath, Path basePath, EntryType section) { + try { + String path = basePath.relativize(entryPath).toString().replace('\\', '/'); + return new FileEntry(entryPath, path, section, + false, Files.size(entryPath)); + } catch (IOException e) { + throw new UncheckedIOException(e); } } }