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) {
|
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 @Override
1476 public List<IOException> removeForcibly(List<ModuleId> mids)
1477 throws IOException
1478 {
1479 try {
1480 return remove(mids, true, false);
1481 } catch (ConfigurationException x) {
1482 throw new Error("should not be thrown when forcibly removing", x);
1483 }
1484 }
1485
1486 @Override
1487 public List<IOException> remove(List<ModuleId> mids, boolean dry)
1488 throws ConfigurationException, IOException
1489 {
1490 return remove(mids, false, dry);
1491 }
1492
1493 private List<IOException> remove(List<ModuleId> mids, boolean force, boolean dry)
1494 throws ConfigurationException, IOException
1495 {
1496 boolean needRefresh = false;
1497 List<IOException> excs = new ArrayList<>();
1498 IOException ioe = null;
1499 FileChannel fc = FileChannel.open(lockf.toPath(), WRITE);
1500 try {
1501 fc.lock();
1502 for (ModuleId mid : mids) {
1503 if (moduleDictionary.findDeclaringModuleDir(mid) == null)
1504 throw new IllegalArgumentException(mid + ": No such module");
1505 }
1506 if (!force)
1507 checkRootsRequire(mids);
1508 if (dry)
1509 return Collections.emptyList();
1510
1511 // The library may be altered after this point, so the modules
1512 // dictionary needs to be refreshed
1513 needRefresh = true;
1514 excs.addAll(removeWhileLocked(mids));
1515 } catch (IOException x) {
1516 ioe = x;
1517 } finally {
1518 if (needRefresh) {
1519 try {
1520 moduleDictionary.refresh();
1521 moduleDictionary.store();
1522 } catch (IOException x) {
1523 if (ioe == null)
1524 ioe = x;
1525 else
1526 ioe.addSuppressed(x);
1527 }
1528 }
1529 fc.close();
1530 if (ioe != null)
1531 throw ioe;
1532 }
1533 return excs;
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 List<IOException> removeWhileLocked(List<ModuleId> mids) {
1560 List<IOException> excs = new ArrayList<>();
1561 for (ModuleId mid : mids) {
1562 File md = moduleDir(root, mid);
1563 excs.addAll(ModuleFile.Reader.remove(md));
1564 File p = md.getParentFile();
1565 if (p.list().length == 0) {
1566 IOException x = Files.deleteUnchecked(p.toPath());
1567 if (x != null)
1568 excs.add(x);
1569 }
1570 }
1571 return excs;
1572 }
1573
1574 /**
1575 * <p> Pre-install one or more modules to an arbitrary destination
1576 * directory. </p>
1577 *
1578 * <p> A pre-installed module has the same format as within the library
1579 * itself, except that there is never a configuration file. </p>
1580 *
1581 * <p> This method is provided for use by the module-packaging tool. </p>
1582 *
1583 * @param mfs
1584 * The manifest describing the contents of the modules to be
1585 * pre-installed
1586 *
1587 * @param dst
1588 * The destination directory, with one subdirectory per module
1589 * name, each of which contains one subdirectory per version
1590 */
1591 public void preInstall(Collection<Manifest> mfs, File dst)
1592 throws IOException
1593 {
1624 * library. </p>
1625 *
1626 * @param mids
1627 * The module ids of the new or updated modules, or
1628 * {@code null} if the configuration of every root module
1629 * should be (re)computed
1630 */
1631 public void configure(Collection<ModuleId> mids)
1632 throws ConfigurationException, IOException
1633 {
1634 try (FileChannel fc = FileChannel.open(lockf.toPath(), WRITE)) {
1635 fc.lock();
1636 configureWhileModuleDirectoryLocked(mids);
1637 }
1638 }
1639
1640 private void configureWhileModuleDirectoryLocked(Collection<ModuleId> mids)
1641 throws ConfigurationException, IOException
1642 {
1643 // ## mids not used yet
1644 for (ModuleId mid : libraryRoots()) {
1645 // ## We could be a lot more clever about this!
1646 Configuration<Context> cf
1647 = Configurator.configure(this, mid.toQuery());
1648 File md = moduleDictionary.findDeclaringModuleDir(mid);
1649 new StoredConfiguration(md, cf).store();
1650 }
1651 }
1652
1653 private List<ModuleId> libraryRoots()
1654 throws IOException
1655 {
1656 List<ModuleId> roots = new ArrayList<>();
1657 for (ModuleId mid : listLocalDeclaringModuleIds()) {
1658 // each module can have multiple entry points, but
1659 // only one configuration for each module.
1660 ModuleInfo mi = readModuleInfo(mid);
1661 for (ModuleView mv : mi.views()) {
1662 if (mv.mainClass() != null) {
1663 roots.add(mid);
1664 break;
1665 }
1666 }
1667 }
1668 return roots;
1669 }
1670
1671 public URI findLocalResource(ModuleId mid, String name)
1672 throws IOException
1673 {
1674 return locateContent(mid, name);
1675 }
1676
1677 public File findLocalNativeLibrary(ModuleId mid, String name)
1678 throws IOException
1679 {
1680 File f = natlibs();
1681 if (f == null) {
1682 f = moduleDictionary.findDeclaringModuleDir(mid);
1683 if (f == null)
1684 return null;
1685 f = new File(f, "lib");
1686 }
1687 f = new File(f, name);
1688 if (!f.exists())
1689 return null;
1885 providingModuleIds.remove(view.id());
1886 Set<ModuleId> mids = moduleIdsForName.get(view.id().name());
1887 if (mids != null)
1888 mids.remove(view.id());
1889 for (ModuleId alias : view.aliases()) {
1890 providingModuleIds.remove(alias);
1891 mids = moduleIdsForName.get(alias.name());
1892 if (mids != null)
1893 mids.remove(view.id());
1894 }
1895 }
1896 File md = moduleDir(root, mi.id());
1897 delete(md);
1898 }
1899
1900 private void delete(File md) throws IOException {
1901 if (!md.exists())
1902 return;
1903
1904 checkModuleDir(md);
1905 // ## TODO:
1906 ModuleFile.Reader.remove(md);
1907 File parent = md.getParentFile();
1908 if (parent.list().length == 0)
1909 parent.delete();
1910 }
1911
1912 void refresh() throws IOException {
1913 providingModuleIds = new LinkedHashMap<>();
1914 moduleIdsForName = new LinkedHashMap<>();
1915 modules = new HashSet<>();
1916
1917 try (DirectoryStream<Path> ds = java.nio.file.Files.newDirectoryStream(root.toPath())) {
1918 for (Path mnp : ds) {
1919 String mn = mnp.toFile().getName();
1920 if (mn.startsWith(FileConstants.META_PREFIX)) {
1921 continue;
1922 }
1923
1924 try (DirectoryStream<Path> mds = java.nio.file.Files.newDirectoryStream(mnp)) {
1925 for (Path versionp : mds) {
|