8189777: jlink --module-path default value and automatic addition of $JAVA_HOME/jmods if java.base is missing
authorsundar
Fri, 27 Oct 2017 08:21:53 +0530
changeset 47464 36de9c637393
parent 47463 30186b6741b8
child 47465 bc25e62f4794
8189777: jlink --module-path default value and automatic addition of $JAVA_HOME/jmods if java.base is missing Reviewed-by: alanb, mchung
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java
test/jdk/tools/jlink/IntegrationTest.java
test/jdk/tools/jlink/JLinkTest.java
test/jdk/tools/lib/tests/Helper.java
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java	Thu Oct 26 18:04:29 2017 -0700
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java	Fri Oct 27 08:21:53 2017 +0530
@@ -27,7 +27,9 @@
 import java.lang.module.Configuration;
 import java.lang.module.ModuleFinder;
 import java.nio.ByteOrder;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -146,10 +148,8 @@
      */
     public static final class JlinkConfiguration {
 
-        private final List<Path> modulepaths;
         private final Path output;
         private final Set<String> modules;
-        private final Set<String> limitmods;
         private final ByteOrder endian;
         private final ModuleFinder finder;
 
@@ -157,33 +157,18 @@
          * jlink configuration,
          *
          * @param output Output directory, must not exist.
-         * @param modulepaths Modules paths
          * @param modules The possibly-empty set of root modules to resolve
-         * @param limitmods Limit the universe of observable modules
          * @param endian Jimage byte order. Native order by default
+         * @param finder the ModuleFinder for this configuration
          */
         public JlinkConfiguration(Path output,
-                                  List<Path> modulepaths,
                                   Set<String> modules,
-                                  Set<String> limitmods,
-                                  ByteOrder endian) {
-            if (Objects.requireNonNull(modulepaths).isEmpty()) {
-                throw new IllegalArgumentException("Empty module path");
-            }
-
+                                  ByteOrder endian,
+                                  ModuleFinder finder) {
             this.output = output;
-            this.modulepaths = modulepaths;
             this.modules = Objects.requireNonNull(modules);
-            this.limitmods = Objects.requireNonNull(limitmods);
             this.endian = Objects.requireNonNull(endian);
-            this.finder = moduleFinder();
-        }
-
-        /**
-         * @return the modulepaths
-         */
-        public List<Path> getModulepaths() {
-            return modulepaths;
+            this.finder = finder;
         }
 
         /**
@@ -208,13 +193,6 @@
         }
 
         /**
-         * @return the limitmods
-         */
-        public Set<String> getLimitmods() {
-            return limitmods;
-        }
-
-        /**
          * Returns {@link ModuleFinder} that finds all observable modules
          * for this jlink configuration.
          */
@@ -244,37 +222,16 @@
                                                  modules);
         }
 
-        private ModuleFinder moduleFinder() {
-            Path[] entries = modulepaths.toArray(new Path[0]);
-            ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
-            if (!limitmods.isEmpty()) {
-                finder = JlinkTask.limitFinder(finder, limitmods, modules);
-            }
-            return finder;
-        }
-
         @Override
         public String toString() {
             StringBuilder builder = new StringBuilder();
 
             builder.append("output=").append(output).append("\n");
-            StringBuilder pathsBuilder = new StringBuilder();
-            for (Path p : modulepaths) {
-                pathsBuilder.append(p).append(",");
-            }
-            builder.append("modulepaths=").append(pathsBuilder).append("\n");
-
             StringBuilder modsBuilder = new StringBuilder();
             for (String p : modules) {
                 modsBuilder.append(p).append(",");
             }
             builder.append("modules=").append(modsBuilder).append("\n");
-
-            StringBuilder limitsBuilder = new StringBuilder();
-            for (String p : limitmods) {
-                limitsBuilder.append(p).append(",");
-            }
-            builder.append("limitmodules=").append(limitsBuilder).append("\n");
             builder.append("endian=").append(endian).append("\n");
             return builder.toString();
         }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Thu Oct 26 18:04:29 2017 -0700
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Fri Oct 27 08:21:53 2017 +0530
@@ -251,9 +251,18 @@
                 return EXIT_OK;
             }
 
+
             if (options.modulePath.isEmpty()) {
-                throw taskHelper.newBadArgs("err.modulepath.must.be.specified")
-                                .showUsage(true);
+                // no --module-path specified - try to set $JAVA_HOME/jmods if that exists
+                Path jmods = getDefaultModulePath();
+                if (jmods != null) {
+                    options.modulePath.add(jmods);
+                }
+
+                if (options.modulePath.isEmpty()) {
+                     throw taskHelper.newBadArgs("err.modulepath.must.be.specified")
+                                 .showUsage(true);
+                }
             }
 
             JlinkConfiguration config = initJlinkConfig();
@@ -347,14 +356,7 @@
         Set<String> roots = new HashSet<>();
         for (String mod : options.addMods) {
             if (mod.equals(ALL_MODULE_PATH)) {
-                Path[] entries = options.modulePath.toArray(new Path[0]);
-                ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
-                if (!options.limitMods.isEmpty()) {
-                    // finder for the observable modules specified in
-                    // the --module-path and --limit-modules options
-                    finder = limitFinder(finder, options.limitMods, Collections.emptySet());
-                }
-
+                ModuleFinder finder = newModuleFinder(options.modulePath, options.limitMods, Set.of());
                 // all observable modules are roots
                 finder.findAll()
                       .stream()
@@ -366,11 +368,19 @@
             }
         }
 
+        ModuleFinder finder = newModuleFinder(options.modulePath, options.limitMods, roots);
+        if (!finder.find("java.base").isPresent()) {
+            Path defModPath = getDefaultModulePath();
+            if (defModPath != null) {
+                options.modulePath.add(defModPath);
+            }
+            finder = newModuleFinder(options.modulePath, options.limitMods, roots);
+        }
+
         return new JlinkConfiguration(options.output,
-                                      options.modulePath,
                                       roots,
-                                      options.limitMods,
-                                      options.endian);
+                                      options.endian,
+                                      finder);
     }
 
     private void createImage(JlinkConfiguration config) throws Exception {
@@ -398,6 +408,14 @@
         stack.operate(imageProvider);
     }
 
+    /**
+     * @return the system module path or null
+     */
+    public static Path getDefaultModulePath() {
+        Path jmods = Paths.get(System.getProperty("java.home"), "jmods");
+        return Files.isDirectory(jmods)? jmods : null;
+    }
+
     /*
      * Returns a module finder of the given module path that limits
      * the observable modules to those in the transitive closure of
@@ -408,12 +426,15 @@
                                                Set<String> limitMods,
                                                Set<String> roots)
     {
+        if (Objects.requireNonNull(paths).isEmpty()) {
+             throw new IllegalArgumentException("Empty module path");
+        }
         Path[] entries = paths.toArray(new Path[0]);
         ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
 
         // if limitmods is specified then limit the universe
-        if (!limitMods.isEmpty()) {
-            finder = limitFinder(finder, limitMods, roots);
+        if (limitMods != null && !limitMods.isEmpty()) {
+            finder = limitFinder(finder, limitMods, Objects.requireNonNull(roots));
         }
         return finder;
     }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Thu Oct 26 18:04:29 2017 -0700
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Fri Oct 27 08:21:53 2017 +0530
@@ -96,10 +96,10 @@
         // jlink main arguments
         Jlink.JlinkConfiguration jlinkConfig =
             new Jlink.JlinkConfiguration(new File("").toPath(), // Unused
-                                         modulePath,
                                          addModules,
-                                         limitModules,
-                                         ByteOrder.nativeOrder());
+                                         ByteOrder.nativeOrder(),
+                                         moduleFinder(modulePath,
+                                             limitModules, addModules));
 
         // plugin configuration
         List<Plugin> plugins = new ArrayList<Plugin>();
--- a/test/jdk/tools/jlink/IntegrationTest.java	Thu Oct 26 18:04:29 2017 -0700
+++ b/test/jdk/tools/jlink/IntegrationTest.java	Fri Oct 27 08:21:53 2017 +0530
@@ -39,6 +39,7 @@
 import java.util.Set;
 import java.util.function.Function;
 import jdk.tools.jlink.internal.Jlink;
+import jdk.tools.jlink.internal.JlinkTask;
 import jdk.tools.jlink.builder.DefaultImageBuilder;
 import jdk.tools.jlink.plugin.ResourcePool;
 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
@@ -159,7 +160,8 @@
         Set<String> limits = new HashSet<>();
         limits.add("java.management");
         JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
-                modulePaths, mods, limits, ByteOrder.nativeOrder());
+                mods, ByteOrder.nativeOrder(),
+                JlinkTask.newModuleFinder(modulePaths, limits, mods));
 
         List<Plugin> lst = new ArrayList<>();
 
--- a/test/jdk/tools/jlink/JLinkTest.java	Thu Oct 26 18:04:29 2017 -0700
+++ b/test/jdk/tools/jlink/JLinkTest.java	Fri Oct 27 08:21:53 2017 +0530
@@ -42,6 +42,7 @@
 /*
  * @test
  * @summary Test image creation
+ * @bug 8189777
  * @author Jean-Francois Denise
  * @library ../lib
  * @modules java.base/jdk.internal.jimage
@@ -106,6 +107,37 @@
         }
 
         {
+            // No --module-path specified. $JAVA_HOME/jmods should be assumed.
+            // The following should succeed as it uses only system modules.
+            String imageDir = "bug818977-no-modulepath";
+            JImageGenerator.getJLinkTask()
+                    .output(helper.createNewImageDir(imageDir))
+                    .addMods("jdk.scripting.nashorn")
+                    .call().assertSuccess();
+        }
+
+        {
+            // invalid --module-path specified. java.base not found it it.
+            // $JAVA_HOME/jmods should be added automatically.
+            // The following should succeed as it uses only system modules.
+            String imageDir = "bug8189777-invalid-modulepath";
+            JImageGenerator.getJLinkTask()
+                    .modulePath("does_not_exist_path")
+                    .output(helper.createNewImageDir(imageDir))
+                    .addMods("jdk.scripting.nashorn")
+                    .call().assertSuccess();
+        }
+
+        {
+            // No --module-path specified. --add-modules ALL-MODULE-PATH specified.
+            String imageDir = "bug8189777-all-module-path";
+            JImageGenerator.getJLinkTask()
+                    .output(helper.createNewImageDir(imageDir))
+                    .addMods("ALL-MODULE-PATH")
+                    .call().assertSuccess();
+        }
+
+        {
             String moduleName = "bug8134651";
             JImageGenerator.getJLinkTask()
                     .modulePath(helper.defaultModulePath())
@@ -122,6 +154,17 @@
                     .output(helper.createNewImageDir(moduleName))
                     .addMods("leaf1")
                     .call().assertFailure("Error: no value given for --module-path");
+            // do not include standard module path - should be added automatically
+            JImageGenerator.getJLinkTask()
+                    .modulePath(helper.defaultModulePath(false))
+                    .output(helper.createNewImageDir(moduleName))
+                    .addMods("leaf1")
+                    .call().assertSuccess();
+            // no --module-path. default sys mod path is assumed - but that won't contain 'leaf1' module
+            JImageGenerator.getJLinkTask()
+                    .output(helper.createNewImageDir(moduleName))
+                    .addMods("leaf1")
+                    .call().assertFailure("Error: Module leaf1 not found");
         }
 
         {
--- a/test/jdk/tools/lib/tests/Helper.java	Thu Oct 26 18:04:29 2017 -0700
+++ b/test/jdk/tools/lib/tests/Helper.java	Fri Oct 27 08:21:53 2017 +0530
@@ -136,7 +136,11 @@
     }
 
     public String defaultModulePath() {
-        return stdjmods.toAbsolutePath().toString() + File.pathSeparator
+        return defaultModulePath(true);
+    }
+
+    public String defaultModulePath(boolean includeStdMods) {
+        return (includeStdMods? stdjmods.toAbsolutePath().toString() : "") + File.pathSeparator
                 + jmods.toAbsolutePath().toString() + File.pathSeparator
                 + jars.toAbsolutePath().toString() + File.pathSeparator
                 + explodedmodsclasses.toAbsolutePath().toString();