< prev index next >

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 108,117 **** --- 108,123 ---- }, "--add-modules"), new Option<JlinkTask>(true, (task, opt, arg) -> { Path path = Paths.get(arg); task.options.output = path; }, "--output"), + new Option<JlinkTask>(false, (task, opt, arg) -> { + task.options.bindServices = true; + }, "--bind-services"), + new Option<JlinkTask>(false, (task, opt, arg) -> { + task.options.suggestProviders = true; + }, "--suggest-providers", "", true), new Option<JlinkTask>(true, (task, opt, arg) -> { String[] values = arg.split("="); // check values if (values.length != 2 || values[0].isEmpty() || values[1].isEmpty()) { throw taskHelper.newBadArgs("err.launcher.value.format", arg);
*** 139,148 **** --- 145,157 ---- } else { throw taskHelper.newBadArgs("err.unknown.byte.order", arg); } }, "--endian"), new Option<JlinkTask>(false, (task, opt, arg) -> { + task.options.verbose = true; + }, "--verbose", "-v"), + new Option<JlinkTask>(false, (task, opt, arg) -> { task.options.version = true; }, "--version"), new Option<JlinkTask>(true, (task, opt, arg) -> { Path path = Paths.get(arg); if (Files.exists(path)) {
*** 183,211 **** EXIT_ABNORMAL = 4;// terminated abnormally static class OptionsValues { boolean help; String saveoptsfile; boolean version; boolean fullVersion; final List<Path> modulePath = new ArrayList<>(); final Set<String> limitMods = new HashSet<>(); final Set<String> addMods = new HashSet<>(); Path output; final Map<String, String> launchers = new HashMap<>(); Path packagedModulesPath; ByteOrder endian = ByteOrder.nativeOrder(); boolean ignoreSigning = false; } int run(String[] args) { if (log == null) { setLog(new PrintWriter(System.out, true), new PrintWriter(System.err, true)); } try { ! optionsHelper.handleOptionsNoUnhandled(this, args); if (options.help) { optionsHelper.showHelp(PROGNAME); return EXIT_OK; } if (optionsHelper.shouldListPlugins()) { --- 192,227 ---- EXIT_ABNORMAL = 4;// terminated abnormally static class OptionsValues { boolean help; String saveoptsfile; + boolean verbose; boolean version; boolean fullVersion; final List<Path> modulePath = new ArrayList<>(); final Set<String> limitMods = new HashSet<>(); final Set<String> addMods = new HashSet<>(); Path output; final Map<String, String> launchers = new HashMap<>(); Path packagedModulesPath; ByteOrder endian = ByteOrder.nativeOrder(); boolean ignoreSigning = false; + boolean bindServices = false; + boolean suggestProviders = false; } int run(String[] args) { if (log == null) { setLog(new PrintWriter(System.out, true), new PrintWriter(System.err, true)); } try { ! List<String> remaining = optionsHelper.handleOptions(this, args); ! if (remaining.size() > 0 && !options.suggestProviders) { ! throw taskHelper.newBadArgs("err.orphan.arguments", toString(remaining)) ! .showUsage(true); ! } if (options.help) { optionsHelper.showHelp(PROGNAME); return EXIT_OK; } if (optionsHelper.shouldListPlugins()) {
*** 215,236 **** if (options.version || options.fullVersion) { taskHelper.showVersion(options.fullVersion); return EXIT_OK; } ! if (taskHelper.getExistingImage() == null) { ! if (options.modulePath.isEmpty()) { ! throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true); ! } ! createImage(); ! } else { postProcessOnly(taskHelper.getExistingImage()); } if (options.saveoptsfile != null) { Files.write(Paths.get(options.saveoptsfile), getSaveOpts().getBytes()); } return EXIT_OK; } catch (PluginException | IllegalArgumentException | UncheckedIOException |IOException | FindException | ResolutionException e) { log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage()); --- 231,259 ---- if (options.version || options.fullVersion) { taskHelper.showVersion(options.fullVersion); return EXIT_OK; } ! if (taskHelper.getExistingImage() != null) { postProcessOnly(taskHelper.getExistingImage()); + return EXIT_OK; + } + + if (options.modulePath.isEmpty()) { + throw taskHelper.newBadArgs("err.modulepath.must.be.specified") + .showUsage(true); } + JlinkConfiguration config = initJlinkConfig(); + if (options.suggestProviders) { + suggestProviders(config, remaining); + } else { + createImage(config); if (options.saveoptsfile != null) { Files.write(Paths.get(options.saveoptsfile), getSaveOpts().getBytes()); } + } return EXIT_OK; } catch (PluginException | IllegalArgumentException | UncheckedIOException |IOException | FindException | ResolutionException e) { log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage());
*** 264,292 **** throws Exception { Objects.requireNonNull(config); Objects.requireNonNull(config.getOutput()); plugins = plugins == null ? new PluginsConfiguration() : plugins; - if (config.getModulepaths().isEmpty()) { - throw new IllegalArgumentException("Empty module paths"); - } - - ModuleFinder finder = newModuleFinder(config.getModulepaths(), - config.getLimitmods(), - config.getModules()); - - if (config.getModules().isEmpty()) { - throw new IllegalArgumentException("No modules to add"); - } - // First create the image provider ImageProvider imageProvider = ! createImageProvider(finder, ! config.getModules(), ! config.getByteOrder(), null, IGNORE_SIGNING_DEFAULT, null); // Then create the Plugin Stack ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins); --- 287,303 ---- throws Exception { Objects.requireNonNull(config); Objects.requireNonNull(config.getOutput()); plugins = plugins == null ? new PluginsConfiguration() : plugins; // First create the image provider ImageProvider imageProvider = ! createImageProvider(config, null, IGNORE_SIGNING_DEFAULT, + false, + false, null); // Then create the Plugin Stack ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
*** 317,384 **** postProcessImage(img, config.getPlugins()); } // the token for "all modules on the module path" private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; ! private void createImage() throws Exception { ! if (options.output == null) { ! throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true); ! } ! if (options.addMods.isEmpty()) { throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules") .showUsage(true); } Set<String> roots = new HashSet<>(); for (String mod : options.addMods) { if (mod.equals(ALL_MODULE_PATH)) { ! ModuleFinder finder = modulePathFinder(); finder.findAll() .stream() .map(ModuleReference::descriptor) .map(ModuleDescriptor::name) .forEach(mn -> roots.add(mn)); } else { roots.add(mod); } } ! ModuleFinder finder = newModuleFinder(options.modulePath, options.limitMods, ! roots); // First create the image provider ! ImageProvider imageProvider = createImageProvider(finder, ! roots, ! options.endian, options.packagedModulesPath, options.ignoreSigning, log); // Then create the Plugin Stack ! ImagePluginStack stack = ImagePluginConfiguration. ! parseConfiguration(taskHelper.getPluginsConfig(options.output, options.launchers)); //Ask the stack to proceed stack.operate(imageProvider); } - /** - * Returns a module finder to find the observable modules specified in - * the --module-path and --limit-modules options - */ - private ModuleFinder modulePathFinder() { - Path[] entries = options.modulePath.toArray(new Path[0]); - ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries); - if (!options.limitMods.isEmpty()) { - finder = limitFinder(finder, options.limitMods, Collections.emptySet()); - } - return finder; - } - /* * Returns a module finder of the given module path that limits * the observable modules to those in the transitive closure of * the modules specified in {@code limitMods} plus other modules * specified in the {@code roots} set. --- 328,393 ---- postProcessImage(img, config.getPlugins()); } // the token for "all modules on the module path" private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; ! private JlinkConfiguration initJlinkConfig() throws BadArgs { if (options.addMods.isEmpty()) { throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules") .showUsage(true); } Set<String> roots = new HashSet<>(); for (String mod : options.addMods) { if (mod.equals(ALL_MODULE_PATH)) { ! Path[] entries = options.modulePath.toArray(new Path[0]); ! ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries); ! if (!options.limitMods.isEmpty()) { ! // finder for the observable modules specified in ! // the --module-path and --limit-modules options ! finder = limitFinder(finder, options.limitMods, Collections.emptySet()); ! } ! ! // all observable modules are roots finder.findAll() .stream() .map(ModuleReference::descriptor) .map(ModuleDescriptor::name) .forEach(mn -> roots.add(mn)); } else { roots.add(mod); } } ! return new JlinkConfiguration(options.output, ! options.modulePath, ! roots, options.limitMods, ! options.endian); ! } + private void createImage(JlinkConfiguration config) throws Exception { + if (options.output == null) { + throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true); + } // First create the image provider ! ImageProvider imageProvider = createImageProvider(config, options.packagedModulesPath, options.ignoreSigning, + options.bindServices, + options.verbose, log); // Then create the Plugin Stack ! ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration( ! taskHelper.getPluginsConfig(options.output, options.launchers)); //Ask the stack to proceed stack.operate(imageProvider); } /* * Returns a module finder of the given module path that limits * the observable modules to those in the transitive closure of * the modules specified in {@code limitMods} plus other modules * specified in the {@code roots} set.
*** 403,428 **** throw new InternalError(m + " does not have a location"); URI uri = ouri.get(); return Paths.get(uri); } ! private static ImageProvider createImageProvider(ModuleFinder finder, ! Set<String> roots, ! ByteOrder order, Path retainModulesPath, boolean ignoreSigning, PrintWriter log) throws IOException { ! if (roots.isEmpty()) { ! throw new IllegalArgumentException("empty modules and limitmods"); ! } ! Configuration cf = Configuration.empty() ! .resolve(finder, ! ModuleFinder.of(), ! roots); // emit a warning for any incubating modules in the configuration if (log != null) { String im = cf.modules() .stream() --- 412,447 ---- throw new InternalError(m + " does not have a location"); URI uri = ouri.get(); return Paths.get(uri); } ! ! private static ImageProvider createImageProvider(JlinkConfiguration config, Path retainModulesPath, boolean ignoreSigning, + boolean bindService, + boolean verbose, PrintWriter log) throws IOException { ! Configuration cf = bindService ? config.resolveAndBind() ! : config.resolve(); ! if (verbose && log != null) { ! // print modules to be linked in ! cf.modules().stream() ! .sorted(Comparator.comparing(ResolvedModule::name)) ! .forEach(rm -> log.format("module %s (%s)%n", ! rm.name(), rm.reference().location().get())); ! ! // print provider info ! Set<ModuleReference> references = cf.modules().stream() ! .map(ResolvedModule::reference).collect(Collectors.toSet()); ! ! log.format("%n%s:%n", taskHelper.getMessage("providers.header")); ! printProviders(references, log); ! } // emit a warning for any incubating modules in the configuration if (log != null) { String im = cf.modules() .stream()
*** 436,453 **** log.println("WARNING: Using incubator modules: " + im); } Map<String, Path> mods = cf.modules().stream() .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation)); ! return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning); } /* * Returns a ModuleFinder that limits observability to the given root * modules, their transitive dependences, plus a set of other modules. */ ! private static ModuleFinder limitFinder(ModuleFinder finder, Set<String> roots, Set<String> otherMods) { // resolve all root modules Configuration cf = Configuration.empty() --- 455,472 ---- log.println("WARNING: Using incubator modules: " + im); } Map<String, Path> mods = cf.modules().stream() .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation)); ! return new ImageHelper(cf, mods, config.getByteOrder(), retainModulesPath, ignoreSigning); } /* * Returns a ModuleFinder that limits observability to the given root * modules, their transitive dependences, plus a set of other modules. */ ! public static ModuleFinder limitFinder(ModuleFinder finder, Set<String> roots, Set<String> otherMods) { // resolve all root modules Configuration cf = Configuration.empty()
*** 482,491 **** --- 501,646 ---- return mrefs; } }; } + /* + * Returns a map of each service type to the modules that use it + */ + private static Map<String, Set<String>> uses(Set<ModuleReference> modules) { + // collects the services used by the modules and print uses + Map<String, Set<String>> uses = new HashMap<>(); + modules.stream() + .map(ModuleReference::descriptor) + .forEach(md -> + md.uses().stream().forEach(s -> + uses.computeIfAbsent(s, _k -> new HashSet<>()).add(md.name())) + ); + return uses; + } + + private static void printProviders(Set<ModuleReference> modules, + PrintWriter log) { + printProviders(modules, uses(modules), log); + } + + /* + * Prints the providers that are used by the services specified in + * the given modules. + * + * The specified uses maps a service type name to the modules + * using the service type and that may or may not be present + * the given modules. + */ + private static void printProviders(Set<ModuleReference> modules, + Map<String, Set<String>> uses, + PrintWriter log) { + if (modules.isEmpty()) + return; + + // Build a map of a service type to the provider modules + Map<String, Set<ModuleDescriptor>> providers = new HashMap<>(); + modules.stream() + .map(ModuleReference::descriptor) + .forEach(md -> { + md.provides().stream() + .filter(p -> uses.containsKey(p.service())) + .forEach(p -> providers.computeIfAbsent(p.service(), _k -> new HashSet<>()) + .add(md)); + }); + + // print the providers of the service types used by the specified modules + // sorted by the service type name and then provider's module name + providers.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> { + String service = e.getKey(); + e.getValue().stream() + .sorted(Comparator.comparing(ModuleDescriptor::name)) + .forEach(md -> + md.provides().stream() + .filter(p -> p.service().equals(service)) + .forEach(p -> log.format(" module %s provides %s, used by %s%n", + md.name(), p.service(), + uses.get(p.service()).stream() + .sorted() + .collect(Collectors.joining(",")))) + ); + }); + } + + private void suggestProviders(JlinkConfiguration config, List<String> args) + throws BadArgs + { + if (args.size() > 1) { + throw taskHelper.newBadArgs("err.orphan.argument", + toString(args.subList(1, args.size()))) + .showUsage(true); + } + + if (options.bindServices) { + log.println(taskHelper.getMessage("no.suggested.providers")); + return; + } + + ModuleFinder finder = config.finder(); + if (args.isEmpty()) { + // print providers used by the modules resolved without service binding + Configuration cf = config.resolve(); + Set<ModuleReference> mrefs = cf.modules().stream() + .map(ResolvedModule::reference) + .collect(Collectors.toSet()); + + // print uses of the modules that would be linked into the image + mrefs.stream() + .sorted(Comparator.comparing(mref -> mref.descriptor().name())) + .forEach(mref -> { + ModuleDescriptor md = mref.descriptor(); + log.format("module %s located (%s)%n", md.name(), + mref.location().get()); + md.uses().stream().sorted() + .forEach(s -> log.format(" uses %s%n", s)); + }); + + log.format("%n%s:%n", taskHelper.getMessage("suggested.providers.header")); + printProviders(finder.findAll(), uses(mrefs), log); + + } else { + // comma-separated service types, if specified + Set<String> names = Stream.of(args.get(0).split(",")) + .collect(Collectors.toSet()); + // find the modules that provide the specified service + Set<ModuleReference> mrefs = finder.findAll().stream() + .filter(mref -> mref.descriptor().provides().stream() + .map(ModuleDescriptor.Provides::service) + .anyMatch(names::contains)) + .collect(Collectors.toSet()); + + // the specified services may or may not be in the modules that + // would be linked in. So find uses declared in all observable modules + Map<String, Set<String>> uses = uses(finder.findAll()); + + // check if any name given on the command line are unused service + mrefs.stream() + .flatMap(mref -> mref.descriptor().provides().stream() + .map(ModuleDescriptor.Provides::service)) + .forEach(names::remove); + if (!names.isEmpty()) { + log.println(taskHelper.getMessage("warn.unused.services", + toString(names))); + } + + log.format("%n%s:%n", taskHelper.getMessage("suggested.providers.header")); + printProviders(mrefs, uses, log); + } + } + + private static String toString(Collection<String> collection) { + return collection.stream().sorted() + .collect(Collectors.joining(",")); + } + private String getSaveOpts() { StringBuilder sb = new StringBuilder(); sb.append('#').append(new Date()).append("\n"); for (String c : optionsHelper.getInputCommand()) { sb.append(c).append(" ");
< prev index next >