9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.internal.module;
27
28 import java.io.File;
29 import java.io.PrintStream;
30 import java.lang.module.Configuration;
31 import java.lang.module.ModuleDescriptor;
32 import java.lang.module.ModuleFinder;
33 import java.lang.module.ModuleReference;
34 import java.lang.module.ResolvedModule;
35 import java.lang.reflect.Layer;
36 import java.lang.reflect.Module;
37 import java.net.URI;
38 import java.nio.file.Path;
39 import java.nio.file.Paths;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Optional;
47 import java.util.Set;
48 import java.util.function.Function;
49
50 import jdk.internal.loader.BootLoader;
51 import jdk.internal.loader.BuiltinClassLoader;
52 import jdk.internal.misc.SharedSecrets;
53 import jdk.internal.perf.PerfCounter;
54
55 /**
56 * Initializes/boots the module system.
57 *
58 * The {@link #boot() boot} method is called early in the startup to initialize
59 * the module system. In summary, the boot method creates a Configuration by
60 * resolving a set of module names specified via the launcher (or equivalent)
61 * -m and --add-modules options. The modules are located on a module path that
62 * is constructed from the upgrade module path, system modules, and application
63 * module path. The Configuration is instantiated as the boot Layer with each
64 * module in the the configuration defined to one of the built-in class loaders.
65 */
66
67 public final class ModuleBootstrap {
68 private ModuleBootstrap() { }
97 }
98
99 /**
100 * Returns the ModuleFinder for the initial configuration
101 */
102 public static ModuleFinder finder() {
103 assert initialFinder != null;
104 return initialFinder;
105 }
106
107 /**
108 * Initialize the module system, returning the boot Layer.
109 *
110 * @see java.lang.System#initPhase2()
111 */
112 public static Layer boot() {
113
114 long t0 = System.nanoTime();
115
116 // system modules (may be patched)
117 ModuleFinder systemModules = ModuleFinder.ofSystem();
118
119 PerfCounters.systemModulesTime.addElapsedTimeFrom(t0);
120
121
122 long t1 = System.nanoTime();
123
124 // Once we have the system modules then we define the base module to
125 // the VM. We do this here so that java.base is defined as early as
126 // possible and also that resources in the base module can be located
127 // for error messages that may happen from here on.
128 ModuleReference base = systemModules.find(JAVA_BASE).orElse(null);
129 if (base == null)
130 throw new InternalError(JAVA_BASE + " not found");
131 URI baseUri = base.location().orElse(null);
132 if (baseUri == null)
133 throw new InternalError(JAVA_BASE + " does not have a location");
134 BootLoader.loadModule(base);
135 Modules.defineModule(null, base.descriptor(), baseUri);
136
137 PerfCounters.defineBaseTime.addElapsedTimeFrom(t1);
258 PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t2);
259
260
261 long t3 = System.nanoTime();
262
263 // determine if post resolution checks are needed
264 boolean needPostResolutionChecks = true;
265 if (baseUri.getScheme().equals("jrt") // toLowerCase not needed here
266 && (upgradeModulePath == null)
267 && (appModulePath == null)
268 && (patcher.isEmpty())) {
269 needPostResolutionChecks = false;
270 }
271
272 PrintStream traceOutput = null;
273 if (Boolean.getBoolean("jdk.launcher.traceResolver"))
274 traceOutput = System.out;
275
276 // run the resolver to create the configuration
277 Configuration cf = SharedSecrets.getJavaLangModuleAccess()
278 .resolveRequiresAndUses(finder,
279 roots,
280 needPostResolutionChecks,
281 traceOutput);
282
283 // time to create configuration
284 PerfCounters.resolveTime.addElapsedTimeFrom(t3);
285
286 // check module names and incubating status
287 checkModuleNamesAndStatus(cf);
288
289 // mapping of modules to class loaders
290 Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
291
292 // check that all modules to be mapped to the boot loader will be
293 // loaded from the runtime image
294 if (needPostResolutionChecks) {
295 for (ResolvedModule resolvedModule : cf.modules()) {
296 ModuleReference mref = resolvedModule.reference();
297 String name = mref.descriptor().name();
298 ClassLoader cl = clf.apply(name);
363 addExtraExportsAndOpens(bootLayer);
364
365 // total time to initialize
366 PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
367
368 // remember the ModuleFinder
369 initialFinder = finder;
370
371 return bootLayer;
372 }
373
374 /**
375 * Returns a ModuleFinder that limits observability to the given root
376 * modules, their transitive dependences, plus a set of other modules.
377 */
378 private static ModuleFinder limitFinder(ModuleFinder finder,
379 Set<String> roots,
380 Set<String> otherMods)
381 {
382 // resolve all root modules
383 Configuration cf = Configuration.empty()
384 .resolveRequires(finder,
385 ModuleFinder.of(),
386 roots);
387
388 // module name -> reference
389 Map<String, ModuleReference> map = new HashMap<>();
390
391 // root modules and their transitive dependences
392 cf.modules().stream()
393 .map(ResolvedModule::reference)
394 .forEach(mref -> map.put(mref.descriptor().name(), mref));
395
396 // additional modules
397 otherMods.stream()
398 .map(finder::find)
399 .flatMap(Optional::stream)
400 .forEach(mref -> map.putIfAbsent(mref.descriptor().name(), mref));
401
402 // set of modules that are observable
403 Set<ModuleReference> mrefs = new HashSet<>(map.values());
404
511
512 /**
513 * Process the --add-exports and --add-opens options to export/open
514 * additional packages specified on the command-line.
515 */
516 private static void addExtraExportsAndOpens(Layer bootLayer) {
517
518 // --add-exports
519 String prefix = "jdk.module.addexports.";
520 Map<String, List<String>> extraExports = decode(prefix);
521 if (!extraExports.isEmpty()) {
522 addExtraExportsOrOpens(bootLayer, extraExports, false);
523 }
524
525 // --add-opens
526 prefix = "jdk.module.addopens.";
527 Map<String, List<String>> extraOpens = decode(prefix);
528 if (!extraOpens.isEmpty()) {
529 addExtraExportsOrOpens(bootLayer, extraOpens, true);
530 }
531 }
532
533 private static void addExtraExportsOrOpens(Layer bootLayer,
534 Map<String, List<String>> map,
535 boolean opens)
536 {
537 String option = opens ? ADD_OPENS : ADD_EXPORTS;
538 for (Map.Entry<String, List<String>> e : map.entrySet()) {
539
540 // the key is $MODULE/$PACKAGE
541 String key = e.getKey();
542 String[] s = key.split("/");
543 if (s.length != 2)
544 fail(unableToParse(option, "<module>/<package>", key));
545
546 String mn = s[0];
547 String pn = s[1];
548 if (mn.isEmpty() || pn.isEmpty())
549 fail(unableToParse(option, "<module>/<package>", key));
550
551 // The exporting module is in the boot layer
552 Module m;
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.internal.module;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.io.PrintStream;
31 import java.io.UncheckedIOException;
32 import java.lang.module.Configuration;
33 import java.lang.module.ModuleDescriptor;
34 import java.lang.module.ModuleFinder;
35 import java.lang.module.ModuleReference;
36 import java.lang.module.ResolvedModule;
37 import java.lang.reflect.Layer;
38 import java.lang.reflect.Module;
39 import java.net.URI;
40 import java.nio.file.Files;
41 import java.nio.file.Path;
42 import java.nio.file.Paths;
43 import java.util.ArrayList;
44 import java.util.Collections;
45 import java.util.HashMap;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Optional;
50 import java.util.Set;
51 import java.util.function.Function;
52 import java.util.stream.Stream;
53
54 import jdk.internal.loader.BootLoader;
55 import jdk.internal.loader.BuiltinClassLoader;
56 import jdk.internal.misc.SharedSecrets;
57 import jdk.internal.perf.PerfCounter;
58
59 /**
60 * Initializes/boots the module system.
61 *
62 * The {@link #boot() boot} method is called early in the startup to initialize
63 * the module system. In summary, the boot method creates a Configuration by
64 * resolving a set of module names specified via the launcher (or equivalent)
65 * -m and --add-modules options. The modules are located on a module path that
66 * is constructed from the upgrade module path, system modules, and application
67 * module path. The Configuration is instantiated as the boot Layer with each
68 * module in the the configuration defined to one of the built-in class loaders.
69 */
70
71 public final class ModuleBootstrap {
72 private ModuleBootstrap() { }
101 }
102
103 /**
104 * Returns the ModuleFinder for the initial configuration
105 */
106 public static ModuleFinder finder() {
107 assert initialFinder != null;
108 return initialFinder;
109 }
110
111 /**
112 * Initialize the module system, returning the boot Layer.
113 *
114 * @see java.lang.System#initPhase2()
115 */
116 public static Layer boot() {
117
118 long t0 = System.nanoTime();
119
120 // system modules (may be patched)
121 ModuleFinder systemModules;
122 if (SystemModules.MODULE_NAMES.length > 0) {
123 systemModules = SystemModuleFinder.getInstance();
124 } else {
125 systemModules = ModuleFinder.ofSystem();
126 }
127
128 PerfCounters.systemModulesTime.addElapsedTimeFrom(t0);
129
130
131 long t1 = System.nanoTime();
132
133 // Once we have the system modules then we define the base module to
134 // the VM. We do this here so that java.base is defined as early as
135 // possible and also that resources in the base module can be located
136 // for error messages that may happen from here on.
137 ModuleReference base = systemModules.find(JAVA_BASE).orElse(null);
138 if (base == null)
139 throw new InternalError(JAVA_BASE + " not found");
140 URI baseUri = base.location().orElse(null);
141 if (baseUri == null)
142 throw new InternalError(JAVA_BASE + " does not have a location");
143 BootLoader.loadModule(base);
144 Modules.defineModule(null, base.descriptor(), baseUri);
145
146 PerfCounters.defineBaseTime.addElapsedTimeFrom(t1);
267 PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t2);
268
269
270 long t3 = System.nanoTime();
271
272 // determine if post resolution checks are needed
273 boolean needPostResolutionChecks = true;
274 if (baseUri.getScheme().equals("jrt") // toLowerCase not needed here
275 && (upgradeModulePath == null)
276 && (appModulePath == null)
277 && (patcher.isEmpty())) {
278 needPostResolutionChecks = false;
279 }
280
281 PrintStream traceOutput = null;
282 if (Boolean.getBoolean("jdk.launcher.traceResolver"))
283 traceOutput = System.out;
284
285 // run the resolver to create the configuration
286 Configuration cf = SharedSecrets.getJavaLangModuleAccess()
287 .resolveAndBind(finder,
288 roots,
289 needPostResolutionChecks,
290 traceOutput);
291
292 // time to create configuration
293 PerfCounters.resolveTime.addElapsedTimeFrom(t3);
294
295 // check module names and incubating status
296 checkModuleNamesAndStatus(cf);
297
298 // mapping of modules to class loaders
299 Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
300
301 // check that all modules to be mapped to the boot loader will be
302 // loaded from the runtime image
303 if (needPostResolutionChecks) {
304 for (ResolvedModule resolvedModule : cf.modules()) {
305 ModuleReference mref = resolvedModule.reference();
306 String name = mref.descriptor().name();
307 ClassLoader cl = clf.apply(name);
372 addExtraExportsAndOpens(bootLayer);
373
374 // total time to initialize
375 PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
376
377 // remember the ModuleFinder
378 initialFinder = finder;
379
380 return bootLayer;
381 }
382
383 /**
384 * Returns a ModuleFinder that limits observability to the given root
385 * modules, their transitive dependences, plus a set of other modules.
386 */
387 private static ModuleFinder limitFinder(ModuleFinder finder,
388 Set<String> roots,
389 Set<String> otherMods)
390 {
391 // resolve all root modules
392 Configuration cf = Configuration.empty().resolve(finder,
393 ModuleFinder.of(),
394 roots);
395
396 // module name -> reference
397 Map<String, ModuleReference> map = new HashMap<>();
398
399 // root modules and their transitive dependences
400 cf.modules().stream()
401 .map(ResolvedModule::reference)
402 .forEach(mref -> map.put(mref.descriptor().name(), mref));
403
404 // additional modules
405 otherMods.stream()
406 .map(finder::find)
407 .flatMap(Optional::stream)
408 .forEach(mref -> map.putIfAbsent(mref.descriptor().name(), mref));
409
410 // set of modules that are observable
411 Set<ModuleReference> mrefs = new HashSet<>(map.values());
412
519
520 /**
521 * Process the --add-exports and --add-opens options to export/open
522 * additional packages specified on the command-line.
523 */
524 private static void addExtraExportsAndOpens(Layer bootLayer) {
525
526 // --add-exports
527 String prefix = "jdk.module.addexports.";
528 Map<String, List<String>> extraExports = decode(prefix);
529 if (!extraExports.isEmpty()) {
530 addExtraExportsOrOpens(bootLayer, extraExports, false);
531 }
532
533 // --add-opens
534 prefix = "jdk.module.addopens.";
535 Map<String, List<String>> extraOpens = decode(prefix);
536 if (!extraOpens.isEmpty()) {
537 addExtraExportsOrOpens(bootLayer, extraOpens, true);
538 }
539
540 // DEBUG_ADD_OPENS is for debugging purposes only
541 String home = System.getProperty("java.home");
542 Path file = Paths.get(home, "conf", "DEBUG_ADD_OPENS");
543 if (Files.exists(file)) {
544 warn(file + " detected; may break encapsulation");
545 try (Stream<String> lines = Files.lines(file)) {
546 lines.map(line -> line.trim())
547 .filter(line -> (!line.isEmpty() && !line.startsWith("#")))
548 .forEach(line -> {
549 String[] s = line.split("/");
550 if (s.length != 2) {
551 fail("Unable to parse as <module>/<package>: " + line);
552 } else {
553 String mn = s[0];
554 String pkg = s[1];
555 openPackage(bootLayer, mn, pkg);
556 }
557 });
558 } catch (IOException ioe) {
559 throw new UncheckedIOException(ioe);
560 }
561 }
562 }
563
564 private static void openPackage(Layer bootLayer, String mn, String pkg) {
565 if (mn.equals("ALL-RESOLVED") && pkg.equals("ALL-PACKAGES")) {
566 bootLayer.modules().stream().forEach(m ->
567 m.getDescriptor().packages().forEach(pn -> openPackage(m, pn)));
568 } else {
569 bootLayer.findModule(mn)
570 .filter(m -> m.getDescriptor().packages().contains(pkg))
571 .ifPresent(m -> openPackage(m, pkg));
572 }
573 }
574
575 private static void openPackage(Module m, String pn) {
576 Modules.addOpensToAllUnnamed(m, pn);
577 warn("Opened for deep reflection: " + m.getName() + "/" + pn);
578 }
579
580
581 private static void addExtraExportsOrOpens(Layer bootLayer,
582 Map<String, List<String>> map,
583 boolean opens)
584 {
585 String option = opens ? ADD_OPENS : ADD_EXPORTS;
586 for (Map.Entry<String, List<String>> e : map.entrySet()) {
587
588 // the key is $MODULE/$PACKAGE
589 String key = e.getKey();
590 String[] s = key.split("/");
591 if (s.length != 2)
592 fail(unableToParse(option, "<module>/<package>", key));
593
594 String mn = s[0];
595 String pn = s[1];
596 if (mn.isEmpty() || pn.isEmpty())
597 fail(unableToParse(option, "<module>/<package>", key));
598
599 // The exporting module is in the boot layer
600 Module m;
|