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.net.URI;
36 import java.nio.file.Path;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.LinkedHashMap;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.NoSuchElementException;
46 import java.util.Objects;
47 import java.util.Optional;
48 import java.util.Set;
49 import java.util.function.Function;
50 import java.util.stream.Collectors;
51
52 import jdk.internal.loader.BootLoader;
53 import jdk.internal.loader.BuiltinClassLoader;
54 import jdk.internal.access.JavaLangAccess;
55 import jdk.internal.access.JavaLangModuleAccess;
56 import jdk.internal.access.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 configuration defined to a class loader.
69 */
70
71 public final class ModuleBootstrap {
72 private ModuleBootstrap() { }
73
74 private static final String JAVA_BASE = "java.base";
75
76 // the token for "all default modules"
77 private static final String ALL_DEFAULT = "ALL-DEFAULT";
78
79 // the token for "all unnamed modules"
80 private static final String ALL_UNNAMED = "ALL-UNNAMED";
81
82 // the token for "all system modules"
83 private static final String ALL_SYSTEM = "ALL-SYSTEM";
84
85 // the token for "all modules on the module path"
86 private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
87
88 // access to java.lang/module
89 private static final JavaLangModuleAccess JLMA
90 = SharedSecrets.getJavaLangModuleAccess();
91
92 // The ModulePatcher for the initial configuration
93 private static final ModulePatcher patcher = initModulePatcher();
94
95 /**
96 * Returns the ModulePatcher for the initial configuration.
97 */
98 public static ModulePatcher patcher() {
99 return patcher;
100 }
101
102 // ModuleFinders for the initial configuration
103 private static volatile ModuleFinder unlimitedFinder;
104 private static volatile ModuleFinder limitedFinder;
105
106 /**
107 * Returns the ModuleFinder for the initial configuration before
108 * observability is limited by the --limit-modules command line option.
109 *
110 * @apiNote Used to support locating modules {@code java.instrument} and
117 } else {
118 return finder;
119 }
120 }
121
122 /**
123 * Returns the ModuleFinder for the initial configuration.
124 *
125 * @apiNote Used to support "{@code java --list-modules}".
126 */
127 public static ModuleFinder limitedFinder() {
128 ModuleFinder finder = limitedFinder;
129 if (finder == null) {
130 return unlimitedFinder();
131 } else {
132 return finder;
133 }
134 }
135
136 /**
137 * Initialize the module system, returning the boot layer.
138 *
139 * @see java.lang.System#initPhase2(boolean, boolean)
140 */
141 public static ModuleLayer boot() throws Exception {
142
143 Counters.start();
144
145 // Step 0: Command line options
146
147 ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path");
148 ModuleFinder appModulePath = finderFor("jdk.module.path");
149 boolean isPatched = patcher.hasPatches();
150
151 String mainModule = System.getProperty("jdk.module.main");
152 Set<String> addModules = addModules();
153 Set<String> limitModules = limitModules();
154
155 PrintStream traceOutput = null;
156 String trace = getAndRemoveProperty("jdk.module.showModuleResolution");
157 if (trace != null && Boolean.parseBoolean(trace))
158 traceOutput = System.out;
159
160 Counters.add("jdk.module.boot.0.commandLineTime");
161
162 // Step 1: The observable system modules, either all system modules
163 // or the system modules pre-generated for the initial module (the
164 // initial module may be the unnamed module). If the system modules
411 // Step 7: Miscellaneous
412
413 // check incubating status
414 if (hasIncubatorModules || haveModulePath) {
415 checkIncubatingStatus(cf);
416 }
417
418 // --add-reads, --add-exports/--add-opens, and --illegal-access
419 addExtraReads(bootLayer);
420 boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer);
421
422 Map<String, Set<String>> concealedPackagesToOpen;
423 Map<String, Set<String>> exportedPackagesToOpen;
424 if (archivedModuleGraph != null) {
425 concealedPackagesToOpen = archivedModuleGraph.concealedPackagesToOpen();
426 exportedPackagesToOpen = archivedModuleGraph.exportedPackagesToOpen();
427 } else {
428 concealedPackagesToOpen = systemModules.concealedPackagesToOpen();
429 exportedPackagesToOpen = systemModules.exportedPackagesToOpen();
430 }
431 addIllegalAccess(upgradeModulePath,
432 concealedPackagesToOpen,
433 exportedPackagesToOpen,
434 bootLayer,
435 extraExportsOrOpens);
436 Counters.add("jdk.module.boot.7.adjustModulesTime");
437
438 // save module finders for later use
439 if (savedModuleFinder != null) {
440 unlimitedFinder = new SafeModuleFinder(savedModuleFinder);
441 if (savedModuleFinder != finder)
442 limitedFinder = new SafeModuleFinder(finder);
443 }
444
445 // Module graph can be archived at CDS dump time. Only allow the
446 // unnamed module case for now.
447 if (canArchive && (mainModule == null)) {
448 ArchivedModuleGraph.archive(
449 new ArchivedModuleGraph(hasSplitPackages,
450 hasIncubatorModules,
451 systemModuleFinder,
452 cf,
453 clf,
454 concealedPackagesToOpen,
455 exportedPackagesToOpen));
456 }
457
458 // total time to initialize
459 Counters.publish("jdk.module.boot.totalTime");
460
461 return bootLayer;
462 }
463
464 /**
465 * Load/register the modules to the built-in class loaders.
466 */
467 private static void loadModules(Configuration cf,
468 Function<String, ClassLoader> clf) {
469 for (ResolvedModule resolvedModule : cf.modules()) {
470 ModuleReference mref = resolvedModule.reference();
471 String name = resolvedModule.name();
472 ClassLoader loader = clf.apply(name);
473 if (loader == null) {
474 // skip java.base as it is already loaded
475 if (!name.equals(JAVA_BASE)) {
476 BootLoader.loadModule(mref);
477 }
478 } else if (loader instanceof BuiltinClassLoader) {
479 ((BuiltinClassLoader) loader).loadModule(mref);
734 if (opens) {
735 Modules.addOpensToAllUnnamed(m, pn);
736 } else {
737 Modules.addExportsToAllUnnamed(m, pn);
738 }
739 } else {
740 if (opens) {
741 Modules.addOpens(m, pn, other);
742 } else {
743 Modules.addExports(m, pn, other);
744 }
745 }
746 }
747 }
748 }
749
750 /**
751 * Process the --illegal-access option (and its default) to open packages
752 * of system modules in the boot layer to code in unnamed modules.
753 */
754 private static void addIllegalAccess(ModuleFinder upgradeModulePath,
755 Map<String, Set<String>> concealedPackagesToOpen,
756 Map<String, Set<String>> exportedPackagesToOpen,
757 ModuleLayer bootLayer,
758 boolean extraExportsOrOpens) {
759 String value = getAndRemoveProperty("jdk.module.illegalAccess");
760 IllegalAccessLogger.Mode mode = IllegalAccessLogger.Mode.ONESHOT;
761 if (value != null) {
762 switch (value) {
763 case "deny":
764 return;
765 case "permit":
766 break;
767 case "warn":
768 mode = IllegalAccessLogger.Mode.WARN;
769 break;
770 case "debug":
771 mode = IllegalAccessLogger.Mode.DEBUG;
772 break;
773 default:
774 fail("Value specified to --illegal-access not recognized:"
775 + " '" + value + "'");
776 return;
777 }
778 }
779 IllegalAccessLogger.Builder builder
780 = new IllegalAccessLogger.Builder(mode, System.err);
781
782 if (concealedPackagesToOpen.isEmpty() && exportedPackagesToOpen.isEmpty()) {
783 // need to generate (exploded build)
784 IllegalAccessMaps maps = IllegalAccessMaps.generate(limitedFinder());
785 concealedPackagesToOpen = maps.concealedPackagesToOpen();
786 exportedPackagesToOpen = maps.exportedPackagesToOpen();
787 }
788
789 // open specific packages in the system modules
790 Set<String> emptySet = Set.of();
791 for (Module m : bootLayer.modules()) {
792 ModuleDescriptor descriptor = m.getDescriptor();
793 String name = m.getName();
794
795 // skip open modules
796 if (descriptor.isOpen()) {
819 exportedPackages.add(pn);
820 }
821 }
822 iterator = exportedPackages.iterator();
823 while (iterator.hasNext()) {
824 String pn = iterator.next();
825 if (m.isOpen(pn, BootLoader.getUnnamedModule())) {
826 // exported package is opened to ALL-UNNAMED
827 iterator.remove();
828 }
829 }
830 }
831
832 // log reflective access to all types in concealed packages
833 builder.logAccessToConcealedPackages(m, concealedPackages);
834
835 // log reflective access to non-public members/types in exported packages
836 builder.logAccessToExportedPackages(m, exportedPackages);
837
838 // open the packages to unnamed modules
839 JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
840 jla.addOpensToAllUnnamed(m, concealedPackages, exportedPackages);
841 }
842
843 builder.complete();
844 }
845
846 /**
847 * Decodes the values of --add-reads, -add-exports, --add-opens or
848 * --patch-modules options that are encoded in system properties.
849 *
850 * @param prefix the system property prefix
851 * @praam regex the regex for splitting the RHS of the option value
852 */
853 private static Map<String, List<String>> decode(String prefix,
854 String regex,
855 boolean allowDuplicates) {
856 int index = 0;
857 // the system property is removed after decoding
858 String value = getAndRemoveProperty(prefix + index);
859 if (value == null)
860 return Map.of();
861
862 Map<String, List<String>> map = new HashMap<>();
863
888 }
889 }
890 if (ntargets == 0)
891 fail("Target must be specified: " + option(prefix) + " " + value);
892
893 index++;
894 value = getAndRemoveProperty(prefix + index);
895 }
896
897 return map;
898 }
899
900 /**
901 * Decodes the values of --add-reads, -add-exports or --add-opens
902 * which use the "," to separate the RHS of the option value.
903 */
904 private static Map<String, List<String>> decode(String prefix) {
905 return decode(prefix, ",", true);
906 }
907
908 /**
909 * Gets and remove the named system property
910 */
911 private static String getAndRemoveProperty(String key) {
912 return (String)System.getProperties().remove(key);
913 }
914
915 /**
916 * Checks incubating status of modules in the configuration
917 */
918 private static void checkIncubatingStatus(Configuration cf) {
919 String incubating = null;
920 for (ResolvedModule resolvedModule : cf.modules()) {
921 ModuleReference mref = resolvedModule.reference();
922
923 // emit warning if the WARN_INCUBATING module resolution bit set
924 if (ModuleResolution.hasIncubatingWarning(mref)) {
925 String mn = mref.descriptor().name();
926 if (incubating == null) {
927 incubating = mn;
928 } else {
929 incubating += ", " + mn;
930 }
931 }
932 }
|
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.net.URI;
36 import java.nio.file.Path;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.LinkedHashMap;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Objects;
46 import java.util.Optional;
47 import java.util.Set;
48 import java.util.function.Function;
49 import java.util.stream.Collectors;
50
51 import jdk.internal.access.JavaLangAccess;
52 import jdk.internal.access.JavaLangModuleAccess;
53 import jdk.internal.access.SharedSecrets;
54 import jdk.internal.loader.BootLoader;
55 import jdk.internal.loader.BuiltinClassLoader;
56 import jdk.internal.loader.ClassLoaders;
57 import jdk.internal.misc.VM;
58 import jdk.internal.perf.PerfCounter;
59
60 /**
61 * Initializes/boots the module system.
62 *
63 * The {@link #boot() boot} method is called early in the startup to initialize
64 * the module system. In summary, the boot method creates a Configuration by
65 * resolving a set of module names specified via the launcher (or equivalent)
66 * -m and --add-modules options. The modules are located on a module path that
67 * is constructed from the upgrade module path, system modules, and application
68 * module path. The Configuration is instantiated as the boot layer with each
69 * module in the configuration defined to a class loader.
70 */
71
72 public final class ModuleBootstrap {
73 private ModuleBootstrap() { }
74
75 private static final String JAVA_BASE = "java.base";
76
77 // the token for "all default modules"
78 private static final String ALL_DEFAULT = "ALL-DEFAULT";
79
80 // the token for "all unnamed modules"
81 private static final String ALL_UNNAMED = "ALL-UNNAMED";
82
83 // the token for "all system modules"
84 private static final String ALL_SYSTEM = "ALL-SYSTEM";
85
86 // the token for "all modules on the module path"
87 private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
88
89 // access to java.lang/module
90 private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
91 private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
92
93 // The ModulePatcher for the initial configuration
94 private static final ModulePatcher patcher = initModulePatcher();
95
96 /**
97 * Returns the ModulePatcher for the initial configuration.
98 */
99 public static ModulePatcher patcher() {
100 return patcher;
101 }
102
103 // ModuleFinders for the initial configuration
104 private static volatile ModuleFinder unlimitedFinder;
105 private static volatile ModuleFinder limitedFinder;
106
107 /**
108 * Returns the ModuleFinder for the initial configuration before
109 * observability is limited by the --limit-modules command line option.
110 *
111 * @apiNote Used to support locating modules {@code java.instrument} and
118 } else {
119 return finder;
120 }
121 }
122
123 /**
124 * Returns the ModuleFinder for the initial configuration.
125 *
126 * @apiNote Used to support "{@code java --list-modules}".
127 */
128 public static ModuleFinder limitedFinder() {
129 ModuleFinder finder = limitedFinder;
130 if (finder == null) {
131 return unlimitedFinder();
132 } else {
133 return finder;
134 }
135 }
136
137 /**
138 * Returns true if the archived boot layer can be used. The system properties
139 * are checked in the order that they are used by boot2.
140 */
141 private static boolean canUseArchivedBootLayer() {
142 return getProperty("jdk.module.upgrade.path") == null &&
143 getProperty("jdk.module.path") == null &&
144 getProperty("jdk.module.patch.0") == null && // --patch-module
145 getProperty("jdk.module.main") == null &&
146 getProperty("jdk.module.addmods.0") == null && // --add-modules
147 getProperty("jdk.module.limitmods") == null &&
148 getProperty("jdk.module.addreads.0") == null && // --add-reads
149 getProperty("jdk.module.addexports.0") == null && // --add-exports
150 getProperty("jdk.module.addopens.0") == null && // --add-opens
151 getProperty("jdk.module.illegalAccess") == null;
152 }
153
154 /**
155 * Initialize the module system, returning the boot layer. The boot layer
156 * is obtained from the CDS archive if possible, otherwise it is generated
157 * from the module graph.
158 *
159 * @see java.lang.System#initPhase2(boolean, boolean)
160 */
161 public static ModuleLayer boot() {
162 Counters.start();
163
164 ModuleLayer bootLayer;
165 ArchivedBootLayer archivedBootLayer = ArchivedBootLayer.get();
166 if (archivedBootLayer != null) {
167 assert canUseArchivedBootLayer();
168 bootLayer = archivedBootLayer.bootLayer();
169 BootLoader.getUnnamedModule(); // trigger <clinit> of BootLoader.
170 VM.defineArchivedModules(ClassLoaders.platformClassLoader(), ClassLoaders.appClassLoader());
171
172 // assume boot layer has at least one module providing a service
173 // that is mapped to the application class loader.
174 JLA.bindToLoader(bootLayer, ClassLoaders.appClassLoader());
175
176 // IllegalAccessLogger needs to be set
177 var illegalAccessLoggerBuilder = archivedBootLayer.illegalAccessLoggerBuilder();
178 if (illegalAccessLoggerBuilder != null) {
179 illegalAccessLoggerBuilder.complete();
180 }
181 } else {
182 bootLayer = boot2();
183 }
184
185 Counters.publish("jdk.module.boot.totalTime");
186 return bootLayer;
187 }
188
189 private static ModuleLayer boot2() {
190 // Step 0: Command line options
191
192 ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path");
193 ModuleFinder appModulePath = finderFor("jdk.module.path");
194 boolean isPatched = patcher.hasPatches();
195
196 String mainModule = System.getProperty("jdk.module.main");
197 Set<String> addModules = addModules();
198 Set<String> limitModules = limitModules();
199
200 PrintStream traceOutput = null;
201 String trace = getAndRemoveProperty("jdk.module.showModuleResolution");
202 if (trace != null && Boolean.parseBoolean(trace))
203 traceOutput = System.out;
204
205 Counters.add("jdk.module.boot.0.commandLineTime");
206
207 // Step 1: The observable system modules, either all system modules
208 // or the system modules pre-generated for the initial module (the
209 // initial module may be the unnamed module). If the system modules
456 // Step 7: Miscellaneous
457
458 // check incubating status
459 if (hasIncubatorModules || haveModulePath) {
460 checkIncubatingStatus(cf);
461 }
462
463 // --add-reads, --add-exports/--add-opens, and --illegal-access
464 addExtraReads(bootLayer);
465 boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer);
466
467 Map<String, Set<String>> concealedPackagesToOpen;
468 Map<String, Set<String>> exportedPackagesToOpen;
469 if (archivedModuleGraph != null) {
470 concealedPackagesToOpen = archivedModuleGraph.concealedPackagesToOpen();
471 exportedPackagesToOpen = archivedModuleGraph.exportedPackagesToOpen();
472 } else {
473 concealedPackagesToOpen = systemModules.concealedPackagesToOpen();
474 exportedPackagesToOpen = systemModules.exportedPackagesToOpen();
475 }
476 IllegalAccessLogger.Builder builder =
477 addIllegalAccess(upgradeModulePath,
478 concealedPackagesToOpen,
479 exportedPackagesToOpen,
480 bootLayer,
481 extraExportsOrOpens);
482 Counters.add("jdk.module.boot.7.adjustModulesTime");
483
484 // save module finders for later use
485 if (savedModuleFinder != null) {
486 unlimitedFinder = new SafeModuleFinder(savedModuleFinder);
487 if (savedModuleFinder != finder)
488 limitedFinder = new SafeModuleFinder(finder);
489 }
490
491 // Archive module graph and boot layer can be archived at CDS dump time.
492 // Only allow the unnamed module case for now.
493 if (canArchive && (mainModule == null)) {
494 ArchivedModuleGraph.archive(hasSplitPackages,
495 hasIncubatorModules,
496 systemModuleFinder,
497 cf,
498 clf,
499 concealedPackagesToOpen,
500 exportedPackagesToOpen);
501
502 if (!hasSplitPackages && !hasIncubatorModules) {
503 ArchivedBootLayer.archive(bootLayer, builder);
504 }
505 }
506
507 return bootLayer;
508 }
509
510 /**
511 * Load/register the modules to the built-in class loaders.
512 */
513 private static void loadModules(Configuration cf,
514 Function<String, ClassLoader> clf) {
515 for (ResolvedModule resolvedModule : cf.modules()) {
516 ModuleReference mref = resolvedModule.reference();
517 String name = resolvedModule.name();
518 ClassLoader loader = clf.apply(name);
519 if (loader == null) {
520 // skip java.base as it is already loaded
521 if (!name.equals(JAVA_BASE)) {
522 BootLoader.loadModule(mref);
523 }
524 } else if (loader instanceof BuiltinClassLoader) {
525 ((BuiltinClassLoader) loader).loadModule(mref);
780 if (opens) {
781 Modules.addOpensToAllUnnamed(m, pn);
782 } else {
783 Modules.addExportsToAllUnnamed(m, pn);
784 }
785 } else {
786 if (opens) {
787 Modules.addOpens(m, pn, other);
788 } else {
789 Modules.addExports(m, pn, other);
790 }
791 }
792 }
793 }
794 }
795
796 /**
797 * Process the --illegal-access option (and its default) to open packages
798 * of system modules in the boot layer to code in unnamed modules.
799 */
800 private static IllegalAccessLogger.Builder
801 addIllegalAccess(ModuleFinder upgradeModulePath,
802 Map<String, Set<String>> concealedPackagesToOpen,
803 Map<String, Set<String>> exportedPackagesToOpen,
804 ModuleLayer bootLayer,
805 boolean extraExportsOrOpens) {
806 String value = getAndRemoveProperty("jdk.module.illegalAccess");
807 IllegalAccessLogger.Mode mode = IllegalAccessLogger.Mode.ONESHOT;
808 if (value != null) {
809 switch (value) {
810 case "deny":
811 return null;
812 case "permit":
813 break;
814 case "warn":
815 mode = IllegalAccessLogger.Mode.WARN;
816 break;
817 case "debug":
818 mode = IllegalAccessLogger.Mode.DEBUG;
819 break;
820 default:
821 fail("Value specified to --illegal-access not recognized:"
822 + " '" + value + "'");
823 return null;
824 }
825 }
826 IllegalAccessLogger.Builder builder
827 = new IllegalAccessLogger.Builder(mode, System.err);
828
829 if (concealedPackagesToOpen.isEmpty() && exportedPackagesToOpen.isEmpty()) {
830 // need to generate (exploded build)
831 IllegalAccessMaps maps = IllegalAccessMaps.generate(limitedFinder());
832 concealedPackagesToOpen = maps.concealedPackagesToOpen();
833 exportedPackagesToOpen = maps.exportedPackagesToOpen();
834 }
835
836 // open specific packages in the system modules
837 Set<String> emptySet = Set.of();
838 for (Module m : bootLayer.modules()) {
839 ModuleDescriptor descriptor = m.getDescriptor();
840 String name = m.getName();
841
842 // skip open modules
843 if (descriptor.isOpen()) {
866 exportedPackages.add(pn);
867 }
868 }
869 iterator = exportedPackages.iterator();
870 while (iterator.hasNext()) {
871 String pn = iterator.next();
872 if (m.isOpen(pn, BootLoader.getUnnamedModule())) {
873 // exported package is opened to ALL-UNNAMED
874 iterator.remove();
875 }
876 }
877 }
878
879 // log reflective access to all types in concealed packages
880 builder.logAccessToConcealedPackages(m, concealedPackages);
881
882 // log reflective access to non-public members/types in exported packages
883 builder.logAccessToExportedPackages(m, exportedPackages);
884
885 // open the packages to unnamed modules
886 JLA.addOpensToAllUnnamed(m, concealedPackages, exportedPackages);
887 }
888
889 builder.complete();
890 return builder;
891 }
892
893 /**
894 * Decodes the values of --add-reads, -add-exports, --add-opens or
895 * --patch-modules options that are encoded in system properties.
896 *
897 * @param prefix the system property prefix
898 * @praam regex the regex for splitting the RHS of the option value
899 */
900 private static Map<String, List<String>> decode(String prefix,
901 String regex,
902 boolean allowDuplicates) {
903 int index = 0;
904 // the system property is removed after decoding
905 String value = getAndRemoveProperty(prefix + index);
906 if (value == null)
907 return Map.of();
908
909 Map<String, List<String>> map = new HashMap<>();
910
935 }
936 }
937 if (ntargets == 0)
938 fail("Target must be specified: " + option(prefix) + " " + value);
939
940 index++;
941 value = getAndRemoveProperty(prefix + index);
942 }
943
944 return map;
945 }
946
947 /**
948 * Decodes the values of --add-reads, -add-exports or --add-opens
949 * which use the "," to separate the RHS of the option value.
950 */
951 private static Map<String, List<String>> decode(String prefix) {
952 return decode(prefix, ",", true);
953 }
954
955
956 /**
957 * Gets the named system property
958 */
959 private static String getProperty(String key) {
960 return System.getProperty(key);
961 }
962
963 /**
964 * Gets and remove the named system property
965 */
966 private static String getAndRemoveProperty(String key) {
967 return (String) System.getProperties().remove(key);
968 }
969
970 /**
971 * Checks incubating status of modules in the configuration
972 */
973 private static void checkIncubatingStatus(Configuration cf) {
974 String incubating = null;
975 for (ResolvedModule resolvedModule : cf.modules()) {
976 ModuleReference mref = resolvedModule.reference();
977
978 // emit warning if the WARN_INCUBATING module resolution bit set
979 if (ModuleResolution.hasIncubatingWarning(mref)) {
980 String mn = mref.descriptor().name();
981 if (incubating == null) {
982 incubating = mn;
983 } else {
984 incubating += ", " + mn;
985 }
986 }
987 }
|