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

Print this page

        

*** 235,244 **** --- 235,245 ---- private final File configs; private final SimpleLibrary parent; private final Header hd; private final ModuleDictionary moduleDictionary; private final File lockf; + private final File trash; public String name() { return root.toString(); } public File root() { return canonicalRoot; } public int majorVersion() { return hd.majorVersion; } public int minorVersion() { return hd.minorVersion; }
*** 297,306 **** --- 298,308 ---- new File(canonicalRoot, hd.natcmds().toString()).getCanonicalFile(); configs = hd.configs() == null ? null : new File(canonicalRoot, hd.configs().toString()).getCanonicalFile(); lockf = new File(root, FileConstants.META_PREFIX + "lock"); + trash = new File(root, TRASH); moduleDictionary = new ModuleDictionary(root); } // Creates a new library private SimpleLibrary(File path, File parentPath, File natlibs, File natcmds,
*** 328,337 **** --- 330,341 ---- relativize(this.natcmds), relativize(this.configs), opts); hd.store(); lockf = new File(root, FileConstants.META_PREFIX + "lock"); lockf.createNewFile(); + trash = new File(root, TRASH); + Files.mkdirs(trash, "module library trash"); moduleDictionary = new ModuleDictionary(canonicalRoot); moduleDictionary.store(); } public static SimpleLibrary create(File path, File parent, File natlibs,
*** 1470,1479 **** --- 1474,1608 ---- throws ConfigurationException, IOException, SignatureException { install(res, verifySignature, false); } + @Override + public void removeForcibly(List<ModuleId> mids) + throws IOException + { + try { + remove(mids, true, false); + } catch (ConfigurationException x) { + throw new Error("should not be thrown when forcibly removing", x); + } + } + + @Override + public void remove(List<ModuleId> mids, boolean dry) + throws ConfigurationException, IOException + { + remove(mids, false, dry); + } + + private void remove(List<ModuleId> mids, boolean force, boolean dry) + throws ConfigurationException, IOException + { + IOException ioe = null; + FileChannel fc = FileChannel.open(lockf.toPath(), WRITE); + try { + fc.lock(); + for (ModuleId mid : mids) { + if (moduleDictionary.findDeclaringModuleDir(mid) == null) + throw new IllegalArgumentException(mid + ": No such module"); + } + if (!force) + checkRootsRequire(mids); + if (dry) + return; + + // The library may be altered after this point, so the modules + // dictionary needs to be refreshed + List<IOException> excs = removeWhileLocked(mids); + try { + moduleDictionary.refresh(); + moduleDictionary.store(); + } catch (IOException x) { + excs.add(x); + } + if (!excs.isEmpty()) { + ioe = excs.remove(0); + for (IOException x : excs) + ioe.addSuppressed(x); + } + } catch (IOException x) { + ioe = x; + } finally { + fc.close(); + if (ioe != null) + throw ioe; + } + } + + private void checkRootsRequire(List<ModuleId> mids) + throws ConfigurationException, IOException + { + // ## We do not know if a root module in a child library depends on one + // ## of the 'to be removed' modules. We would break it's configuration. + + // check each root configuration for reference to a module in mids + for (ModuleId rootid : libraryRoots()) { + // skip any root modules being removed + if (mids.contains(rootid)) + continue; + + Configuration<Context> cf = readConfiguration(rootid); + for (Context cx : cf.contexts()) { + for (ModuleId mid : cx.modules()) { + if (mids.contains(mid)) + throw new ConfigurationException(mid + + ": being used by " + rootid); + } + } + } + } + + private static final String TRASH = ".trash"; + // file name generation, same as java.io.File for now + // lazy initialization of SecureRandom + private static class LazyInitialization { + static final SecureRandom random = new SecureRandom(); + } + private static File moduleTrashDir(File trash, ModuleId mid) + throws IOException + { + File mtd = null; + for (;;) { + long n = LazyInitialization.random.nextLong(); + n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n); + Version version = mid.version(); + String v = (version != null) ? version.toString() : "default"; + String modTrashName = mid.name() + '_' + v + '_' + Long.toString(n); + mtd = new File(trash, modTrashName); + if (!mtd.exists()) + break; + } + Files.mkdirs(mtd, mtd.toString()); + return mtd; + } + + private List<IOException> removeWhileLocked(List<ModuleId> mids) { + List<IOException> excs = new ArrayList<>(); + // First move the modules to the .trash dir + for (ModuleId mid : mids) { + try { + File mtd = moduleTrashDir(trash, mid); + File md = moduleDir(root, mid); + java.nio.file.Files.move(md.toPath(), mtd.toPath(), ATOMIC_MOVE); + File p = md.getParentFile(); + if (p.list().length == 0) + java.nio.file.Files.delete(p.toPath()); + } catch (IOException x) { + excs.add(x); + } + } + for (String tm : trash.list()) + excs.addAll(ModuleFile.Reader.remove(new File(trash, tm))); + + return excs; + } + /** * <p> Pre-install one or more modules to an arbitrary destination * directory. </p> * * <p> A pre-installed module has the same format as within the library
*** 1540,1570 **** private void configureWhileModuleDirectoryLocked(Collection<ModuleId> mids) throws ConfigurationException, IOException { // ## mids not used yet List<ModuleId> roots = new ArrayList<>(); for (ModuleId mid : listLocalDeclaringModuleIds()) { ! // each module can have multiple entry points ! // only configure once for each module. ModuleInfo mi = readModuleInfo(mid); for (ModuleView mv : mi.views()) { if (mv.mainClass() != null) { roots.add(mid); break; } } } ! ! for (ModuleId mid : roots) { ! // ## We could be a lot more clever about this! ! Configuration<Context> cf ! = Configurator.configure(this, mid.toQuery()); ! File md = moduleDictionary.findDeclaringModuleDir(mid); ! new StoredConfiguration(md, cf).store(); } - } public URI findLocalResource(ModuleId mid, String name) throws IOException { return locateContent(mid, name); --- 1669,1704 ---- private void configureWhileModuleDirectoryLocked(Collection<ModuleId> mids) throws ConfigurationException, IOException { // ## mids not used yet + for (ModuleId mid : libraryRoots()) { + // ## We could be a lot more clever about this! + Configuration<Context> cf + = Configurator.configure(this, mid.toQuery()); + File md = moduleDictionary.findDeclaringModuleDir(mid); + new StoredConfiguration(md, cf).store(); + } + } + + private List<ModuleId> libraryRoots() + throws IOException + { List<ModuleId> roots = new ArrayList<>(); for (ModuleId mid : listLocalDeclaringModuleIds()) { ! // each module can have multiple entry points, but ! // only one configuration for each module. ModuleInfo mi = readModuleInfo(mid); for (ModuleView mv : mi.views()) { if (mv.mainClass() != null) { roots.add(mid); break; } } } ! return roots; } public URI findLocalResource(ModuleId mid, String name) throws IOException { return locateContent(mid, name);
*** 1796,1805 **** --- 1930,1940 ---- private void delete(File md) throws IOException { if (!md.exists()) return; checkModuleDir(md); + // ## TODO: ModuleFile.Reader.remove(md); File parent = md.getParentFile(); if (parent.list().length == 0) parent.delete(); }
*** 1810,1820 **** modules = new HashSet<>(); try (DirectoryStream<Path> ds = java.nio.file.Files.newDirectoryStream(root.toPath())) { for (Path mnp : ds) { String mn = mnp.toFile().getName(); ! if (mn.startsWith(FileConstants.META_PREFIX)) { continue; } try (DirectoryStream<Path> mds = java.nio.file.Files.newDirectoryStream(mnp)) { for (Path versionp : mds) { --- 1945,1956 ---- modules = new HashSet<>(); try (DirectoryStream<Path> ds = java.nio.file.Files.newDirectoryStream(root.toPath())) { for (Path mnp : ds) { String mn = mnp.toFile().getName(); ! if (mn.startsWith(FileConstants.META_PREFIX) || ! TRASH.equals(mn)) { continue; } try (DirectoryStream<Path> mds = java.nio.file.Files.newDirectoryStream(mnp)) { for (Path versionp : mds) {