< prev index next >
make/src/classes/build/tools/module/ModuleArchive.java
Print this page
@@ -24,19 +24,21 @@
*/
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.
*/
public class ModuleArchive implements Archive {
@@ -44,10 +46,12 @@
private final Path cmds;
private final Path libs;
private final Path configs;
private final String moduleName;
+ private final List<InputStream> opened = new ArrayList<>();
+
public ModuleArchive(String moduleName, Path classes, Path cmds,
Path libs, Path configs) {
this.moduleName = moduleName;
this.classes = classes;
this.cmds = cmds;
@@ -59,184 +63,121 @@
public String moduleName() {
return moduleName;
}
@Override
- public void visitResources(Consumer<Resource> 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) {
+ @Override
+ public void close() throws IOException {
+ IOException e = null;
+ for (InputStream stream : opened) {
try {
- return new Resource(classes.relativize(path).toString().replace('\\','/'),
- Files.size(path),
- 0 /* no compression support yet */);
- } catch (IOException ioe) {
- throw new UncheckedIOException(ioe);
+ stream.close();
+ } catch (IOException ex) {
+ if (e == null) {
+ e = ex;
+ } else {
+ e.addSuppressed(ex);
}
}
-
- private enum Section {
- CLASSES,
- CMDS,
- LIBS,
- CONFIGS
+ }
+ if (e != null) {
+ throw e;
+ }
}
@Override
- public void visitEntries(Consumer<Entry> consumer) {
- try{
- if (classes != null)
- Files.walk(classes)
- .sorted()
+ public Stream<Entry> entries() {
+ List<Entry> 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<Path> 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"))
- .map(p -> toEntry(p, classes, Section.CLASSES))
- .forEach(consumer::accept);
- if (cmds != null)
- Files.walk(cmds)
+ .sorted()
+ .map(p -> toEntry(p, classes, EntryType.CLASS_OR_RESOURCE))
+ .collect(Collectors.toList()));
+ }
+ }
+ if (cmds != null) {
+ try (Stream<Path> stream = Files.walk(cmds)) {
+ entries.addAll(stream
.filter(p -> !Files.isDirectory(p))
- .map(p -> toEntry(p, cmds, Section.CMDS))
- .forEach(consumer::accept);
- if (libs != null)
- Files.walk(libs)
+ .map(p -> toEntry(p, cmds, EntryType.NATIVE_CMD))
+ .collect(Collectors.toList()));
+ }
+ }
+ if (libs != null) {
+ try (Stream<Path> stream = Files.walk(libs)) {
+ entries.addAll(stream
.filter(p -> !Files.isDirectory(p))
- .map(p -> toEntry(p, libs, Section.LIBS))
- .forEach(consumer::accept);
- if (configs != null)
- Files.walk(configs)
+ .map(p -> toEntry(p, libs, EntryType.NATIVE_LIB))
+ .collect(Collectors.toList()));
+ }
+ }
+ if (configs != null) {
+ try (Stream<Path> 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<Entry> defaultImageWriter(Path path, OutputStream out) {
- return new DefaultEntryWriter(path, out);
- }
-
- private static class DefaultEntryWriter implements Consumer<Archive.Entry> {
- private final Path root;
- private final OutputStream out;
-
- DefaultEntryWriter(Path root, OutputStream out) {
- this.root = root;
- this.out = out;
+ public long size() {
+ return size;
}
@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);
+ public InputStream stream() throws IOException {
+ InputStream stream = Files.newInputStream(entryPath);
+ opened.add(stream);
+ return stream;
}
}
- private Path destFile(String dir, String filename) {
- return root.resolve(dir).resolve(filename);
- }
-
- 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);
- }
-
- 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);
}
}
}
< prev index next >