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

Print this page




  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package org.openjdk.jigsaw;
  27 
  28 import java.lang.module.*;
  29 import java.io.*;
  30 import java.net.URI;
  31 import java.nio.channels.FileChannel;
  32 import java.nio.file.*;
  33 import java.nio.file.attribute.BasicFileAttributes;
  34 import java.security.*;
  35 import java.security.cert.*;
  36 import java.util.*;
  37 import java.util.jar.*;
  38 import java.util.zip.*;
  39 
  40 import static java.nio.file.StandardCopyOption.*;
  41 import static java.nio.file.StandardOpenOption.*;
  42 import org.openjdk.jigsaw.Repository.ModuleType;
  43 
  44 /**
  45  * A simple module library which stores data directly in the filesystem
  46  *
  47  * @see Library
  48  */
  49 
  50 // ## TODO: Move remaining parent-searching logic upward into Library class
  51 
  52 // On-disk library layout
  53 //
  54 //   $LIB/%jigsaw-library
  55 //        com.foo.bar/1.2.3/info (= module-info.class)
  56 //                          index (list of defined classes)
  57 //                          config (resolved configuration, if a root)
  58 //                          classes/com/foo/bar/...
  59 //                          resources/com/foo/bar/...
  60 //                          lib/libbar.so
  61 //                          bin/bar
  62 //                          signer (signer's certchain & timestamp)


 141     {
 142         private static final String FILE
 143             = FileConstants.META_PREFIX + "jigsaw-library";
 144 
 145         private static final int MAJOR_VERSION = 0;
 146         private static final int MINOR_VERSION = 1;
 147 
 148         private static final int DEFLATED = 1 << 0;
 149 
 150         private File parent;
 151         // location of native libs for this library (may be outside the library)
 152         // null:default, to use a per-module 'lib' directory
 153         private File natlibs;
 154         // location of native cmds for this library (may be outside the library)
 155         // null:default, to use a per-module 'bin' directory
 156         private File natcmds;
 157         // location of config files for this library (may be outside the library)
 158         // null:default, to use a per-module 'etc' directory
 159         private File configs;
 160         private Set<StorageOption> opts;




 161 
 162         public File parent()  { return parent;  }
 163         public File natlibs() { return natlibs; }
 164         public File natcmds() { return natcmds; }
 165         public File configs() { return configs; }


 166         public boolean isDeflated() {
 167             return opts.contains(StorageOption.DEFLATED);
 168         }
 169 
 170         private Header(File root) {
 171             super(MAJOR_VERSION, MINOR_VERSION,
 172                   FileConstants.Type.LIBRARY_HEADER,
 173                   new File(root, FILE));
 174         }
 175 
 176         private Header(File root, File parent, File natlibs, File natcmds,
 177                        File configs, Set<StorageOption> opts) {

 178             this(root);
 179             this.parent = parent;
 180             this.natlibs = natlibs;
 181             this.natcmds = natcmds;
 182             this.configs = configs;


 183             this.opts = new HashSet<>(opts);
 184         }
 185 
 186         private void storePath(File p, DataOutputStream out) throws IOException {
 187             if (p != null) {
 188                 out.writeByte(1);
 189                 out.writeUTF(Files.convertSeparator(p.toString()));
 190             } else {
 191                 out.write(0);
 192             }
 193         }
 194 










 195         protected void storeRest(DataOutputStream out) throws IOException {
 196             int flags = 0;
 197             if (isDeflated())
 198                 flags |= DEFLATED;
 199             out.writeShort(flags);
 200 
 201             storePath(parent, out);
 202             storePath(natlibs, out);
 203             storePath(natcmds, out);
 204             storePath(configs, out);


 205         }
 206 
 207         private File loadPath(DataInputStream in) throws IOException {
 208             if (in.readByte() != 0)
 209                 return new File(Files.platformSeparator(in.readUTF()));
 210             return null;
 211         }
 212 







 213         protected void loadRest(DataInputStream in) throws IOException {
 214             opts = new HashSet<StorageOption>();
 215             int flags = in.readShort();
 216             if ((flags & DEFLATED) == DEFLATED)
 217                 opts.add(StorageOption.DEFLATED);
 218             parent = loadPath(in);
 219             natlibs = loadPath(in);
 220             natcmds = loadPath(in);
 221             configs = loadPath(in);


 222         }
 223 
 224         private static Header load(File f) throws IOException {
 225             Header h = new Header(f);
 226             h.load();
 227             return h;
 228         }
 229     }
 230 
 231     private final File root;
 232     private final File canonicalRoot;
 233     private final File parentPath;
 234     private final File natlibs;
 235     private final File natcmds;
 236     private final File configs;

 237     private final SimpleLibrary parent;
 238     private final Header hd;
 239     private final ModuleDictionary moduleDictionary;
 240     private final File lockf;
 241     private final File trash;
 242 
 243     public String name() { return root.toString(); }
 244     public File root() { return canonicalRoot; }
 245     public int majorVersion() { return hd.majorVersion; }
 246     public int minorVersion() { return hd.minorVersion; }
 247     public SimpleLibrary parent() { return parent; }
 248     public File natlibs() { return natlibs; }
 249     public File natcmds() { return natcmds; }
 250     public File configs() { return configs; }

 251     public boolean isDeflated() { return hd.isDeflated(); }
 252 
 253     private URI location = null;
 254     public URI location() {
 255         if (location == null)
 256             location = root().toURI();
 257         return location;
 258     }
 259 
 260     @Override
 261     public String toString() {
 262         return (this.getClass().getName()
 263                 + "[" + canonicalRoot
 264                 + ", v" + hd.majorVersion + "." + hd.minorVersion + "]");
 265     }
 266 
 267     private static File resolveAndEnsurePath(File path) throws IOException {
 268         if (path == null) { return null; }
 269 
 270         File p = path.getCanonicalFile();


 282         // Return the path relative to the canonical root
 283         return (canonicalRoot.toPath().relativize(path.toPath().toRealPath())).toFile();
 284     }
 285 
 286     // Opens an existing library
 287     private SimpleLibrary(File path) throws IOException {
 288         root = path;
 289         canonicalRoot = root.getCanonicalFile();
 290         Files.ensureIsDirectory(root);
 291         hd = Header.load(root);
 292 
 293         parentPath = hd.parent();
 294         parent = parentPath != null ? open(parentPath) : null;
 295 
 296         natlibs = hd.natlibs() == null ? null :
 297             new File(canonicalRoot, hd.natlibs().toString()).getCanonicalFile();
 298         natcmds = hd.natcmds() == null ? null :
 299             new File(canonicalRoot, hd.natcmds().toString()).getCanonicalFile();
 300         configs = hd.configs() == null ? null :
 301             new File(canonicalRoot, hd.configs().toString()).getCanonicalFile();

 302 
 303         lockf = new File(root, FileConstants.META_PREFIX + "lock");
 304         trash = new File(root, TRASH);
 305         moduleDictionary = new ModuleDictionary(root);
 306     }
 307 
 308     // Creates a new library
 309     private SimpleLibrary(File path, File parentPath, File natlibs, File natcmds,
 310                           File configs, Set<StorageOption> opts)

 311         throws IOException
 312     {
 313         root = path;
 314         canonicalRoot = root.getCanonicalFile();
 315         if (root.exists()) {
 316             Files.ensureIsDirectory(root);
 317             if (root.list().length != 0)
 318                 throw new IOException(root + ": Already Exists");
 319             Files.ensureWriteable(root);
 320         } else
 321             Files.mkdirs(root, root.toString());
 322 
 323         this.parent = parentPath != null ? open(parentPath) : null;
 324         this.parentPath = parentPath != null ? this.parent.root() : null;
 325 
 326         this.natlibs = resolveAndEnsurePath(natlibs);
 327         this.natcmds = resolveAndEnsurePath(natcmds);
 328         this.configs = resolveAndEnsurePath(configs);

 329 
 330         hd = new Header(canonicalRoot, this.parentPath, relativize(this.natlibs),
 331                         relativize(this.natcmds), relativize(this.configs), opts);

 332         hd.store();
 333 
 334         lockf = new File(root, FileConstants.META_PREFIX + "lock");
 335         lockf.createNewFile();
 336         trash = new File(root, TRASH);
 337         Files.mkdirs(trash, "module library trash");
 338         moduleDictionary = new ModuleDictionary(canonicalRoot);
 339         moduleDictionary.store();
 340     }
 341 
 342     public static SimpleLibrary create(File path, File parent, File natlibs,
 343                                        File natcmds, File configs,
 344                                        Set<StorageOption> opts)

 345         throws IOException
 346     {
 347         return new SimpleLibrary(path, parent, natlibs, natcmds, configs, opts);

 348     }
 349 
 350     public static SimpleLibrary create(File path, File parent, Set<StorageOption> opts)
 351         throws IOException
 352     {
 353         return new SimpleLibrary(path, parent, null, null, null, opts);

 354     }
 355 
 356     public static SimpleLibrary create(File path, File parent)
 357         throws IOException
 358     {
 359         return SimpleLibrary.create(path, parent, Collections.<StorageOption>emptySet());
 360     }
 361 
 362     public static SimpleLibrary create(File path, Set<StorageOption> opts)
 363         throws IOException
 364     {
 365         // ## Should default parent to $JAVA_HOME/lib/modules
 366         return SimpleLibrary.create(path, null, opts);
 367     }
 368 
 369     public static SimpleLibrary open(File path)
 370         throws IOException
 371     {
 372         return new SimpleLibrary(path);
 373     }


1170                 }
1171             } catch (IOException y) {
1172                 x.addSuppressed(y);
1173             }
1174             throw x;
1175         } finally {
1176             if (complete) {
1177                 moduleDictionary.store();
1178             }
1179             fc.close();
1180         }
1181     }
1182 
1183     @Override
1184     public void installFromManifests(Collection<Manifest> mfs)
1185         throws ConfigurationException, IOException
1186     {
1187         installFromManifests(mfs, false);
1188     }
1189 
1190     private ModuleId installWhileLocked(ModuleType type, InputStream is, boolean verifySignature,
1191                                         boolean strip) 
1192         throws ConfigurationException, IOException, SignatureException
1193     {
1194         switch (type) {
1195             case JAR:
1196                 Path jf = java.nio.file.Files.createTempFile(null, null);
1197                 try {
1198                     java.nio.file.Files.copy(is, jf, StandardCopyOption.REPLACE_EXISTING);
1199                     return installFromJarFile(jf.toFile(), verifySignature, strip);
1200                 } finally {
1201                     java.nio.file.Files.delete(jf);
1202                 }
1203             case JMOD:
1204             default:
1205                 return installWhileLocked(is, verifySignature, strip);
1206         }
1207     }
1208     
1209     private ModuleId installWhileLocked(InputStream is, boolean verifySignature,
1210                                         boolean strip)
1211         throws ConfigurationException, IOException, SignatureException
1212     {
1213         BufferedInputStream bin = new BufferedInputStream(is);
1214         DataInputStream in = new DataInputStream(bin);
1215         ModuleInfo mi = null;
1216         try (ModuleFile.Reader mr = new ModuleFile.Reader(in)) {
1217             ModuleInfo moduleInfo = jms.parseModuleInfo(mr.getModuleInfoBytes());







1218             File md = moduleDictionary.add(moduleInfo);
1219             mi = moduleInfo;
1220             if (verifySignature && mr.hasSignature()) {
1221                 // Verify the module signature
1222                 SignedModule sm = new SignedModule(mr);
1223                 Set<CodeSigner> signers = sm.verifySignature();
1224 
1225                 // Validate the signers
1226                 try {
1227                     SignedModule.validateSigners(signers);
1228                 } catch (CertificateException x) {
1229                     throw new SignatureException(x);
1230                 }
1231 
1232                 // ## TODO: Check policy and determine if signer is trusted
1233                 // ## and what permissions should be granted.
1234                 // ## If there is no policy entry, show signers and prompt
1235                 // ## user to accept before proceeding.
1236 
1237                 // Verify the module header hash and the module info hash


1498             // ## Handle case of installing multiple root modules
1499             assert res.rootQueries.size() == 1;
1500             ModuleIdQuery midq = res.rootQueries.iterator().next();
1501             ModuleInfo root = null;
1502             for (String mn : res.moduleViewForName.keySet()) {
1503                 ModuleView mv = res.moduleViewForName.get(mn);
1504                 if (midq.matches(mv.id())) {
1505                     root = mv.moduleInfo();
1506                     break;
1507                 }
1508             }
1509             assert root != null;
1510 
1511             // Download
1512             //
1513             for (ModuleId mid : res.modulesNeeded()) {
1514                 URI u = res.locationForName.get(mid.name());
1515                 assert u != null;
1516                 RemoteRepository rr = repositoryList().firstRepository();
1517                 assert rr != null;
1518                 installWhileLocked(rr.fetchMetaData(mid).getType(), 






1519                                    rr.fetch(mid), 
1520                                    verifySignature, 
1521                                    strip);
1522                 res.locationForName.put(mid.name(), location());
1523                 // ## If something goes wrong, delete all our modules
1524             }
1525 
1526             // Configure
1527             //
1528             configureWhileModuleDirectoryLocked(res.modulesNeeded());
1529             complete = true;
1530         } catch (ConfigurationException | IOException | SignatureException |
1531                  ModuleFileParserException x) {  // ## catch throwable??
1532             try {
1533                 for (ModuleId mid : res.modulesNeeded()) {
1534                     ModuleInfo mi = readLocalModuleInfo(mid);
1535                     if (mi != null) {
1536                         moduleDictionary.remove(mi);
1537                     }
1538                 }




  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package org.openjdk.jigsaw;
  27 
  28 import java.lang.module.*;
  29 import java.io.*;
  30 import java.net.URI;
  31 import java.nio.channels.FileChannel;
  32 import java.nio.file.*;
  33 import java.nio.file.attribute.BasicFileAttributes;
  34 import java.security.*;
  35 import java.security.cert.*;
  36 import java.util.*;
  37 import java.util.jar.*;
  38 import java.util.zip.*;
  39 
  40 import static java.nio.file.StandardCopyOption.*;
  41 import static java.nio.file.StandardOpenOption.*;
  42 import org.openjdk.jigsaw.Repository.ModuleFileType;
  43 
  44 /**
  45  * A simple module library which stores data directly in the filesystem
  46  *
  47  * @see Library
  48  */
  49 
  50 // ## TODO: Move remaining parent-searching logic upward into Library class
  51 
  52 // On-disk library layout
  53 //
  54 //   $LIB/%jigsaw-library
  55 //        com.foo.bar/1.2.3/info (= module-info.class)
  56 //                          index (list of defined classes)
  57 //                          config (resolved configuration, if a root)
  58 //                          classes/com/foo/bar/...
  59 //                          resources/com/foo/bar/...
  60 //                          lib/libbar.so
  61 //                          bin/bar
  62 //                          signer (signer's certchain & timestamp)


 141     {
 142         private static final String FILE
 143             = FileConstants.META_PREFIX + "jigsaw-library";
 144 
 145         private static final int MAJOR_VERSION = 0;
 146         private static final int MINOR_VERSION = 1;
 147 
 148         private static final int DEFLATED = 1 << 0;
 149 
 150         private File parent;
 151         // location of native libs for this library (may be outside the library)
 152         // null:default, to use a per-module 'lib' directory
 153         private File natlibs;
 154         // location of native cmds for this library (may be outside the library)
 155         // null:default, to use a per-module 'bin' directory
 156         private File natcmds;
 157         // location of config files for this library (may be outside the library)
 158         // null:default, to use a per-module 'etc' directory
 159         private File configs;
 160         private Set<StorageOption> opts;
 161         // target Operating System of this library
 162         private String os;
 163         // target Architecture of this library
 164         private String arch;
 165 
 166         public File parent()  { return parent;  }
 167         public File natlibs() { return natlibs; }
 168         public File natcmds() { return natcmds; }
 169         public File configs() { return configs; }
 170         public String os()    { return os; }
 171         public String arch()  { return arch; }
 172         public boolean isDeflated() {
 173             return opts.contains(StorageOption.DEFLATED);
 174         }
 175 
 176         private Header(File root) {
 177             super(MAJOR_VERSION, MINOR_VERSION,
 178                   FileConstants.Type.LIBRARY_HEADER,
 179                   new File(root, FILE));
 180         }
 181 
 182         private Header(File root, File parent, File natlibs, File natcmds,
 183                        File configs, Set<StorageOption> opts, String os,
 184                        String arch) {
 185             this(root);
 186             this.parent = parent;
 187             this.natlibs = natlibs;
 188             this.natcmds = natcmds;
 189             this.configs = configs;
 190             this.os = os;
 191             this.arch = arch;
 192             this.opts = new HashSet<>(opts);
 193         }
 194 
 195         private void storePath(File p, DataOutputStream out) throws IOException {
 196             if (p != null) {
 197                 out.writeByte(1);
 198                 out.writeUTF(Files.convertSeparator(p.toString()));
 199             } else {
 200                 out.write(0);
 201             }
 202         }
 203 
 204         private void storeUTF(String s, DataOutputStream out) throws IOException {
 205             if (s != null) {
 206                 out.writeByte(1);
 207                 out.writeUTF(s);
 208             } else {
 209                 out.write(0);
 210             }
 211         }
 212 
 213         @Override
 214         protected void storeRest(DataOutputStream out) throws IOException {
 215             int flags = 0;
 216             if (isDeflated())
 217                 flags |= DEFLATED;
 218             out.writeShort(flags);
 219 
 220             storePath(parent, out);
 221             storePath(natlibs, out);
 222             storePath(natcmds, out);
 223             storePath(configs, out);
 224             storeUTF(os, out);
 225             storeUTF(arch, out);
 226         }
 227 
 228         private File loadPath(DataInputStream in) throws IOException {
 229             if (in.readByte() != 0)
 230                 return new File(Files.platformSeparator(in.readUTF()));
 231             return null;
 232         }
 233 
 234         private String loadUTF(DataInputStream in) throws IOException {
 235             if (in.readByte() != 0)
 236                 return in.readUTF();
 237             return null;
 238         }
 239 
 240         @Override
 241         protected void loadRest(DataInputStream in) throws IOException {
 242             opts = new HashSet<StorageOption>();
 243             int flags = in.readShort();
 244             if ((flags & DEFLATED) == DEFLATED)
 245                 opts.add(StorageOption.DEFLATED);
 246             parent = loadPath(in);
 247             natlibs = loadPath(in);
 248             natcmds = loadPath(in);
 249             configs = loadPath(in);
 250             os = loadUTF(in);
 251             arch = loadUTF(in);
 252         }
 253 
 254         private static Header load(File f) throws IOException {
 255             Header h = new Header(f);
 256             h.load();
 257             return h;
 258         }
 259     }
 260 
 261     private final File root;
 262     private final File canonicalRoot;
 263     private final File parentPath;
 264     private final File natlibs;
 265     private final File natcmds;
 266     private final File configs;
 267     private final ModuleArchitecture modArch;
 268     private final SimpleLibrary parent;
 269     private final Header hd;
 270     private final ModuleDictionary moduleDictionary;
 271     private final File lockf;
 272     private final File trash;
 273 
 274     public String name() { return root.toString(); }
 275     public File root() { return canonicalRoot; }
 276     public int majorVersion() { return hd.majorVersion; }
 277     public int minorVersion() { return hd.minorVersion; }
 278     public SimpleLibrary parent() { return parent; }
 279     public File natlibs() { return natlibs; }
 280     public File natcmds() { return natcmds; }
 281     public File configs() { return configs; }
 282     public ModuleArchitecture architecture() { return modArch; }
 283     public boolean isDeflated() { return hd.isDeflated(); }
 284 
 285     private URI location = null;
 286     public URI location() {
 287         if (location == null)
 288             location = root().toURI();
 289         return location;
 290     }
 291 
 292     @Override
 293     public String toString() {
 294         return (this.getClass().getName()
 295                 + "[" + canonicalRoot
 296                 + ", v" + hd.majorVersion + "." + hd.minorVersion + "]");
 297     }
 298 
 299     private static File resolveAndEnsurePath(File path) throws IOException {
 300         if (path == null) { return null; }
 301 
 302         File p = path.getCanonicalFile();


 314         // Return the path relative to the canonical root
 315         return (canonicalRoot.toPath().relativize(path.toPath().toRealPath())).toFile();
 316     }
 317 
 318     // Opens an existing library
 319     private SimpleLibrary(File path) throws IOException {
 320         root = path;
 321         canonicalRoot = root.getCanonicalFile();
 322         Files.ensureIsDirectory(root);
 323         hd = Header.load(root);
 324 
 325         parentPath = hd.parent();
 326         parent = parentPath != null ? open(parentPath) : null;
 327 
 328         natlibs = hd.natlibs() == null ? null :
 329             new File(canonicalRoot, hd.natlibs().toString()).getCanonicalFile();
 330         natcmds = hd.natcmds() == null ? null :
 331             new File(canonicalRoot, hd.natcmds().toString()).getCanonicalFile();
 332         configs = hd.configs() == null ? null :
 333             new File(canonicalRoot, hd.configs().toString()).getCanonicalFile();
 334         modArch = ModuleArchitecture.create(hd.os(), hd.arch());
 335 
 336         lockf = new File(root, FileConstants.META_PREFIX + "lock");
 337         trash = new File(root, TRASH);
 338         moduleDictionary = new ModuleDictionary(root);
 339     }
 340 
 341     // Creates a new library
 342     private SimpleLibrary(File path, File parentPath, File natlibs, File natcmds,
 343                           File configs, Set<StorageOption> opts,
 344                           ModuleArchitecture modArch)
 345         throws IOException
 346     {
 347         root = path;
 348         canonicalRoot = root.getCanonicalFile();
 349         if (root.exists()) {
 350             Files.ensureIsDirectory(root);
 351             if (root.list().length != 0)
 352                 throw new IOException(root + ": Already Exists");
 353             Files.ensureWriteable(root);
 354         } else
 355             Files.mkdirs(root, root.toString());
 356 
 357         this.parent = parentPath != null ? open(parentPath) : null;
 358         this.parentPath = parentPath != null ? this.parent.root() : null;
 359 
 360         this.natlibs = resolveAndEnsurePath(natlibs);
 361         this.natcmds = resolveAndEnsurePath(natcmds);
 362         this.configs = resolveAndEnsurePath(configs);
 363         this.modArch = modArch;
 364 
 365         hd = new Header(canonicalRoot, this.parentPath, relativize(this.natlibs),
 366                         relativize(this.natcmds), relativize(this.configs),
 367                         opts, modArch.os(), modArch.arch());
 368         hd.store();
 369 
 370         lockf = new File(root, FileConstants.META_PREFIX + "lock");
 371         lockf.createNewFile();
 372         trash = new File(root, TRASH);
 373         Files.mkdirs(trash, "module library trash");
 374         moduleDictionary = new ModuleDictionary(canonicalRoot);
 375         moduleDictionary.store();
 376     }
 377 
 378     public static SimpleLibrary create(File path, File parent, File natlibs,
 379                                        File natcmds, File configs,
 380                                        Set<StorageOption> opts,
 381                                        ModuleArchitecture modArch)
 382         throws IOException
 383     {
 384         return new SimpleLibrary(path, parent, natlibs, natcmds, configs,
 385                                  opts, modArch);
 386     }
 387 
 388     public static SimpleLibrary create(File path, File parent, Set<StorageOption> opts)
 389         throws IOException
 390     {
 391         return new SimpleLibrary(path, parent, null, null, null, opts,
 392                                  ModuleArchitecture.ANY);
 393     }
 394 
 395     public static SimpleLibrary create(File path, File parent)
 396         throws IOException
 397     {
 398         return SimpleLibrary.create(path, parent, Collections.<StorageOption>emptySet());
 399     }
 400 
 401     public static SimpleLibrary create(File path, Set<StorageOption> opts)
 402         throws IOException
 403     {
 404         // ## Should default parent to $JAVA_HOME/lib/modules
 405         return SimpleLibrary.create(path, null, opts);
 406     }
 407 
 408     public static SimpleLibrary open(File path)
 409         throws IOException
 410     {
 411         return new SimpleLibrary(path);
 412     }


1209                 }
1210             } catch (IOException y) {
1211                 x.addSuppressed(y);
1212             }
1213             throw x;
1214         } finally {
1215             if (complete) {
1216                 moduleDictionary.store();
1217             }
1218             fc.close();
1219         }
1220     }
1221 
1222     @Override
1223     public void installFromManifests(Collection<Manifest> mfs)
1224         throws ConfigurationException, IOException
1225     {
1226         installFromManifests(mfs, false);
1227     }
1228 
1229     private ModuleId installWhileLocked(ModuleFileType type, InputStream is,
1230                                         boolean verifySignature, boolean strip)
1231         throws ConfigurationException, IOException, SignatureException
1232     {
1233         switch (type) {
1234             case JAR:
1235                 Path jf = java.nio.file.Files.createTempFile(null, null);
1236                 try {
1237                     java.nio.file.Files.copy(is, jf, StandardCopyOption.REPLACE_EXISTING);
1238                     return installFromJarFile(jf.toFile(), verifySignature, strip);
1239                 } finally {
1240                     java.nio.file.Files.delete(jf);
1241                 }
1242             case JMOD:
1243             default:
1244                 return installWhileLocked(is, verifySignature, strip);
1245         }
1246     }
1247 
1248     private ModuleId installWhileLocked(InputStream is, boolean verifySignature,
1249                                         boolean strip)
1250         throws ConfigurationException, IOException, SignatureException
1251     {
1252         BufferedInputStream bin = new BufferedInputStream(is);
1253         DataInputStream in = new DataInputStream(bin);
1254         ModuleInfo mi = null;
1255         try (ModuleFile.Reader mr = new ModuleFile.Reader(in)) {
1256             ModuleInfo moduleInfo = jms.parseModuleInfo(mr.getModuleInfoBytes());
1257 
1258             // Installee must have the same architecture as the library
1259             if (!mr.getArchitecture().matches(architecture()))
1260                 throw new IOException("Module architecture [" + mr.getArchitecture()
1261                                       + "] does not match library ["
1262                                       + architecture() + "]");  // ## exception type??
1263 
1264             File md = moduleDictionary.add(moduleInfo);
1265             mi = moduleInfo;
1266             if (verifySignature && mr.hasSignature()) {
1267                 // Verify the module signature
1268                 SignedModule sm = new SignedModule(mr);
1269                 Set<CodeSigner> signers = sm.verifySignature();
1270 
1271                 // Validate the signers
1272                 try {
1273                     SignedModule.validateSigners(signers);
1274                 } catch (CertificateException x) {
1275                     throw new SignatureException(x);
1276                 }
1277 
1278                 // ## TODO: Check policy and determine if signer is trusted
1279                 // ## and what permissions should be granted.
1280                 // ## If there is no policy entry, show signers and prompt
1281                 // ## user to accept before proceeding.
1282 
1283                 // Verify the module header hash and the module info hash


1544             // ## Handle case of installing multiple root modules
1545             assert res.rootQueries.size() == 1;
1546             ModuleIdQuery midq = res.rootQueries.iterator().next();
1547             ModuleInfo root = null;
1548             for (String mn : res.moduleViewForName.keySet()) {
1549                 ModuleView mv = res.moduleViewForName.get(mn);
1550                 if (midq.matches(mv.id())) {
1551                     root = mv.moduleInfo();
1552                     break;
1553                 }
1554             }
1555             assert root != null;
1556 
1557             // Download
1558             //
1559             for (ModuleId mid : res.modulesNeeded()) {
1560                 URI u = res.locationForName.get(mid.name());
1561                 assert u != null;
1562                 RemoteRepository rr = repositoryList().firstRepository();
1563                 assert rr != null;
1564                 Repository.ModuleFileMetaData mfmd = rr.fetchMetaData(mid);
1565                 // Installee must have the same architecture as the library
1566                 if (!mfmd.architecture().matches(architecture()))
1567                     throw new IOException("Module architecture [" + mfmd.architecture()
1568                                           + "] does not match library ["
1569                                           + architecture() + "]");  // ## exception type??
1570                 installWhileLocked(mfmd.getType(),
1571                                    rr.fetch(mid),
1572                                    verifySignature,
1573                                    strip);
1574                 res.locationForName.put(mid.name(), location());
1575                 // ## If something goes wrong, delete all our modules
1576             }
1577 
1578             // Configure
1579             //
1580             configureWhileModuleDirectoryLocked(res.modulesNeeded());
1581             complete = true;
1582         } catch (ConfigurationException | IOException | SignatureException |
1583                  ModuleFileParserException x) {  // ## catch throwable??
1584             try {
1585                 for (ModuleId mid : res.modulesNeeded()) {
1586                     ModuleInfo mi = readLocalModuleInfo(mid);
1587                     if (mi != null) {
1588                         moduleDictionary.remove(mi);
1589                     }
1590                 }