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

Print this page




 220             configs = loadPath(in);
 221         }
 222 
 223         private static Header load(File f) throws IOException {
 224             Header h = new Header(f);
 225             h.load();
 226             return h;
 227         }
 228     }
 229 
 230     private final File root;
 231     private final File canonicalRoot;
 232     private final File parentPath;
 233     private final File natlibs;
 234     private final File natcmds;
 235     private final File configs;
 236     private final SimpleLibrary parent;
 237     private final Header hd;
 238     private final ModuleDictionary moduleDictionary;
 239     private final File lockf;

 240 
 241     public String name() { return root.toString(); }
 242     public File root() { return canonicalRoot; }
 243     public int majorVersion() { return hd.majorVersion; }
 244     public int minorVersion() { return hd.minorVersion; }
 245     public SimpleLibrary parent() { return parent; }
 246     public File natlibs() { return natlibs; }
 247     public File natcmds() { return natcmds; }
 248     public File configs() { return configs; }
 249     public boolean isDeflated() { return hd.isDeflated(); }
 250 
 251     private URI location = null;
 252     public URI location() {
 253         if (location == null)
 254             location = root().toURI();
 255         return location;
 256     }
 257 
 258     @Override
 259     public String toString() {


 282     }
 283 
 284     // Opens an existing library
 285     private SimpleLibrary(File path) throws IOException {
 286         root = path;
 287         canonicalRoot = root.getCanonicalFile();
 288         Files.ensureIsDirectory(root);
 289         hd = Header.load(root);
 290 
 291         parentPath = hd.parent();
 292         parent = parentPath != null ? open(parentPath) : null;
 293 
 294         natlibs = hd.natlibs() == null ? null :
 295             new File(canonicalRoot, hd.natlibs().toString()).getCanonicalFile();
 296         natcmds = hd.natcmds() == null ? null :
 297             new File(canonicalRoot, hd.natcmds().toString()).getCanonicalFile();
 298         configs = hd.configs() == null ? null :
 299             new File(canonicalRoot, hd.configs().toString()).getCanonicalFile();
 300 
 301         lockf = new File(root, FileConstants.META_PREFIX + "lock");

 302         moduleDictionary = new ModuleDictionary(root);
 303     }
 304 
 305     // Creates a new library
 306     private SimpleLibrary(File path, File parentPath, File natlibs, File natcmds,
 307                           File configs, Set<StorageOption> opts)
 308         throws IOException
 309     {
 310         root = path;
 311         canonicalRoot = root.getCanonicalFile();
 312         if (root.exists()) {
 313             Files.ensureIsDirectory(root);
 314             if (root.list().length != 0)
 315                 throw new IOException(root + ": Already Exists");
 316             Files.ensureWriteable(root);
 317         } else
 318             Files.mkdirs(root, root.toString());
 319 
 320         this.parent = parentPath != null ? open(parentPath) : null;
 321         this.parentPath = parentPath != null ? this.parent.root() : null;
 322 
 323         this.natlibs = resolveAndEnsurePath(natlibs);
 324         this.natcmds = resolveAndEnsurePath(natcmds);
 325         this.configs = resolveAndEnsurePath(configs);
 326 
 327         hd = new Header(canonicalRoot, this.parentPath, relativize(this.natlibs),
 328                         relativize(this.natcmds), relativize(this.configs), opts);
 329         hd.store();
 330 
 331         lockf = new File(root, FileConstants.META_PREFIX + "lock");
 332         lockf.createNewFile();


 333         moduleDictionary = new ModuleDictionary(canonicalRoot);
 334         moduleDictionary.store();
 335     }
 336 
 337     public static SimpleLibrary create(File path, File parent, File natlibs,
 338                                        File natcmds, File configs,
 339                                        Set<StorageOption> opts)
 340         throws IOException
 341     {
 342         return new SimpleLibrary(path, parent, natlibs, natcmds, configs, opts);
 343     }
 344 
 345     public static SimpleLibrary create(File path, File parent, Set<StorageOption> opts)
 346         throws IOException
 347     {
 348         return new SimpleLibrary(path, parent, null, null, null, opts);
 349     }
 350 
 351     public static SimpleLibrary create(File path, File parent)
 352         throws IOException


1455                 }
1456             } catch (IOException y) {
1457                 x.addSuppressed(y);
1458             }
1459             throw x;
1460         } finally {
1461             if (complete) {
1462                 moduleDictionary.store();
1463             }
1464             fc.close();
1465         }
1466     }
1467 
1468     @Override
1469     public void install(Resolution res, boolean verifySignature)
1470         throws ConfigurationException, IOException, SignatureException
1471     {
1472         install(res, verifySignature, false);
1473     }
1474 
























































































































1475     /**
1476      * <p> Pre-install one or more modules to an arbitrary destination
1477      * directory. </p>
1478      *
1479      * <p> A pre-installed module has the same format as within the library
1480      * itself, except that there is never a configuration file. </p>
1481      *
1482      * <p> This method is provided for use by the module-packaging tool. </p>
1483      *
1484      * @param   mfs
1485      *          The manifest describing the contents of the modules to be
1486      *          pre-installed
1487      *
1488      * @param   dst
1489      *          The destination directory, with one subdirectory per module
1490      *          name, each of which contains one subdirectory per version
1491      */
1492     public void preInstall(Collection<Manifest> mfs, File dst)
1493         throws IOException
1494     {


1525      * library. </p>
1526      *
1527      * @param   mids
1528      *          The module ids of the new or updated modules, or
1529      *          {@code null} if the configuration of every root module
1530      *          should be (re)computed
1531      */
1532     public void configure(Collection<ModuleId> mids)
1533         throws ConfigurationException, IOException
1534     {
1535         try (FileChannel fc = FileChannel.open(lockf.toPath(), WRITE)) {
1536             fc.lock();
1537             configureWhileModuleDirectoryLocked(mids);
1538         }
1539     }
1540 
1541     private void configureWhileModuleDirectoryLocked(Collection<ModuleId> mids)
1542         throws ConfigurationException, IOException
1543     {
1544         // ## mids not used yet












1545         List<ModuleId> roots = new ArrayList<>();
1546         for (ModuleId mid : listLocalDeclaringModuleIds()) {
1547             // each module can have multiple entry points
1548             // only configure once for each module.
1549             ModuleInfo mi = readModuleInfo(mid);
1550             for (ModuleView mv : mi.views()) {
1551                 if (mv.mainClass() != null) {
1552                     roots.add(mid);
1553                     break;
1554                 }
1555             }
1556         }
1557 
1558         for (ModuleId mid : roots) {
1559             // ## We could be a lot more clever about this!
1560             Configuration<Context> cf
1561                 = Configurator.configure(this, mid.toQuery());
1562             File md = moduleDictionary.findDeclaringModuleDir(mid);
1563             new StoredConfiguration(md, cf).store();
1564         }
1565     }
1566 
1567     public URI findLocalResource(ModuleId mid, String name)
1568         throws IOException
1569     {
1570         return locateContent(mid, name);
1571     }
1572 
1573     public File findLocalNativeLibrary(ModuleId mid, String name)
1574         throws IOException
1575     {
1576         File f = natlibs();
1577         if (f == null) {
1578             f = moduleDictionary.findDeclaringModuleDir(mid);
1579             if (f == null)
1580                 return null;
1581             f = new File(f, "lib");
1582         }
1583         f = new File(f, name);
1584         if (!f.exists())
1585             return null;


1795 
1796         private void delete(File md) throws IOException {
1797             if (!md.exists())
1798                 return;
1799 
1800             checkModuleDir(md);
1801             ModuleFile.Reader.remove(md);
1802             File parent = md.getParentFile();
1803             if (parent.list().length == 0)
1804                 parent.delete();
1805         }
1806         
1807         void refresh() throws IOException {
1808             providingModuleIds = new LinkedHashMap<>();
1809             moduleIdsForName = new LinkedHashMap<>();
1810             modules = new HashSet<>();
1811 
1812             try (DirectoryStream<Path> ds = java.nio.file.Files.newDirectoryStream(root.toPath())) {
1813                 for (Path mnp : ds) {
1814                     String mn = mnp.toFile().getName();
1815                     if (mn.startsWith(FileConstants.META_PREFIX)) {

1816                         continue;
1817                     }
1818 
1819                     try (DirectoryStream<Path> mds = java.nio.file.Files.newDirectoryStream(mnp)) {
1820                         for (Path versionp : mds) {
1821                             File v = versionp.toFile();
1822                             if (!v.isDirectory()) {
1823                                 throw new IOException(versionp + ": Not a directory");
1824                             }
1825                             modules.add(jms.parseModuleId(mn, v.getName()));
1826                         }
1827                     }
1828                 }
1829             }
1830             for (ModuleId mid : modules) {
1831                 byte[] bs = Files.load(new File(moduleDir(root, mid), "info"));
1832                 ModuleInfo mi = jms.parseModuleInfo(bs);
1833                 addToDirectory(mi);
1834             }
1835         }




 220             configs = loadPath(in);
 221         }
 222 
 223         private static Header load(File f) throws IOException {
 224             Header h = new Header(f);
 225             h.load();
 226             return h;
 227         }
 228     }
 229 
 230     private final File root;
 231     private final File canonicalRoot;
 232     private final File parentPath;
 233     private final File natlibs;
 234     private final File natcmds;
 235     private final File configs;
 236     private final SimpleLibrary parent;
 237     private final Header hd;
 238     private final ModuleDictionary moduleDictionary;
 239     private final File lockf;
 240     private final File trash;
 241 
 242     public String name() { return root.toString(); }
 243     public File root() { return canonicalRoot; }
 244     public int majorVersion() { return hd.majorVersion; }
 245     public int minorVersion() { return hd.minorVersion; }
 246     public SimpleLibrary parent() { return parent; }
 247     public File natlibs() { return natlibs; }
 248     public File natcmds() { return natcmds; }
 249     public File configs() { return configs; }
 250     public boolean isDeflated() { return hd.isDeflated(); }
 251 
 252     private URI location = null;
 253     public URI location() {
 254         if (location == null)
 255             location = root().toURI();
 256         return location;
 257     }
 258 
 259     @Override
 260     public String toString() {


 283     }
 284 
 285     // Opens an existing library
 286     private SimpleLibrary(File path) throws IOException {
 287         root = path;
 288         canonicalRoot = root.getCanonicalFile();
 289         Files.ensureIsDirectory(root);
 290         hd = Header.load(root);
 291 
 292         parentPath = hd.parent();
 293         parent = parentPath != null ? open(parentPath) : null;
 294 
 295         natlibs = hd.natlibs() == null ? null :
 296             new File(canonicalRoot, hd.natlibs().toString()).getCanonicalFile();
 297         natcmds = hd.natcmds() == null ? null :
 298             new File(canonicalRoot, hd.natcmds().toString()).getCanonicalFile();
 299         configs = hd.configs() == null ? null :
 300             new File(canonicalRoot, hd.configs().toString()).getCanonicalFile();
 301 
 302         lockf = new File(root, FileConstants.META_PREFIX + "lock");
 303         trash = new File(root, TRASH);
 304         moduleDictionary = new ModuleDictionary(root);
 305     }
 306 
 307     // Creates a new library
 308     private SimpleLibrary(File path, File parentPath, File natlibs, File natcmds,
 309                           File configs, Set<StorageOption> opts)
 310         throws IOException
 311     {
 312         root = path;
 313         canonicalRoot = root.getCanonicalFile();
 314         if (root.exists()) {
 315             Files.ensureIsDirectory(root);
 316             if (root.list().length != 0)
 317                 throw new IOException(root + ": Already Exists");
 318             Files.ensureWriteable(root);
 319         } else
 320             Files.mkdirs(root, root.toString());
 321 
 322         this.parent = parentPath != null ? open(parentPath) : null;
 323         this.parentPath = parentPath != null ? this.parent.root() : null;
 324 
 325         this.natlibs = resolveAndEnsurePath(natlibs);
 326         this.natcmds = resolveAndEnsurePath(natcmds);
 327         this.configs = resolveAndEnsurePath(configs);
 328 
 329         hd = new Header(canonicalRoot, this.parentPath, relativize(this.natlibs),
 330                         relativize(this.natcmds), relativize(this.configs), opts);
 331         hd.store();
 332 
 333         lockf = new File(root, FileConstants.META_PREFIX + "lock");
 334         lockf.createNewFile();
 335         trash = new File(root, TRASH);
 336         Files.mkdirs(trash, "module library trash");
 337         moduleDictionary = new ModuleDictionary(canonicalRoot);
 338         moduleDictionary.store();
 339     }
 340 
 341     public static SimpleLibrary create(File path, File parent, File natlibs,
 342                                        File natcmds, File configs,
 343                                        Set<StorageOption> opts)
 344         throws IOException
 345     {
 346         return new SimpleLibrary(path, parent, natlibs, natcmds, configs, opts);
 347     }
 348 
 349     public static SimpleLibrary create(File path, File parent, Set<StorageOption> opts)
 350         throws IOException
 351     {
 352         return new SimpleLibrary(path, parent, null, null, null, opts);
 353     }
 354 
 355     public static SimpleLibrary create(File path, File parent)
 356         throws IOException


1459                 }
1460             } catch (IOException y) {
1461                 x.addSuppressed(y);
1462             }
1463             throw x;
1464         } finally {
1465             if (complete) {
1466                 moduleDictionary.store();
1467             }
1468             fc.close();
1469         }
1470     }
1471 
1472     @Override
1473     public void install(Resolution res, boolean verifySignature)
1474         throws ConfigurationException, IOException, SignatureException
1475     {
1476         install(res, verifySignature, false);
1477     }
1478 
1479     @Override
1480     public void removeForcibly(List<ModuleId> mids)
1481         throws IOException
1482     {
1483         try {
1484             remove(mids, true, false);
1485         } catch (ConfigurationException x) {
1486             throw new Error("should not be thrown when forcibly removing", x);
1487         }
1488     }
1489 
1490     @Override
1491     public void remove(List<ModuleId> mids, boolean dry)
1492         throws ConfigurationException, IOException
1493     {
1494         remove(mids, false,  dry);
1495     }
1496 
1497     private void remove(List<ModuleId> mids, boolean force, boolean dry)
1498         throws ConfigurationException, IOException
1499     {
1500         IOException ioe = null;
1501 
1502         try (FileChannel fc = FileChannel.open(lockf.toPath(), WRITE)) {
1503             fc.lock();
1504             for (ModuleId mid : mids) {
1505                 if (moduleDictionary.findDeclaringModuleDir(mid) == null)
1506                     throw new IllegalArgumentException(mid + ": No such module");
1507             }
1508             if (!force)
1509                 ensureNotInConfiguration(mids);
1510             if (dry)
1511                 return;
1512 
1513             // The library may be altered after this point, so the modules
1514             // dictionary needs to be refreshed
1515             List<IOException> excs = removeWhileLocked(mids);
1516             try {
1517                 moduleDictionary.refresh();
1518                 moduleDictionary.store();
1519             } catch (IOException x) {
1520                 excs.add(x);
1521             }
1522             if (!excs.isEmpty()) {
1523                 ioe = excs.remove(0);
1524                 for (IOException x : excs)
1525                     ioe.addSuppressed(x);
1526             }
1527         } finally {
1528             if (ioe != null)
1529                 throw ioe;
1530         }
1531     }
1532 
1533     private void ensureNotInConfiguration(List<ModuleId> mids)
1534         throws ConfigurationException, IOException
1535     {
1536         // ## We do not know if a root module in a child library depends on one
1537         // ## of the 'to be removed' modules. We would break it's configuration.
1538 
1539         // check each root configuration for reference to a module in mids
1540         for (ModuleId rootid : libraryRoots()) {
1541             // skip any root modules being removed
1542             if (mids.contains(rootid))
1543                 continue;
1544 
1545             Configuration<Context> cf = readConfiguration(rootid);
1546             for (Context cx : cf.contexts()) {
1547                 for (ModuleId mid : cx.modules()) {
1548                     if (mids.contains(mid))
1549                         throw new ConfigurationException(mid +
1550                                 ": being used by " + rootid);
1551                 }
1552             }
1553         }
1554     }
1555 
1556     private static final String TRASH = ".trash";
1557     // lazy initialization of Random
1558     private static class LazyInitialization {
1559         static final Random random = new Random();
1560     }
1561     private static Path moduleTrashDir(File trash, ModuleId mid)
1562         throws IOException
1563     {
1564         String mn = mid.name();
1565         Version version = mid.version();
1566         String v = (version != null) ? version.toString() : "default";
1567         for (;;) {
1568             long n = LazyInitialization.random.nextLong();
1569             n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n);
1570             String modTrashName = mn + '_' + v + '_' + Long.toString(n);
1571             File mtd = new File(trash, modTrashName);
1572             if (!mtd.exists())
1573                 return mtd.toPath();
1574         }
1575     }
1576 
1577     private List<IOException> removeWhileLocked(List<ModuleId> mids) {
1578         List<IOException> excs = new ArrayList<>();
1579         // First move the modules to the .trash dir
1580         for (ModuleId mid : mids) {
1581             try {
1582                 File md = moduleDir(root, mid);
1583                 java.nio.file.Files.move(md.toPath(),
1584                                          moduleTrashDir(trash, mid),
1585                                          ATOMIC_MOVE);
1586                 File p = md.getParentFile();
1587                 if (p.list().length == 0)
1588                     java.nio.file.Files.delete(p.toPath());
1589             } catch (IOException x) {
1590                 excs.add(x);
1591             }
1592         }
1593         for (String tm : trash.list())
1594             excs.addAll(ModuleFile.Reader.remove(new File(trash, tm)));
1595 
1596         return excs;
1597     }
1598 
1599     /**
1600      * <p> Pre-install one or more modules to an arbitrary destination
1601      * directory. </p>
1602      *
1603      * <p> A pre-installed module has the same format as within the library
1604      * itself, except that there is never a configuration file. </p>
1605      *
1606      * <p> This method is provided for use by the module-packaging tool. </p>
1607      *
1608      * @param   mfs
1609      *          The manifest describing the contents of the modules to be
1610      *          pre-installed
1611      *
1612      * @param   dst
1613      *          The destination directory, with one subdirectory per module
1614      *          name, each of which contains one subdirectory per version
1615      */
1616     public void preInstall(Collection<Manifest> mfs, File dst)
1617         throws IOException
1618     {


1649      * library. </p>
1650      *
1651      * @param   mids
1652      *          The module ids of the new or updated modules, or
1653      *          {@code null} if the configuration of every root module
1654      *          should be (re)computed
1655      */
1656     public void configure(Collection<ModuleId> mids)
1657         throws ConfigurationException, IOException
1658     {
1659         try (FileChannel fc = FileChannel.open(lockf.toPath(), WRITE)) {
1660             fc.lock();
1661             configureWhileModuleDirectoryLocked(mids);
1662         }
1663     }
1664 
1665     private void configureWhileModuleDirectoryLocked(Collection<ModuleId> mids)
1666         throws ConfigurationException, IOException
1667     {
1668         // ## mids not used yet
1669         for (ModuleId mid : libraryRoots()) {
1670             // ## We could be a lot more clever about this!
1671             Configuration<Context> cf
1672                 = Configurator.configure(this, mid.toQuery());
1673             File md = moduleDictionary.findDeclaringModuleDir(mid);
1674             new StoredConfiguration(md, cf).store();
1675         }
1676     }
1677 
1678     private List<ModuleId> libraryRoots()
1679         throws IOException
1680     {
1681         List<ModuleId> roots = new ArrayList<>();
1682         for (ModuleId mid : listLocalDeclaringModuleIds()) {
1683             // each module can have multiple entry points, but
1684             // only one configuration for each module.
1685             ModuleInfo mi = readModuleInfo(mid);
1686             for (ModuleView mv : mi.views()) {
1687                 if (mv.mainClass() != null) {
1688                     roots.add(mid);
1689                     break;
1690                 }
1691             }
1692         }
1693         return roots;






1694     }

1695 
1696     public URI findLocalResource(ModuleId mid, String name)
1697         throws IOException
1698     {
1699         return locateContent(mid, name);
1700     }
1701 
1702     public File findLocalNativeLibrary(ModuleId mid, String name)
1703         throws IOException
1704     {
1705         File f = natlibs();
1706         if (f == null) {
1707             f = moduleDictionary.findDeclaringModuleDir(mid);
1708             if (f == null)
1709                 return null;
1710             f = new File(f, "lib");
1711         }
1712         f = new File(f, name);
1713         if (!f.exists())
1714             return null;


1924 
1925         private void delete(File md) throws IOException {
1926             if (!md.exists())
1927                 return;
1928 
1929             checkModuleDir(md);
1930             ModuleFile.Reader.remove(md);
1931             File parent = md.getParentFile();
1932             if (parent.list().length == 0)
1933                 parent.delete();
1934         }
1935 
1936         void refresh() throws IOException {
1937             providingModuleIds = new LinkedHashMap<>();
1938             moduleIdsForName = new LinkedHashMap<>();
1939             modules = new HashSet<>();
1940 
1941             try (DirectoryStream<Path> ds = java.nio.file.Files.newDirectoryStream(root.toPath())) {
1942                 for (Path mnp : ds) {
1943                     String mn = mnp.toFile().getName();
1944                     if (mn.startsWith(FileConstants.META_PREFIX) ||
1945                         TRASH.equals(mn)) {
1946                         continue;
1947                     }
1948 
1949                     try (DirectoryStream<Path> mds = java.nio.file.Files.newDirectoryStream(mnp)) {
1950                         for (Path versionp : mds) {
1951                             File v = versionp.toFile();
1952                             if (!v.isDirectory()) {
1953                                 throw new IOException(versionp + ": Not a directory");
1954                             }
1955                             modules.add(jms.parseModuleId(mn, v.getName()));
1956                         }
1957                     }
1958                 }
1959             }
1960             for (ModuleId mid : modules) {
1961                 byte[] bs = Files.load(new File(moduleDir(root, mid), "info"));
1962                 ModuleInfo mi = jms.parseModuleInfo(bs);
1963                 addToDirectory(mi);
1964             }
1965         }