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;


1781                 providingModuleIds.remove(view.id());
1782                 Set<ModuleId> mids = moduleIdsForName.get(view.id().name());
1783                 if (mids != null)
1784                     mids.remove(view.id());
1785                 for (ModuleId alias : view.aliases()) {
1786                     providingModuleIds.remove(alias);
1787                     mids = moduleIdsForName.get(alias.name());
1788                     if (mids != null)
1789                         mids.remove(view.id());
1790                 }
1791             }
1792             File md = moduleDir(root, mi.id());
1793             delete(md);
1794         }
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         FileChannel fc = FileChannel.open(lockf.toPath(), WRITE);
1502         try {
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                 checkRootsRequire(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         } catch (IOException x) {
1528             ioe = x;
1529         } finally {
1530             fc.close();
1531             if (ioe != null)
1532                 throw ioe;
1533         }
1534     }
1535 
1536     private void checkRootsRequire(List<ModuleId> mids)
1537         throws ConfigurationException, IOException
1538     {
1539         // ## We do not know if a root module in a child library depends on one
1540         // ## of the 'to be removed' modules. We would break it's configuration.
1541 
1542         // check each root configuration for reference to a module in mids
1543         for (ModuleId rootid : libraryRoots()) {
1544             // skip any root modules being removed
1545             if (mids.contains(rootid))
1546                 continue;
1547 
1548             Configuration<Context> cf = readConfiguration(rootid);
1549             for (Context cx : cf.contexts()) {
1550                 for (ModuleId mid : cx.modules()) {
1551                     if (mids.contains(mid))
1552                         throw new ConfigurationException(mid +
1553                                 ": being used by " + rootid);
1554                 }
1555             }
1556         }
1557     }
1558 
1559     private static final String TRASH = ".trash";
1560     // file name generation, same as java.io.File for now
1561     // lazy initialization of SecureRandom
1562     private static class LazyInitialization {
1563         static final SecureRandom random = new SecureRandom(); 
1564     }
1565     private static File moduleTrashDir(File trash, ModuleId mid)
1566         throws IOException
1567     {
1568         File mtd = null;
1569         for (;;) {
1570             long n = LazyInitialization.random.nextLong();
1571             n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n);
1572             Version version = mid.version();
1573             String v = (version != null) ? version.toString() : "default";
1574             String modTrashName = mid.name() + '_' + v + '_' + Long.toString(n);
1575             mtd = new File(trash, modTrashName);
1576             if (!mtd.exists())
1577                 break;
1578         }
1579         Files.mkdirs(mtd, mtd.toString());
1580         return mtd;
1581     }
1582 
1583     private List<IOException> removeWhileLocked(List<ModuleId> mids) {
1584         List<IOException> excs = new ArrayList<>();
1585         // First move the modules to the .trash dir
1586         for (ModuleId mid : mids) {
1587             try {
1588                 File mtd = moduleTrashDir(trash, mid);
1589                 File md = moduleDir(root, mid);
1590                 java.nio.file.Files.move(md.toPath(), mtd.toPath(), ATOMIC_MOVE);
1591                 File p = md.getParentFile();
1592                 if (p.list().length == 0)
1593                     java.nio.file.Files.delete(p.toPath());
1594             } catch (IOException x) {
1595                 excs.add(x);
1596             }
1597         }
1598         for (String tm : trash.list())
1599             excs.addAll(ModuleFile.Reader.remove(new File(trash, tm)));
1600         
1601         return excs;
1602     }
1603 
1604     /**
1605      * <p> Pre-install one or more modules to an arbitrary destination
1606      * directory. </p>
1607      *
1608      * <p> A pre-installed module has the same format as within the library
1609      * itself, except that there is never a configuration file. </p>
1610      *
1611      * <p> This method is provided for use by the module-packaging tool. </p>
1612      *
1613      * @param   mfs
1614      *          The manifest describing the contents of the modules to be
1615      *          pre-installed
1616      *
1617      * @param   dst
1618      *          The destination directory, with one subdirectory per module
1619      *          name, each of which contains one subdirectory per version
1620      */
1621     public void preInstall(Collection<Manifest> mfs, File dst)
1622         throws IOException
1623     {


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






1699     }

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


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