67 private final Map<String, ModuleReference> nameToReference = new HashMap<>(); |
68 private final Map<String, ModuleReference> nameToReference = new HashMap<>(); |
68 |
69 |
69 // module constraints on target platform |
70 // module constraints on target platform |
70 private String osName; |
71 private String osName; |
71 private String osArch; |
72 private String osArch; |
72 private String osVersion; |
|
73 |
73 |
74 String osName() { return osName; } |
74 String osName() { return osName; } |
75 String osArch() { return osArch; } |
75 String osArch() { return osArch; } |
76 String osVersion() { return osVersion; } |
|
77 |
76 |
78 /** |
77 /** |
79 * @throws IllegalArgumentException if there are more than one parent and |
78 * @throws IllegalArgumentException if there are more than one parent and |
80 * the constraints on the target platform conflict |
79 * the constraints on the target platform conflict |
81 */ |
80 */ |
316 /** |
305 /** |
317 * Add the module to the nameToReference map. Also check any constraints on |
306 * Add the module to the nameToReference map. Also check any constraints on |
318 * the target platform with the constraints of other modules. |
307 * the target platform with the constraints of other modules. |
319 */ |
308 */ |
320 private void addFoundModule(ModuleReference mref) { |
309 private void addFoundModule(ModuleReference mref) { |
321 ModuleDescriptor descriptor = mref.descriptor(); |
310 String mn = mref.descriptor().name(); |
322 nameToReference.put(descriptor.name(), mref); |
311 |
323 |
312 if (mref instanceof ModuleReferenceImpl) { |
324 if (descriptor.osName().isPresent() |
313 ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget(); |
325 || descriptor.osArch().isPresent() |
314 if (target != null) |
326 || descriptor.osVersion().isPresent()) |
315 checkTargetConstraints(mn, target); |
327 checkTargetConstraints(descriptor); |
316 } |
|
317 |
|
318 nameToReference.put(mn, mref); |
328 } |
319 } |
329 |
320 |
330 /** |
321 /** |
331 * Check that the module's constraints on the target platform do not |
322 * Check that the module's constraints on the target platform do not |
332 * conflict with the constraints of other modules resolved so far or |
323 * conflict with the constraints of other modules resolved so far or |
333 * modules in parent configurations. |
324 * modules in parent configurations. |
334 */ |
325 */ |
335 private void checkTargetConstraints(ModuleDescriptor descriptor) { |
326 private void checkTargetConstraints(String mn, ModuleTarget target) { |
336 String value = descriptor.osName().orElse(null); |
327 String value = target.osName(); |
337 if (value != null) { |
328 if (value != null) { |
338 if (osName == null) { |
329 if (osName == null) { |
339 osName = value; |
330 osName = value; |
340 } else { |
331 } else { |
341 if (!value.equals(osName)) { |
332 if (!value.equals(osName)) { |
342 failTargetConstraint(descriptor); |
333 failTargetConstraint(mn, target); |
343 } |
334 } |
344 } |
335 } |
345 } |
336 } |
346 value = descriptor.osArch().orElse(null); |
337 value = target.osArch(); |
347 if (value != null) { |
338 if (value != null) { |
348 if (osArch == null) { |
339 if (osArch == null) { |
349 osArch = value; |
340 osArch = value; |
350 } else { |
341 } else { |
351 if (!value.equals(osArch)) { |
342 if (!value.equals(osArch)) { |
352 failTargetConstraint(descriptor); |
343 failTargetConstraint(mn, target); |
353 } |
344 } |
354 } |
345 } |
355 } |
346 } |
356 value = descriptor.osVersion().orElse(null); |
347 } |
357 if (value != null) { |
348 |
358 if (osVersion == null) { |
349 private void failTargetConstraint(String mn, ModuleTarget target) { |
359 osVersion = value; |
350 String s1 = targetAsString(osName, osArch); |
360 } else { |
351 String s2 = targetAsString(target.osName(), target.osArch()); |
361 if (!value.equals(osVersion)) { |
352 findFail("Module %s has constraints on target platform (%s) that" |
362 failTargetConstraint(descriptor); |
353 + " conflict with other modules: %s", mn, s1, s2); |
363 } |
354 } |
364 } |
355 |
365 } |
356 private String targetAsString(ModuleTarget target) { |
366 } |
357 return targetAsString(target.osName(), target.osArch()); |
367 |
358 } |
368 private void failTargetConstraint(ModuleDescriptor md) { |
359 |
369 String s1 = targetAsString(osName, osArch, osVersion); |
360 private String targetAsString(String osName, String osArch) { |
370 String s2 = targetAsString(md); |
|
371 findFail("Module %s has constraints on target platform that conflict" + |
|
372 " with other modules: %s, %s", md.name(), s1, s2); |
|
373 } |
|
374 |
|
375 private String targetAsString(ModuleDescriptor descriptor) { |
|
376 String osName = descriptor.osName().orElse(null); |
|
377 String osArch = descriptor.osArch().orElse(null); |
|
378 String osVersion = descriptor.osVersion().orElse(null); |
|
379 return targetAsString(osName, osArch, osVersion); |
|
380 } |
|
381 |
|
382 private String targetAsString(String osName, String osArch, String osVersion) { |
|
383 return new StringJoiner("-") |
361 return new StringJoiner("-") |
384 .add(Objects.toString(osName, "*")) |
362 .add(Objects.toString(osName, "*")) |
385 .add(Objects.toString(osArch, "*")) |
363 .add(Objects.toString(osArch, "*")) |
386 .add(Objects.toString(osVersion, "*")) |
|
387 .toString(); |
364 .toString(); |
388 } |
365 } |
389 |
366 |
390 |
367 |
391 /** |
368 /** |
710 return m; |
687 return m; |
711 } |
688 } |
712 |
689 |
713 |
690 |
714 /** |
691 /** |
715 * Checks the readability graph to ensure that no two modules export the |
692 * Checks the readability graph to ensure that |
716 * same package to a module. This includes the case where module M has |
693 * <ol> |
717 * a local package P and M reads another module that exports P to M. |
694 * <li><p> A module does not read two or more modules with the same name. |
718 * Also checks the uses/provides of module M to ensure that it reads a |
695 * This includes the case where a module reads another another with the |
719 * module that exports the package of the service type to M. |
696 * same name as itself. </p></li> |
|
697 * <li><p> Two or more modules in the configuration don't export the same |
|
698 * package to a module that reads both. This includes the case where a |
|
699 * module {@code M} containing package {@code p} reads another module |
|
700 * that exports {@code p} to {@code M}. </p></li> |
|
701 * <li><p> A module {@code M} doesn't declare that it "{@code uses p.S}" |
|
702 * or "{@code provides p.S with ...}" but package {@code p} is neither |
|
703 * in module {@code M} nor exported to {@code M} by any module that |
|
704 * {@code M} reads. </p></li> |
|
705 * </ol> |
720 */ |
706 */ |
721 private void checkExportSuppliers(Map<ResolvedModule, Set<ResolvedModule>> graph) { |
707 private void checkExportSuppliers(Map<ResolvedModule, Set<ResolvedModule>> graph) { |
722 |
708 |
723 for (Map.Entry<ResolvedModule, Set<ResolvedModule>> e : graph.entrySet()) { |
709 for (Map.Entry<ResolvedModule, Set<ResolvedModule>> e : graph.entrySet()) { |
724 ModuleDescriptor descriptor1 = e.getKey().descriptor(); |
710 ModuleDescriptor descriptor1 = e.getKey().descriptor(); |
|
711 String name1 = descriptor1.name(); |
|
712 |
|
713 // the names of the modules that are read (including self) |
|
714 Set<String> names = new HashSet<>(); |
|
715 names.add(name1); |
725 |
716 |
726 // the map of packages that are local or exported to descriptor1 |
717 // the map of packages that are local or exported to descriptor1 |
727 Map<String, ModuleDescriptor> packageToExporter = new HashMap<>(); |
718 Map<String, ModuleDescriptor> packageToExporter = new HashMap<>(); |
728 |
719 |
729 // local packages |
720 // local packages |
735 // descriptor1 reads descriptor2 |
726 // descriptor1 reads descriptor2 |
736 Set<ResolvedModule> reads = e.getValue(); |
727 Set<ResolvedModule> reads = e.getValue(); |
737 for (ResolvedModule endpoint : reads) { |
728 for (ResolvedModule endpoint : reads) { |
738 ModuleDescriptor descriptor2 = endpoint.descriptor(); |
729 ModuleDescriptor descriptor2 = endpoint.descriptor(); |
739 |
730 |
|
731 String name2 = descriptor2.name(); |
|
732 if (descriptor2 != descriptor1 && !names.add(name2)) { |
|
733 if (name2.equals(name1)) { |
|
734 resolveFail("Module %s reads another module named %s", |
|
735 name1, name1); |
|
736 } else{ |
|
737 resolveFail("Module %s reads more than one module named %s", |
|
738 name1, name2); |
|
739 } |
|
740 } |
|
741 |
740 if (descriptor2.isAutomatic()) { |
742 if (descriptor2.isAutomatic()) { |
741 // automatic modules read self and export all packages |
743 // automatic modules read self and export all packages |
742 if (descriptor2 != descriptor1){ |
744 if (descriptor2 != descriptor1) { |
743 for (String source : descriptor2.packages()) { |
745 for (String source : descriptor2.packages()) { |
744 ModuleDescriptor supplier |
746 ModuleDescriptor supplier |
745 = packageToExporter.putIfAbsent(source, descriptor2); |
747 = packageToExporter.putIfAbsent(source, descriptor2); |
746 |
748 |
747 // descriptor2 and 'supplier' export source to descriptor1 |
749 // descriptor2 and 'supplier' export source to descriptor1 |