< 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 >