--- old/src/share/bin/java.c Fri May 13 15:58:49 2011 +++ new/src/share/bin/java.c Fri May 13 15:58:48 2011 @@ -768,6 +768,22 @@ JLI_MemFree((char *) s); } +static void +SetModulePath(const char *s) +{ + char *def; + size_t len; + const char *orig = s; + static const char format[] = "-Djava.module.path=%s"; + len = sizeof(format) - 2 + JLI_StrLen(s); /* -2 == strlen("%s") */ + def = JLI_MemAlloc(len); + JLI_Snprintf(def, len, format, s); + AddOption(def, NULL); + if (s != orig) + JLI_MemFree((char *) s); +} + + /* * Set the bootclasspath for installed modules. * A temporary workaround until jigsaw legacy support is @@ -1101,6 +1117,12 @@ /* -classpath can only be set when running legacy mode */ mode = LM_CLASS; argv++; --argc; + } else if (JLI_StrCmp(arg, "-modulepath") == 0 || JLI_StrCmp(arg, "-mp") == 0) { + ARG_CHECK (argc, ARG_ERROR1, arg); + SetModulePath(*argv); + /* -modulepath can only be set when running in module mode */ + mode = LM_MODULE; + argv++; --argc; } else if (JLI_StrCmp(arg, "-jar") == 0) { ARG_CHECK (argc, ARG_ERROR2, arg); if (mode == LM_MODULE) --- old/src/share/classes/org/openjdk/jigsaw/ClassInfo.java Fri May 13 15:58:52 2011 +++ new/src/share/classes/org/openjdk/jigsaw/ClassInfo.java Fri May 13 15:58:51 2011 @@ -363,6 +363,13 @@ } return ci; } + + static ClassInfo parse(byte[] buf) throws IOException { + ClassInfo ci = new ClassInfo(); + ci.load(ByteBuffer.wrap(buf, 0, buf.length), /*path*/null); + return ci; + } + // ## Test // --- old/src/share/classes/org/openjdk/jigsaw/Launcher.java Fri May 13 15:58:54 2011 +++ new/src/share/classes/org/openjdk/jigsaw/Launcher.java Fri May 13 15:58:53 2011 @@ -27,11 +27,8 @@ import java.io.*; import java.lang.module.*; -import java.lang.reflect.*; -import static org.openjdk.jigsaw.Trace.*; - public final class Launcher { private static JigsawModuleSystem jms = JigsawModuleSystem.instance(); @@ -43,8 +40,13 @@ private static Loader loadModule(File libPath, ModuleIdQuery midq) throws IOException { - Library lb = SimpleLibrary.open(libPath, false); + + // interpose modulepath library if -modulepath set + String mp = System.getProperty("java.module.path"); + if (mp != null) + lb = ModulePathLibrary.open(mp, lb); + ModuleId mid = lb.findLatestModuleId(midq); if (mid == null) throw new Error(midq + ": No installed module" @@ -56,9 +58,22 @@ if (cn == null) throw new Error(mid + ": Module does not specify" + " a main class"); + Configuration cf = lb.readConfiguration(mid); - if (cf == null) - throw new Error(mid + ": Module not configured"); + if (cf == null) { + // module not configured so if running with -modulepath we compute + // the full configuration for the root module + if ((lb instanceof ModulePathLibrary)) { + try { + cf = Configurator.configure(lb, mi.id().toQuery()); + } catch (ConfigurationException ce) { + throw new Error(mid + ": Module cannot be configured", ce); + } + } else { + throw new Error(mid + ": Module not configured"); + } + } + Context cx = cf.getContextForModuleName(mid.name()); if (cx == null) throw new InternalError(mid + ": Cannot find context"); @@ -65,7 +80,7 @@ LoaderPool lp = new LoaderPool(lb, cf, cn); return lp.findLoader(cx); - + } public static ClassLoader launch(String midqs) { @@ -115,5 +130,5 @@ public static String mainClass(ClassLoader cl) { return ((Loader)cl).pool.mainClass(); } - + } --- /dev/null Fri May 13 15:58:56 2011 +++ new/src/share/classes/org/openjdk/jigsaw/ModulePathLibrary.java Fri May 13 15:58:55 2011 @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.jigsaw; + +import java.lang.module.*; +import java.util.*; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.io.*; +import java.security.CodeSigner; +import java.security.SignatureException; + +/** + * A simple read-only module library based on a module path as specified by the + * -modulepath (-mp) option. + */ + +public final class ModulePathLibrary + extends Library +{ + private static final JigsawModuleSystem jms = JigsawModuleSystem.instance(); + + private final Path root; + private final Library parent; + + // mid -> module-info bytes + private final Map modules; + + private ModulePathLibrary(String path, Library parent) throws IOException { + this.root = FileSystems.getDefault().getPath(path); + this.parent = parent; + this.modules = new HashMap<>(); + + // preload module info for each module + try (DirectoryStream stream = Files.newDirectoryStream(root)) { + for (Path name: stream) { + Path mipath = name.resolve("module-info.class"); + if (Files.exists(mipath)) { + byte[] bytes = Files.readAllBytes(mipath); + ClassInfo ci = ClassInfo.parse(bytes); + ModuleId mid = jms.parseModuleId(name.getFileName().toString(), + ci.moduleVersion()); + modules.put(mid, bytes); + } + } + } + } + + static ModulePathLibrary open(String path, Library parent) throws IOException { + return new ModulePathLibrary(path, parent); + } + + @Override + public String name() { + return root.toString(); + } + + @Override + public Library parent() { + return parent; + } + + @Override + public URI location() { + return root.toUri(); + } + + @Override + public int majorVersion() { + return 1; + } + + @Override + public int minorVersion() { + return 0; + } + + @Override + public byte[] readLocalModuleInfoBytes(ModuleId mid) { + return modules.get(mid); + } + + @Override + public void gatherLocalModuleIds(String moduleName, Set mids) { + if (moduleName == null) { + mids.addAll(modules.keySet()); + } else { + for (ModuleId mid: modules.keySet()) { + if (mid.name().equals(moduleName)) + mids.add(mid); + } + } + } + + @Override + public byte[] readLocalClass(ModuleId mid, String className) + throws IOException + { + String sep = root.getFileSystem().getSeparator(); + assert sep.length() == 1; + String fn = className.replace('.', sep.charAt(0)) + ".class"; + Path file = root.resolve(mid.name()).resolve(fn); + return Files.readAllBytes(file); + } + + @Override + public List listLocalClasses(ModuleId mid, final boolean all) + throws IOException + { + final Path top = root.resolve(mid.name()); + final List result = new LinkedList<>(); + Files.walkFileTree(top, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException + { + String fn = file.getFileName().toString(); + if (fn.endsWith(".class") && !fn.equals("module-info.class")) { + ClassInfo ci = ClassInfo.read(file.toFile()); + if (all || ci.isPublic()) { + // modules/foo/org/Foo.class => org.Foo + String cn = top.relativize(file).toString(); + String sep = root.getFileSystem().getSeparator(); + cn = cn.replace(sep.charAt(0), '.'); + int len = cn.length() - 6; + cn = cn.substring(0, len); + result.add(cn); + } + } + return FileVisitResult.CONTINUE; + } + }); + return result; + } + + @Override + public byte[] readModuleInfoBytes(ModuleId mid) + throws IOException + { + byte[] bytes = modules.get(mid); + return (bytes != null) ? bytes : parent.readModuleInfoBytes(mid); + } + + @Override + public Configuration readConfiguration(ModuleId mid) + throws IOException + { + // configuration not stored + return null; + } + + @Override + public void installFromManifests(Collection mfs) + throws ConfigurationException, IOException + { + throw new UnsupportedOperationException("Can't install into module path"); + } + + @Override + public void install(Collection mfs, boolean verifySignature) + throws ConfigurationException, IOException, SignatureException + { + throw new UnsupportedOperationException("Can't install into module path"); + } + + @Override + public Resolution resolve(Collection midqs) + throws ConfigurationException, IOException + { + // only required when installing + throw new RuntimeException("not implemented"); + } + + @Override + public void install(Resolution res, boolean verifySignature) + throws ConfigurationException, IOException, SignatureException + { + throw new UnsupportedOperationException("Can't install into module path"); + } + + @Override + public URI findLocalResource(ModuleId mid, String rn) + throws IOException + { + // resources be in a module path? + return null; + } + + @Override + public File findLocalNativeLibrary(ModuleId mid, String name) + throws IOException + { + // no native libraries in a module path + return null; + } + + @Override + public File classPath(ModuleId mid) + throws IOException + { + Path dir = root.resolve(mid.name()); + return dir.toFile(); + } + + private static class EmptyRepositoryList implements RemoteRepositoryList { + @Override + public List repositories() throws IOException { + return Collections.emptyList(); + } + @Override + public RemoteRepository firstRepository() throws IOException { + return null; + } + public RemoteRepository add(URI uri, int position) throws IOException { + throw new RuntimeException(); + } + public boolean remove(RemoteRepository rr) throws IOException { + throw new RuntimeException(); + } + public boolean areCatalogsStale() throws IOException { + throw new RuntimeException(); + } + public boolean updateCatalogs(boolean force) throws IOException { + throw new RuntimeException(); + } + } + + @Override + public RemoteRepositoryList repositoryList() throws IOException { + return new EmptyRepositoryList(); + } + + @Override + public CodeSigner[] readLocalCodeSigners(ModuleId mid) + throws IOException + { + // classes in a module path are not signed + return null; + } +}