src/share/classes/org/openjdk/jigsaw/SimpleLibrary.java

Print this page

        

@@ -26,10 +26,11 @@
 package org.openjdk.jigsaw;
 
 import java.lang.module.*;
 import java.io.*;
 import java.net.URI;
+import java.nio.file.*;
 import java.security.*;
 import java.security.cert.*;
 import java.util.*;
 import java.util.jar.*;
 import java.util.zip.*;

@@ -68,12 +69,12 @@
 
         protected final int maxMajorVersion;
         protected final int maxMinorVersion;
         protected int majorVersion;
         protected int minorVersion;
-        private FileConstants.Type type;
-        private File file;
+        private final FileConstants.Type type;
+        private final File file;
 
         protected MetaData(int maxMajor, int maxMinor,
                            FileConstants.Type t, File f)
         {
             maxMajorVersion = majorVersion = maxMajor;

@@ -84,37 +85,31 @@
 
         protected abstract void storeRest(DataOutputStream out)
             throws IOException;
 
         void store() throws IOException {
-            OutputStream fo = new FileOutputStream(file);
-            DataOutputStream out
-                = new DataOutputStream(new BufferedOutputStream(fo));
-            try {
+            try (OutputStream fos = new FileOutputStream(file);
+                 BufferedOutputStream bos = new BufferedOutputStream(fos);
+                 DataOutputStream out = new DataOutputStream(bos)) {
                 out.writeInt(FileConstants.MAGIC);
                 out.writeShort(type.value());
                 out.writeShort(majorVersion);
                 out.writeShort(minorVersion);
                 storeRest(out);
-            } finally {
-                out.close();
             }
         }
 
         protected abstract void loadRest(DataInputStream in)
             throws IOException;
 
         protected void load() throws IOException {
-            InputStream fi = new FileInputStream(file);
-            try {
-                DataInputStream in
-                    = new DataInputStream(new BufferedInputStream(fi));
-                int m = in.readInt();
-                if (m != FileConstants.MAGIC)
+            try (InputStream fis = new FileInputStream(file);
+                 BufferedInputStream bis = new BufferedInputStream(fis);
+                 DataInputStream in = new DataInputStream(fis)) {
+                if (in.readInt() != FileConstants.MAGIC)
                     throw new IOException(file + ": Invalid magic number");
-                int typ = in.readShort();
-                if (typ != type.value())
+                if (in.readShort() != type.value())
                     throw new IOException(file + ": Invalid file type");
                 int maj = in.readShort();
                 int min = in.readShort();
                 if (   maj > maxMajorVersion
                     || (maj == maxMajorVersion && min > maxMinorVersion)) {

@@ -123,17 +118,13 @@
                 }
                 majorVersion = maj;
                 minorVersion = min;
                 loadRest(in);
             } catch (EOFException x) {
-                throw new IOException(file + ": Invalid library metadata",
-                                      x);
-            } finally {
-                fi.close();
+                throw new IOException(file + ": Invalid library metadata", x);
             }
         }
-
     }
 
     /**
      * Defines the storage options that SimpleLibrary supports.
      */

@@ -151,74 +142,106 @@
         private static final int MINOR_VERSION = 1;
 
         private static final int DEFLATED = 1 << 0;
 
         private File parent;
+        // location of native libs for this library (may be outside the library)
+        // null:default, to use a per-module 'lib' directory
+        private File natlibs;
+        // location of native cmds for this library (may be outside the library)
+        // null:default, to use a per-module 'bin' directory
+        private File natcmds;
+        // location of config files for this library (may be outside the library)
+        // null:default, to use a per-module 'etc' directory
+        private File configs;
         private Set<StorageOption> opts;
 
         public File parent() { return parent; }
+        public File natlibs() { return natlibs; }
+        public File natcmds() { return natcmds; }
+        public File configs() { return configs; }
         public boolean isDeflated() {
            return opts.contains(StorageOption.DEFLATED);
         }
 
-        private Header(File root, File p, Set<StorageOption> opts) {
+        private Header(File root) {
             super(MAJOR_VERSION, MINOR_VERSION,
                   FileConstants.Type.LIBRARY_HEADER,
                   new File(root, FILE));
-            this.parent = p;
+        }
+
+        private Header(File root, File parent, File natlibs, File natcmds,
+                       File configs, Set<StorageOption> opts) {
+            this(root);
+            this.parent = parent;
+            this.natlibs = natlibs;
+            this.natcmds = natcmds;
+            this.configs = configs;
             this.opts = new HashSet<>(opts);
         }
 
-        private Header(File root) {
-            this(root, null, Collections.<StorageOption>emptySet());
+        private void storePath(File p, DataOutputStream out) throws IOException {  
+            if (p != null) {
+                out.writeByte(1);
+                out.writeUTF(Files.convertSeparator(p.toString()));
+            } else 
+                out.write(0);
         }
 
-        protected void storeRest(DataOutputStream out)
-            throws IOException
-        {
+        protected void storeRest(DataOutputStream out) throws IOException {
             int flags = 0;
             if (isDeflated())
                 flags |= DEFLATED;
             out.writeShort(flags);
-            out.writeByte((parent != null) ? 1 : 0);
-            if (parent != null)
-                out.writeUTF(parent.toString());
+            
+            storePath(parent, out);
+            storePath(natlibs, out);
+            storePath(natcmds, out);
+            storePath(configs, out);
         }
 
-        protected void loadRest(DataInputStream in)
-            throws IOException
-        {
+        private File loadPath(DataInputStream in) throws IOException {  
+            if (in.readByte() != 0)
+                return new File(Files.platformSeparator(in.readUTF()));
+            return null;
+        }
+
+        protected void loadRest(DataInputStream in) throws IOException {
             opts = new HashSet<StorageOption>();
             int flags = in.readShort();
             if ((flags & DEFLATED) == DEFLATED)
                 opts.add(StorageOption.DEFLATED);
-            int b = in.readByte();
-            if (b != 0)
-                parent = new File(in.readUTF());
+            parent = loadPath(in);
+            natlibs = loadPath(in);
+            natcmds = loadPath(in);
+            configs = loadPath(in);
         }
 
-        private static Header load(File f)
-            throws IOException
-        {
+        private static Header load(File f) throws IOException {
             Header h = new Header(f);
             h.load();
             return h;
         }
-
     }
 
     private final File root;
     private final File canonicalRoot;
-    private File parentPath = null;
-    private SimpleLibrary parent = null;
+    private File parentPath;
+    private File natlibs;
+    private File natcmds;
+    private File configs;
+    private SimpleLibrary parent;
     private final Header hd;
 
     public String name() { return root.toString(); }
     public File root() { return canonicalRoot; }
     public int majorVersion() { return hd.majorVersion; }
     public int minorVersion() { return hd.minorVersion; }
     public SimpleLibrary parent() { return parent; }
+    public File natlibs() { return natlibs; }
+    public File natcmds() { return natcmds; }
+    public File configs() { return configs; }
     public boolean isDeflated() { return hd.isDeflated(); }
 
     private URI location = null;
     public URI location() {
         if (location == null)

@@ -231,60 +254,109 @@
         return (this.getClass().getName()
                 + "[" + canonicalRoot
                 + ", v" + hd.majorVersion + "." + hd.minorVersion + "]");
     }
 
-    private SimpleLibrary(File path, boolean create, File parentPath, Set<StorageOption> opts)
-        throws IOException
-    {
+
+    private static File resolveAndEnsurePath(File path) throws IOException {
+        if (path == null) { return null; }
+        
+        File p = path.getCanonicalFile();
+        if (!p.exists())
+            Files.mkdirs(p, p.toString());
+        else {
+            Files.ensureIsDirectory(p);
+            Files.ensureWriteable(p);
+        }
+        return p;
+    }
+
+    private File relativize(File path) throws IOException {
+        if (path == null) { return null; }
+        // Return the path relative to the canonical root
+        return (canonicalRoot.toPath().relativize(path.toPath().toRealPath())).toFile();
+    }
+
+    // Opens an existing library
+    private SimpleLibrary(File path) throws IOException {
         root = path;
         canonicalRoot = root.getCanonicalFile();
-        if (root.exists()) {
-            if (!root.isDirectory())
-                throw new IOException(root + ": Exists but is not a directory");
+        Files.ensureIsDirectory(root);
             hd = Header.load(root);
             if (hd.parent() != null) {
                 parent = open(hd.parent());
                 parentPath = hd.parent();
             }
-            return;
+
+        if (hd.natlibs() != null)
+            natlibs = new File(canonicalRoot, hd.natlibs().toString()).getCanonicalFile();
+        if (hd.natcmds() != null)
+            natcmds = new File(canonicalRoot, hd.natcmds().toString()).getCanonicalFile();
+        if (hd.configs() != null)
+            configs = new File(canonicalRoot, hd.configs().toString()).getCanonicalFile();
         }
-        if (!create)
-            throw new FileNotFoundException(root.toString());
+
+    // Creates a new library
+    private SimpleLibrary(File path, File parentPath, File natlibs, File natcmds,
+                          File configs, Set<StorageOption> opts)
+        throws IOException
+    {
+        root = path;
+        canonicalRoot = root.getCanonicalFile();
+        if (root.exists()) {
+            Files.ensureIsDirectory(root);
+            if (root.list().length != 0)
+                throw new IOException(root + ": Already Exists");
+            Files.ensureWriteable(root);
+        } else
+            Files.mkdirs(root, root.toString());
+
         if (parentPath != null) {
             this.parent = open(parentPath);
             this.parentPath = this.parent.root();
         }
-        if (!root.mkdirs())
-            throw new IOException(root + ": Cannot create library directory");
-        hd = new Header(canonicalRoot, this.parentPath, opts);
+
+        this.natlibs = resolveAndEnsurePath(natlibs);
+        this.natcmds = resolveAndEnsurePath(natcmds);
+        this.configs = resolveAndEnsurePath(configs);
+
+        hd = new Header(canonicalRoot, this.parentPath, relativize(this.natlibs),
+                        relativize(this.natcmds), relativize(this.configs), opts);
         hd.store();
     }
 
+    public static SimpleLibrary create(File path, File parent, File natlibs,
+                                       File natcmds, File configs,
+                                       Set<StorageOption> opts)
+        throws IOException
+    {
+        return new SimpleLibrary(path, parent, natlibs, natcmds, configs, opts);
+    }
+
     public static SimpleLibrary create(File path, File parent, Set<StorageOption> opts)
         throws IOException
     {
-        return new SimpleLibrary(path, true, parent, opts);
+        return new SimpleLibrary(path, parent, null, null, null, opts);
     }
 
     public static SimpleLibrary create(File path, File parent)
         throws IOException 
     {
-        return new SimpleLibrary(path, true, parent, Collections.<StorageOption>emptySet());
+        return SimpleLibrary.create(path, parent, Collections.<StorageOption>emptySet());
     }
 
     public static SimpleLibrary create(File path, Set<StorageOption> opts)
         throws IOException
     {
         // ## Should default parent to $JAVA_HOME/lib/modules
-        return new SimpleLibrary(path, true, null, opts);
+        return SimpleLibrary.create(path, null, opts);
     }
 
     public static SimpleLibrary open(File path)
         throws IOException
     {
-        return new SimpleLibrary(path, false, null, Collections.<StorageOption>emptySet());
+        return new SimpleLibrary(path);
     }
 
     private static final JigsawModuleSystem jms
         = JigsawModuleSystem.instance();
 

@@ -996,14 +1068,14 @@
 
                 // Store signer info
                 new Signers(md, signers).store();
 
                 // Read and verify the rest of the hashes
-                mr.readRest(md, isDeflated());
+                mr.readRest(md, isDeflated(), natlibs(), natcmds(), configs());
                 mfv.verifyHashesRest(mfvParams);
             } else {
-                mr.readRest(md, isDeflated());
+                mr.readRest(md, isDeflated(), natlibs(), natcmds(), configs());
             }
  
             if (strip) 
                 strip(md);
             reIndex(mid);         // ## Could do this while reading module file

@@ -1010,11 +1082,11 @@
             return mid;
 
         } catch (IOException | SignatureException x) {
             if (md != null && md.exists()) {
                 try {
-                    Files.deleteTree(md);
+                   ModuleFile.Reader.remove(md);
                 } catch (IOException y) {
                     y.initCause(x);
                     throw y;
                 }
             }

@@ -1184,10 +1256,11 @@
     {
         ModuleId mid;
         if (mf.getName().endsWith(".jar"))
             mid = installFromJarFile(mf, verifySignature, strip);
         else {
+            // Assume jmod file
             try (FileInputStream in = new FileInputStream(mf)) {
                 mid = install(in, verifySignature, strip);
             }
         }
         return mid;

@@ -1336,14 +1409,18 @@
     }
 
     public File findLocalNativeLibrary(ModuleId mid, String name)
         throws IOException
     {
-        File md = findModuleDir(mid);
-        if (md == null)
+        File f = natlibs();
+        if (f == null) {
+            f = findModuleDir(mid);
+            if (f == null)
             return null;
-        File f = new File(new File(md, "lib"), name);
+            f = new File(f, "lib");
+        }
+        f = new File(f, name);
         if (!f.exists())
             return null;
         return f;
     }