private boolean checkModuleInfo(byte[] moduleInfoBytes, Set<String> entries) throws IOException { boolean ok = true; if (moduleInfoBytes != null) { // no root module-info.class if null try { // ModuleDescriptor.read() checks open/exported pkgs vs packages ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes)); // A module must have the implementation class of the services it 'provides'. if (md.provides().stream().map(Provides::providers).flatMap(List::stream) .filter(p -> !entries.contains(toBinaryName(p))) .peek(p -> fatalError(formatMsg("error.missing.provider", p))) .count() != 0) { ok = false; } } catch (InvalidModuleDescriptorException x) { fatalError(x.getMessage()); ok = false; } } return ok; }
private void printModuleInfo(PrintWriter writer, ModuleDescriptor descriptor) { writer.format("module %s {%n", descriptor.name()); Map<String, Module> modules = configuration.getModules(); // first print the JDK modules descriptor.requires().stream() .filter(req -> !req.name().equals("java.base")) // implicit requires .sorted(Comparator.comparing(Requires::name)) .forEach(req -> writer.format(" requires %s;%n", req)); descriptor.exports().stream() .peek(exp -> { if (exp.targets().size() > 0) throw new InternalError(descriptor.name() + " qualified exports: " + exp); }) .sorted(Comparator.comparing(Exports::source)) .forEach(exp -> writer.format(" exports %s;%n", exp.source())); descriptor.provides().values().stream() .sorted(Comparator.comparing(Provides::service)) .forEach(p -> p.providers().stream() .sorted() .forEach(impl -> writer.format(" provides %s with %s;%n", p.service(), impl))); writer.println("}"); }
/** * Returns a new {@code ModuleDescriptor} instance. */ ModuleDescriptor newModuleDescriptor(String name, boolean automatic, boolean synthetic, Set<Requires> requires, Set<String> uses, Set<Exports> exports, Map<String, Provides> provides, Version version, String mainClass, String osName, String osArch, String osVersion, Set<String> conceals, Set<String> packages, ModuleHashes hashes);
private boolean checkServices(byte[] moduleInfoBytes) throws IOException { ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes)); Set<String> missing = md.provides() .values() .stream() .map(Provides::providers) .flatMap(Set::stream) .filter(p -> !jarEntries.contains(toBinaryName(p))) .collect(Collectors.toSet()); if (missing.size() > 0) { missing.stream().forEach(s -> fatalError(formatMsg("error.missing.provider", s))); return false; } return true; }
public void testProvides() { Set<String> pns = new HashSet<>(); pns.add("q.P1"); pns.add("q.P2"); Map<String, Provides> map = new Builder("foo") .provides("p.S", pns) .build() .provides(); assertTrue(map.size() == 1); Provides p = map.values().iterator().next(); assertEquals(p, p); assertTrue(p.providers().size() == 2); assertTrue(p.providers().contains("q.P1")); assertTrue(p.providers().contains("q.P2")); }
private void printModuleInfo(PrintWriter writer, ModuleDescriptor md) { writer.format("%smodule %s {%n", open ? "open " : "", md.name()); Map<String, Module> modules = configuration.getModules(); // first print requires Set<Requires> reqs = md.requires().stream() .filter(req -> !req.name().equals("java.base") && req.modifiers().isEmpty()) .collect(Collectors.toSet()); reqs.stream() .sorted(Comparator.comparing(Requires::name)) .forEach(req -> writer.format(" requires %s;%n", toString(req.modifiers(), req.name()))); if (!reqs.isEmpty()) { writer.println(); } // requires transitive reqs = md.requires().stream() .filter(req -> !req.name().equals("java.base") && !req.modifiers().isEmpty()) .collect(Collectors.toSet()); reqs.stream() .sorted(Comparator.comparing(Requires::name)) .forEach(req -> writer.format(" requires %s;%n", toString(req.modifiers(), req.name()))); if (!reqs.isEmpty()) { writer.println(); } if (!open) { md.exports().stream() .peek(exp -> { if (exp.isQualified()) throw new InternalError(md.name() + " qualified exports: " + exp); }) .sorted(Comparator.comparing(Exports::source)) .forEach(exp -> writer.format(" exports %s;%n", exp.source())); if (!md.exports().isEmpty()) { writer.println(); } } md.provides().stream() .sorted(Comparator.comparing(Provides::service)) .map(p -> p.providers().stream() .map(impl -> " " + impl.replace('$', '.')) .collect(joining(",\n", String.format(" provides %s with%n", p.service().replace('$', '.')), ";"))) .forEach(writer::println); if (!md.provides().isEmpty()) { writer.println(); } writer.println("}"); }
/** * Returns a new {@code ModuleDescriptor} instance. */ ModuleDescriptor newModuleDescriptor(String name, Version version, Set<ModuleDescriptor.Modifier> ms, Set<Requires> requires, Set<Exports> exports, Set<Opens> opens, Set<String> uses, Set<Provides> provides, Set<String> packages, String mainClass, int hashCode);
private Provides provides(String st, String pc) { return ModuleDescriptor.newModule("foo") .provides(st, List.of(pc)) .build() .provides() .iterator() .next(); }
private Provides provides(String st, List<String> pns) { return ModuleDescriptor.newModule("foo") .provides(st, pns) .build() .provides() .iterator() .next(); }
public void testProvidesWithProvides() { Provides p1 = provides("p.S", "q.S1"); ModuleDescriptor descriptor = ModuleDescriptor.newModule("m") .provides(p1) .build(); Provides p2 = descriptor.provides().iterator().next(); assertEquals(p1, p2); }
public void testProvides() { Set<Provides> set = ModuleDescriptor.newModule("foo") .provides("p.S", List.of("q.P1", "q.P2")) .build() .provides(); assertTrue(set.size() == 1); Provides p = set.iterator().next(); assertEquals(p, p); assertEquals(p.service(), "p.S"); assertTrue(p.providers().size() == 2); assertEquals(p.providers().get(0), "q.P1"); assertEquals(p.providers().get(1), "q.P2"); }
public void testProvidesCompare() { Provides p1 = provides("p.S", "q.S1"); Provides p2 = provides("p.S", "q.S1"); assertEquals(p1, p2); assertTrue(p1.hashCode() == p2.hashCode()); assertTrue(p1.compareTo(p2) == 0); assertTrue(p2.compareTo(p1) == 0); }
public void testProvidesCompareWithDifferentService() { Provides p1 = provides("p.S2", "q.S1"); Provides p2 = provides("p.S1", "q.S1"); assertNotEquals(p1, p2); assertTrue(p1.compareTo(p2) == 1); assertTrue(p2.compareTo(p1) == -1); }
public void testProvidesCompareWithDifferentProviders1() { Provides p1 = provides("p.S", "q.S2"); Provides p2 = provides("p.S", "q.S1"); assertNotEquals(p1, p2); assertTrue(p1.compareTo(p2) == 1); assertTrue(p2.compareTo(p1) == -1); }
public void testProvidesCompareWithDifferentProviders2() { Provides p1 = provides("p.S", List.of("q.S1", "q.S2")); Provides p2 = provides("p.S", "q.S1"); assertNotEquals(p1, p2); assertTrue(p1.compareTo(p2) == 1); assertTrue(p2.compareTo(p1) == -1); }
public static void main(String[] args) throws Exception { Module xml = ModuleLayer.boot().findModule("java.xml").get(); Set<String> allServices = new HashSet<>(Arrays.asList(expectedAllServices)); if (!allServices.equals(xml.getDescriptor().uses())) throw new AssertionError("Expect xml module uses: " + allServices + " But actually uses: " + xml.getDescriptor().uses()); long violationCount = Stream.of(args) .map(xmlProviderName -> ModuleLayer.boot().findModule(xmlProviderName).get()) .mapToLong( // services provided by the implementation in provider module provider -> provider.getDescriptor().provides().stream() .map(Provides::service) .filter(serviceName -> { allServices.remove(serviceName); // remove service provided by // customized module from allServices return !belongToModule(serviceName, instantiateXMLService(serviceName), provider); }).count()) .sum(); // the remaining services should be provided by the default implementation violationCount += allServices.stream() .filter(serviceName -> !belongToModule(serviceName, instantiateXMLService(serviceName), xml)) .count(); if (violationCount > 0) throw new AssertionError(violationCount + " services are not provided by expected module"); }
private Provides provides(String st, String pc) { return new Builder("foo") .provides("p.S", pc) .build() .provides() .values() .iterator() .next(); }
@Test(expectedExceptions = IllegalStateException.class ) public void testProvidesWithDuplicateProvides() { Provides p = provides("p.S", "q.S2"); ModuleDescriptor.newModule("m").provides("p.S", List.of("q.S1")).provides(p); }
@Test(expectedExceptions = NullPointerException.class ) public void testProvidesWithNullProvides() { ModuleDescriptor.newModule("foo").provides((Provides) null); }
private void printModuleDescriptor(InputStream entryInputStream) throws IOException { ModuleDescriptor md = ModuleDescriptor.read(entryInputStream); StringBuilder sb = new StringBuilder(); sb.append("\n").append(md.toNameAndVersion()); md.requires().stream() .sorted(Comparator.comparing(Requires::name)) .forEach(r -> { sb.append("\n requires "); if (!r.modifiers().isEmpty()) sb.append(toString(r.modifiers())).append(" "); sb.append(r.name()); }); md.uses().stream().sorted() .forEach(p -> sb.append("\n uses ").append(p)); md.exports().stream() .sorted(Comparator.comparing(Exports::source)) .forEach(p -> sb.append("\n exports ").append(p)); md.conceals().stream().sorted() .forEach(p -> sb.append("\n conceals ").append(p)); md.provides().values().stream() .sorted(Comparator.comparing(Provides::service)) .forEach(p -> sb.append("\n provides ").append(p.service()) .append(" with ") .append(toString(p.providers()))); md.mainClass().ifPresent(v -> sb.append("\n main-class " + v)); md.osName().ifPresent(v -> sb.append("\n operating-system-name " + v)); md.osArch().ifPresent(v -> sb.append("\n operating-system-architecture " + v)); md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v)); JLMA.hashes(md).ifPresent(hashes -> hashes.names().stream().sorted().forEach( mod -> sb.append("\n hashes ").append(mod).append(" ") .append(hashes.algorithm()).append(" ") .append(hashes.hashFor(mod)))); output(sb.toString()); }
private boolean printModuleDescriptor(InputStream in) throws IOException { final String mi = Section.CLASSES.jmodDir() + "/" + MODULE_INFO; try (BufferedInputStream bis = new BufferedInputStream(in); ZipInputStream zis = new ZipInputStream(bis)) { ZipEntry e; while ((e = zis.getNextEntry()) != null) { if (e.getName().equals(mi)) { ModuleDescriptor md = ModuleDescriptor.read(zis); StringBuilder sb = new StringBuilder(); sb.append("\n").append(md.toNameAndVersion()); md.requires().stream() .sorted(Comparator.comparing(Requires::name)) .forEach(r -> { sb.append("\n requires "); if (!r.modifiers().isEmpty()) sb.append(toString(r.modifiers())).append(" "); sb.append(r.name()); }); md.uses().stream().sorted() .forEach(s -> sb.append("\n uses ").append(s)); md.exports().stream() .sorted(Comparator.comparing(Exports::source)) .forEach(p -> sb.append("\n exports ").append(p)); md.conceals().stream().sorted() .forEach(p -> sb.append("\n conceals ").append(p)); md.provides().values().stream() .sorted(Comparator.comparing(Provides::service)) .forEach(p -> sb.append("\n provides ").append(p.service()) .append(" with ") .append(toString(p.providers()))); md.mainClass().ifPresent(v -> sb.append("\n main-class " + v)); md.osName().ifPresent(v -> sb.append("\n operating-system-name " + v)); md.osArch().ifPresent(v -> sb.append("\n operating-system-architecture " + v)); md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v)); JLMA.hashes(md).ifPresent( hashes -> hashes.names().stream().sorted().forEach( mod -> sb.append("\n hashes ").append(mod).append(" ") .append(hashes.algorithm()).append(" ") .append(hashes.hashFor(mod)))); out.println(sb.toString()); return true; } } } return false; }
public void testProvidesWithProvides() { Provides p1 = provides("p.S", "q.S1"); ModuleDescriptor descriptor = new Builder("m").provides(p1).build(); Provides p2 = descriptor.provides().get("p.S"); assertEquals(p1, p2); }
@Test(expectedExceptions = IllegalStateException.class ) public void testProvidesWithDuplicateProvides() { Provides p = provides("p.S", "q.S2"); new Builder("m").provides("p.S", "q.S1").provides(p); }
@Test(expectedExceptions = NullPointerException.class ) public void testProvidesWithNullProvides() { new Builder("foo").provides((Provides)null); }
private ModuleRevisionBuilder createBuilder(ModuleReference ref) { ModuleDescriptor desc = ref.descriptor(); ModuleRevisionBuilder builder = new ModuleRevisionBuilder(); builder.setSymbolicName(desc.name()); Version version = desc.version().map((v) -> { try { return Version.valueOf(v.toString()); } catch (IllegalArgumentException e) { return Version.emptyVersion; } }).orElse(Version.emptyVersion); builder.setVersion(version); // add bundle and identity capabilities, do not create host capability for JPMS builder.addCapability( BundleNamespace.BUNDLE_NAMESPACE, Map.of(), Map.of( BundleNamespace.BUNDLE_NAMESPACE, desc.name(), BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE, version)); builder.addCapability( IdentityNamespace.IDENTITY_NAMESPACE, Map.of(), Map.of( IdentityNamespace.IDENTITY_NAMESPACE, desc.name(), IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, version)); for(Exports exports : desc.exports()) { // TODO map targets to x-friends directive. builder.addCapability( PackageNamespace.PACKAGE_NAMESPACE, Map.of(), Map.of(PackageNamespace.PACKAGE_NAMESPACE, exports.source())); } for(Provides provides : desc.provides()) { builder.addCapability( JpmsServiceNamespace.JPMS_SERVICE_NAMESPACE, Map.of(), Map.of( JpmsServiceNamespace.JPMS_SERVICE_NAMESPACE, provides.service(), JpmsServiceNamespace.CAPABILITY_PROVIDES_WITH, provides.providers())); } for (Requires requires : desc.requires()) { Map<String, String> directives = new HashMap<>(); // determine the resolution value based on the STATIC modifier String resolution = requires.modifiers().contains(Requires.Modifier.STATIC) ? Namespace.RESOLUTION_OPTIONAL : Namespace.RESOLUTION_MANDATORY; directives.put(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE, resolution); // determine the visibility value based on the TRANSITIVE modifier String visibility = requires.modifiers().contains(Requires.Modifier.TRANSITIVE) ? BundleNamespace.VISIBILITY_REEXPORT : BundleNamespace.VISIBILITY_PRIVATE; directives.put(BundleNamespace.REQUIREMENT_VISIBILITY_DIRECTIVE, visibility); // create a bundle filter based on the requires name directives.put(Namespace.REQUIREMENT_FILTER_DIRECTIVE, "(" + BundleNamespace.BUNDLE_NAMESPACE + "=" + requires.name() + ")"); builder.addRequirement(BundleNamespace.BUNDLE_NAMESPACE, directives, Collections.emptyMap()); } for(String uses : desc.uses()) { builder.addRequirement(JpmsServiceNamespace.JPMS_SERVICE_NAMESPACE, Map.of(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE, Namespace.RESOLUTION_OPTIONAL, Namespace.REQUIREMENT_FILTER_DIRECTIVE, "(" + JpmsServiceNamespace.JPMS_SERVICE_NAMESPACE + "=" + uses + ")"), Map.of(JpmsServiceNamespace.JPMS_SERVICE_NAMESPACE, uses)); } return builder; }
private String installBootModule(Module module, BundleContext context) throws IOException, BundleException { String bootLocation = bootModuleLocationPrefix + module.getName(); if (context.getBundle(bootLocation) == null) { Manifest m = new Manifest(); Attributes mainAttrs = m.getMainAttributes(); mainAttrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); mainAttrs.putValue(Constants.BUNDLE_MANIFESTVERSION, "2"); mainAttrs.putValue(Constants.BUNDLE_SYMBOLICNAME, module.getName() + "; " + LayerFactoryImpl.BOOT_JPMS_MODULE + "=true"); mainAttrs.putValue(Constants.BUNDLE_VERSION, module.getDescriptor().version().map((v) -> { String s = v.toString(); int indexDash = s.indexOf('-'); if (indexDash >= 0) { s = s.substring(0, indexDash); } return s; }).orElse("0.0.0")); StringBuilder exportPackages = new StringBuilder(); for (Exports exports : module.getDescriptor().exports()) { if (exports.targets().isEmpty() && !exports.source().startsWith("java.")) { if (exportPackages.length() > 0) { exportPackages.append(", "); } exportPackages.append(exports.source()); exportPackages.append("; mandatory:=").append(LayerFactoryImpl.BOOT_JPMS_MODULE); exportPackages.append("; ").append(LayerFactoryImpl.BOOT_JPMS_MODULE).append("=true"); } } if (exportPackages.length() > 0) { mainAttrs.putValue(Constants.EXPORT_PACKAGE, exportPackages.toString()); } StringBuilder provideCapability = new StringBuilder(); for(Provides provides : module.getDescriptor().provides()) { if (provideCapability.length() > 0) { provideCapability.append(", "); } provideCapability.append(JpmsServiceNamespace.JPMS_SERVICE_NAMESPACE).append("; "); provideCapability.append(JpmsServiceNamespace.JPMS_SERVICE_NAMESPACE).append("=").append(provides.service()).append("; "); provideCapability.append(JpmsServiceNamespace.CAPABILITY_PROVIDES_WITH).append(":List<String>").append("=\""); for (String provider : provides.providers()) { provideCapability.append(provider).append(','); } provideCapability.setLength(provideCapability.length() - 1); provideCapability.append('\"'); provideCapability.append("; ").append(LayerFactoryImpl.BOOT_JPMS_MODULE).append("=true"); } if (provideCapability.length() > 0) { mainAttrs.putValue(Constants.PROVIDE_CAPABILITY, provideCapability.toString()); } mainAttrs.putValue(Constants.REQUIRE_BUNDLE, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); JarOutputStream jarOut = new JarOutputStream(bytes, m); jarOut.close(); context.installBundle(bootLocation, new ByteArrayInputStream(bytes.toByteArray())); } return bootLocation; }
private static boolean containsAtLeastAService(ModuleReference ref, List<String> serviceNames) { Set<String> provides = ref.descriptor().provides().stream().map(Provides::service).collect(Collectors.toSet()); return serviceNames.stream().anyMatch(provides::contains); }
public static ModuleDescriptor mergeModuleDescriptor(ModuleDescriptor sourceModule, ModuleDescriptor testModule) { boolean open = sourceModule.isOpen() || testModule.isOpen(); Set<Modifier> moduleModifiers = open? Set.of(Modifier.OPEN): Set.of(); Builder builder = ModuleDescriptor.newModule(testModule.name(), moduleModifiers); HashMap<String, Set<Requires.Modifier>> requires = merge(ModuleDescriptor::requires, Requires::name, Requires::modifiers, ModuleHelper::mergeRequiresModifiers, sourceModule, testModule); HashMap<String, Set<String>> exports = merge(ModuleDescriptor::exports, Exports::source, Exports::targets, ModuleHelper::mergeRestrictions, sourceModule, testModule); HashMap<String, Boolean> packages = merge(ModuleDescriptor::packages, x -> x, x -> true, (_1, _2) -> true, sourceModule, testModule); HashMap<String, Set<String>> opens = merge(ModuleDescriptor::opens, Opens::source, Opens::targets, ModuleHelper::mergeRestrictions, sourceModule, testModule); HashMap<String, Boolean> uses = merge(ModuleDescriptor::uses, x -> x, x -> true, (_1, _2) -> true, sourceModule, testModule); HashMap<String, Set<String>> provides = merge(ModuleDescriptor::provides, Provides::service, p -> new HashSet<>(p.providers()), ModuleHelper::mergeAll, sourceModule, testModule); requires.forEach((name, modifiers) -> builder.requires(modifiers, name)); exports.forEach((source, target) -> { if (target.isEmpty()) { builder.exports(Set.of(), source); } else { builder.exports(source, target); } }); packages.keySet().removeAll(exports.keySet()); builder.packages(packages.keySet()); opens.forEach((source, target) -> { if (target.isEmpty()) { builder.opens(Set.of(), source); } else { builder.opens(source, target); } }); uses.keySet().forEach(builder::uses); provides.forEach((service, providers) -> builder.provides(service, providers.stream().collect(toList()))); return builder.build(); }
/** * Returns a {@link Provides} for a service with a given list of * implementation classes. */ public static Provides newProvides(String st, List<String> pcs) { return JLMA.newProvides(st, pcs); }
/** * Returns a {@code ModuleDescriptor.Provides} * of the given service name and providers. */ Provides newProvides(String service, List<String> providers);
/** * Returns a {@code ModuleDescriptor.Provides} * of the given service name and providers. */ Provides newProvides(String service, Set<String> providers);