111 * Creates a new named Module. The resulting Module will be defined to the
112 * VM but will not read any other modules, will not have any exports setup
113 * and will not be registered in the service catalog.
114 */
115 private Module(Layer layer,
116 ClassLoader loader,
117 ModuleDescriptor descriptor,
118 URI uri)
119 {
120 this.layer = layer;
121 this.name = descriptor.name();
122 this.loader = loader;
123 this.descriptor = descriptor;
124
125 // define module to VM
126
127 boolean isOpen = descriptor.isOpen();
128 Version version = descriptor.version().orElse(null);
129 String vs = Objects.toString(version, null);
130 String loc = Objects.toString(uri, null);
131 Set<String> packages = descriptor.packages();
132 int n = packages.size();
133 String[] array = new String[n];
134 int i = 0;
135 for (String pn : packages) {
136 array[i++] = pn.replace('.', '/');
137 }
138 defineModule0(this, isOpen, vs, loc, array);
139 }
140
141
142 /**
143 * Create the unnamed Module for the given ClassLoader.
144 *
145 * @see ClassLoader#getUnnamedModule
146 */
147 private Module(ClassLoader loader) {
148 this.layer = null;
149 this.name = null;
150 this.loader = loader;
151 this.descriptor = null;
152 }
153
154
155 /**
156 * Creates a named module but without defining the module to the VM.
157 *
158 * @apiNote This constructor is for VM white-box testing.
772 boolean syncVM) {
773 Objects.requireNonNull(other);
774 Objects.requireNonNull(pn);
775
776 // all packages are open in unnamed and open modules
777 if (!isNamed() || descriptor.isOpen())
778 return;
779
780 // nothing to do if already exported/open to other
781 if (implIsExportedOrOpen(pn, other, open))
782 return;
783
784 // can only export a package in the module
785 if (!containsPackage(pn)) {
786 throw new IllegalArgumentException("package " + pn
787 + " not in contents");
788 }
789
790 // update VM first, just in case it fails
791 if (syncVM) {
792 String pkgInternalForm = pn.replace('.', '/');
793 if (other == EVERYONE_MODULE) {
794 addExportsToAll0(this, pkgInternalForm);
795 } else if (other == ALL_UNNAMED_MODULE) {
796 addExportsToAllUnnamed0(this, pkgInternalForm);
797 } else {
798 addExports0(this, pkgInternalForm, other);
799 }
800 }
801
802 // add package name to reflectivelyExports if absent
803 Map<String, Boolean> map = reflectivelyExports
804 .computeIfAbsent(this, other,
805 (m1, m2) -> new ConcurrentHashMap<>());
806
807 if (open) {
808 map.put(pn, Boolean.TRUE); // may need to promote from FALSE to TRUE
809 } else {
810 map.putIfAbsent(pn, Boolean.FALSE);
811 }
812 }
813
814
815 // -- services --
816
817 // additional service type (2nd key) that some module (1st key) uses
818 private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses
1004 return;
1005 }
1006 synchronized (this) {
1007 // recheck under lock
1008 extraPackages = this.extraPackages;
1009 if (extraPackages != null) {
1010 if (extraPackages.contains(pn)) {
1011 // already added
1012 return;
1013 }
1014
1015 // copy the set
1016 extraPackages = new HashSet<>(extraPackages);
1017 extraPackages.add(pn);
1018 } else {
1019 extraPackages = Collections.singleton(pn);
1020 }
1021
1022 // update VM first, just in case it fails
1023 if (syncVM)
1024 addPackage0(this, pn.replace('.', '/'));
1025
1026 // replace with new set
1027 this.extraPackages = extraPackages; // volatile write
1028 }
1029 }
1030
1031
1032 // -- creating Module objects --
1033
1034 /**
1035 * Defines all module in a configuration to the runtime.
1036 *
1037 * @return a map of module name to runtime {@code Module}
1038 *
1039 * @throws IllegalArgumentException
1040 * If defining any of the modules to the VM fails
1041 */
1042 static Map<String, Module> defineModules(Configuration cf,
1043 Function<String, ClassLoader> clf,
1044 Layer layer)
1163 Optional<Module> om = layer.findModule(dn);
1164 assert om.isPresent() : dn + " not found in layer";
1165 Module m = om.get();
1166 assert m.getLayer() == layer : m + " not in expected layer";
1167 return m;
1168 })
1169 .orElse(null);
1170 }
1171
1172 /**
1173 * Initialize the maps of exported and open packages for module m.
1174 */
1175 private static void initExportsAndOpens(ModuleDescriptor descriptor,
1176 Map<String, Module> nameToModule,
1177 Module m)
1178 {
1179 // The VM doesn't know about open modules so need to export all packages
1180 if (descriptor.isOpen()) {
1181 assert descriptor.opens().isEmpty();
1182 for (String source : descriptor.packages()) {
1183 String sourceInternalForm = source.replace('.', '/');
1184 addExportsToAll0(m, sourceInternalForm);
1185 }
1186 return;
1187 }
1188
1189 Map<String, Set<Module>> openPackages = new HashMap<>();
1190 Map<String, Set<Module>> exportedPackages = new HashMap<>();
1191
1192 // process the open packages first
1193 for (Opens opens : descriptor.opens()) {
1194 String source = opens.source();
1195 String sourceInternalForm = source.replace('.', '/');
1196
1197 if (opens.isQualified()) {
1198 // qualified opens
1199 Set<Module> targets = new HashSet<>();
1200 for (String target : opens.targets()) {
1201 // only open to modules that are in this configuration
1202 Module m2 = nameToModule.get(target);
1203 if (m2 != null) {
1204 addExports0(m, sourceInternalForm, m2);
1205 targets.add(m2);
1206 }
1207 }
1208 if (!targets.isEmpty()) {
1209 openPackages.put(source, targets);
1210 }
1211 } else {
1212 // unqualified opens
1213 addExportsToAll0(m, sourceInternalForm);
1214 openPackages.put(source, EVERYONE_SET);
1215 }
1216 }
1217
1218 // next the exports, skipping exports when the package is open
1219 for (Exports exports : descriptor.exports()) {
1220 String source = exports.source();
1221 String sourceInternalForm = source.replace('.', '/');
1222
1223 // skip export if package is already open to everyone
1224 Set<Module> openToTargets = openPackages.get(source);
1225 if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE))
1226 continue;
1227
1228 if (exports.isQualified()) {
1229 // qualified exports
1230 Set<Module> targets = new HashSet<>();
1231 for (String target : exports.targets()) {
1232 // only export to modules that are in this configuration
1233 Module m2 = nameToModule.get(target);
1234 if (m2 != null) {
1235 // skip qualified export if already open to m2
1236 if (openToTargets == null || !openToTargets.contains(m2)) {
1237 addExports0(m, sourceInternalForm, m2);
1238 targets.add(m2);
1239 }
1240 }
1241 }
1242 if (!targets.isEmpty()) {
1243 exportedPackages.put(source, targets);
1244 }
1245
1246 } else {
1247 // unqualified exports
1248 addExportsToAll0(m, sourceInternalForm);
1249 exportedPackages.put(source, EVERYONE_SET);
1250 }
1251 }
1252
1253 if (!openPackages.isEmpty())
1254 m.openPackages = openPackages;
1255 if (!exportedPackages.isEmpty())
1256 m.exportedPackages = exportedPackages;
1257 }
1258
1259
1260 // -- annotations --
1261
1262 /**
1263 * {@inheritDoc}
1264 * This method returns {@code null} when invoked on an unnamed module.
1265 */
1266 @Override
1267 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
1268 return moduleInfoClass().getDeclaredAnnotation(annotationClass);
|
111 * Creates a new named Module. The resulting Module will be defined to the
112 * VM but will not read any other modules, will not have any exports setup
113 * and will not be registered in the service catalog.
114 */
115 private Module(Layer layer,
116 ClassLoader loader,
117 ModuleDescriptor descriptor,
118 URI uri)
119 {
120 this.layer = layer;
121 this.name = descriptor.name();
122 this.loader = loader;
123 this.descriptor = descriptor;
124
125 // define module to VM
126
127 boolean isOpen = descriptor.isOpen();
128 Version version = descriptor.version().orElse(null);
129 String vs = Objects.toString(version, null);
130 String loc = Objects.toString(uri, null);
131 String[] packages = descriptor.packages().toArray(new String[0]);
132 defineModule0(this, isOpen, vs, loc, packages);
133 }
134
135
136 /**
137 * Create the unnamed Module for the given ClassLoader.
138 *
139 * @see ClassLoader#getUnnamedModule
140 */
141 private Module(ClassLoader loader) {
142 this.layer = null;
143 this.name = null;
144 this.loader = loader;
145 this.descriptor = null;
146 }
147
148
149 /**
150 * Creates a named module but without defining the module to the VM.
151 *
152 * @apiNote This constructor is for VM white-box testing.
766 boolean syncVM) {
767 Objects.requireNonNull(other);
768 Objects.requireNonNull(pn);
769
770 // all packages are open in unnamed and open modules
771 if (!isNamed() || descriptor.isOpen())
772 return;
773
774 // nothing to do if already exported/open to other
775 if (implIsExportedOrOpen(pn, other, open))
776 return;
777
778 // can only export a package in the module
779 if (!containsPackage(pn)) {
780 throw new IllegalArgumentException("package " + pn
781 + " not in contents");
782 }
783
784 // update VM first, just in case it fails
785 if (syncVM) {
786 if (other == EVERYONE_MODULE) {
787 addExportsToAll0(this, pn);
788 } else if (other == ALL_UNNAMED_MODULE) {
789 addExportsToAllUnnamed0(this, pn);
790 } else {
791 addExports0(this, pn, other);
792 }
793 }
794
795 // add package name to reflectivelyExports if absent
796 Map<String, Boolean> map = reflectivelyExports
797 .computeIfAbsent(this, other,
798 (m1, m2) -> new ConcurrentHashMap<>());
799
800 if (open) {
801 map.put(pn, Boolean.TRUE); // may need to promote from FALSE to TRUE
802 } else {
803 map.putIfAbsent(pn, Boolean.FALSE);
804 }
805 }
806
807
808 // -- services --
809
810 // additional service type (2nd key) that some module (1st key) uses
811 private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses
997 return;
998 }
999 synchronized (this) {
1000 // recheck under lock
1001 extraPackages = this.extraPackages;
1002 if (extraPackages != null) {
1003 if (extraPackages.contains(pn)) {
1004 // already added
1005 return;
1006 }
1007
1008 // copy the set
1009 extraPackages = new HashSet<>(extraPackages);
1010 extraPackages.add(pn);
1011 } else {
1012 extraPackages = Collections.singleton(pn);
1013 }
1014
1015 // update VM first, just in case it fails
1016 if (syncVM)
1017 addPackage0(this, pn);
1018
1019 // replace with new set
1020 this.extraPackages = extraPackages; // volatile write
1021 }
1022 }
1023
1024
1025 // -- creating Module objects --
1026
1027 /**
1028 * Defines all module in a configuration to the runtime.
1029 *
1030 * @return a map of module name to runtime {@code Module}
1031 *
1032 * @throws IllegalArgumentException
1033 * If defining any of the modules to the VM fails
1034 */
1035 static Map<String, Module> defineModules(Configuration cf,
1036 Function<String, ClassLoader> clf,
1037 Layer layer)
1156 Optional<Module> om = layer.findModule(dn);
1157 assert om.isPresent() : dn + " not found in layer";
1158 Module m = om.get();
1159 assert m.getLayer() == layer : m + " not in expected layer";
1160 return m;
1161 })
1162 .orElse(null);
1163 }
1164
1165 /**
1166 * Initialize the maps of exported and open packages for module m.
1167 */
1168 private static void initExportsAndOpens(ModuleDescriptor descriptor,
1169 Map<String, Module> nameToModule,
1170 Module m)
1171 {
1172 // The VM doesn't know about open modules so need to export all packages
1173 if (descriptor.isOpen()) {
1174 assert descriptor.opens().isEmpty();
1175 for (String source : descriptor.packages()) {
1176 addExportsToAll0(m, source);
1177 }
1178 return;
1179 }
1180
1181 Map<String, Set<Module>> openPackages = new HashMap<>();
1182 Map<String, Set<Module>> exportedPackages = new HashMap<>();
1183
1184 // process the open packages first
1185 for (Opens opens : descriptor.opens()) {
1186 String source = opens.source();
1187
1188 if (opens.isQualified()) {
1189 // qualified opens
1190 Set<Module> targets = new HashSet<>();
1191 for (String target : opens.targets()) {
1192 // only open to modules that are in this configuration
1193 Module m2 = nameToModule.get(target);
1194 if (m2 != null) {
1195 addExports0(m, source, m2);
1196 targets.add(m2);
1197 }
1198 }
1199 if (!targets.isEmpty()) {
1200 openPackages.put(source, targets);
1201 }
1202 } else {
1203 // unqualified opens
1204 addExportsToAll0(m, source);
1205 openPackages.put(source, EVERYONE_SET);
1206 }
1207 }
1208
1209 // next the exports, skipping exports when the package is open
1210 for (Exports exports : descriptor.exports()) {
1211 String source = exports.source();
1212
1213 // skip export if package is already open to everyone
1214 Set<Module> openToTargets = openPackages.get(source);
1215 if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE))
1216 continue;
1217
1218 if (exports.isQualified()) {
1219 // qualified exports
1220 Set<Module> targets = new HashSet<>();
1221 for (String target : exports.targets()) {
1222 // only export to modules that are in this configuration
1223 Module m2 = nameToModule.get(target);
1224 if (m2 != null) {
1225 // skip qualified export if already open to m2
1226 if (openToTargets == null || !openToTargets.contains(m2)) {
1227 addExports0(m, source, m2);
1228 targets.add(m2);
1229 }
1230 }
1231 }
1232 if (!targets.isEmpty()) {
1233 exportedPackages.put(source, targets);
1234 }
1235
1236 } else {
1237 // unqualified exports
1238 addExportsToAll0(m, source);
1239 exportedPackages.put(source, EVERYONE_SET);
1240 }
1241 }
1242
1243 if (!openPackages.isEmpty())
1244 m.openPackages = openPackages;
1245 if (!exportedPackages.isEmpty())
1246 m.exportedPackages = exportedPackages;
1247 }
1248
1249
1250 // -- annotations --
1251
1252 /**
1253 * {@inheritDoc}
1254 * This method returns {@code null} when invoked on an unnamed module.
1255 */
1256 @Override
1257 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
1258 return moduleInfoClass().getDeclaredAnnotation(annotationClass);
|