JDK 11 jdk.jlink.jmod - JLink Tool

JDK 11 jdk.jlink.jmod is the JMOD file for JDK 11 JLink tool, which can be invoked by the "jlink" command.

JDK 11 JLink tool compiled class files are stored in \fyicenter\jdk-11.0.1\jmods\jdk.jlink.jmod.

JDK 11 JLink tool compiled class files are also linked and stored in the \fyicenter\jdk-11.0.1\lib\modules JImage file.

JDK 11 JLink tool source code files are stored in \fyicenter\jdk-11.0.1\lib\src.zip\jdk.jlink.

You can click and view the content of each source code file in the list below.

✍: FYIcenter

jdk/tools/jlink/internal/TaskHelper.java

/*
 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package jdk.tools.jlink.internal;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin;
import jdk.tools.jlink.plugin.Plugin;
import jdk.tools.jlink.plugin.Plugin.Category;
import jdk.tools.jlink.builder.DefaultImageBuilder;
import jdk.tools.jlink.builder.ImageBuilder;
import jdk.tools.jlink.plugin.PluginException;
import jdk.tools.jlink.internal.Jlink.PluginsConfiguration;
import jdk.tools.jlink.internal.plugins.PluginsResourceBundle;
import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
import jdk.internal.module.ModulePath;

/**
 *
 * JLink and JImage tools shared helper.
 */
public final class TaskHelper {

    public static final String JLINK_BUNDLE = "jdk.tools.jlink.resources.jlink";
    public static final String JIMAGE_BUNDLE = "jdk.tools.jimage.resources.jimage";

    private static final String DEFAULTS_PROPERTY = "jdk.jlink.defaults";

    public final class BadArgs extends Exception {

        static final long serialVersionUID = 8765093759964640721L;

        private BadArgs(String key, Object... args) {
            super(bundleHelper.getMessage(key, args));
            this.key = key;
            this.args = args;
        }

        public BadArgs showUsage(boolean b) {
            showUsage = b;
            return this;
        }
        public final String key;
        public final Object[] args;
        public boolean showUsage;
    }

    public static class Option<T> implements Comparable<T> {
        public interface Processing<T> {

            void process(T task, String opt, String arg) throws BadArgs;
        }

        final boolean hasArg;
        final Processing<T> processing;
        final boolean hidden;
        final String name;
        final String shortname;
        final String shortname2;
        final boolean terminalOption;

        public Option(boolean hasArg,
                      Processing<T> processing,
                      boolean hidden,
                      String name,
                      String shortname,
                      String shortname2,
                      boolean isTerminal)
        {
            if (!name.startsWith("--")) {
                throw new RuntimeException("option name missing --, " + name);
            }
            if (!shortname.isEmpty() && !shortname.startsWith("-")) {
                throw new RuntimeException("short name missing -, " + shortname);
            }

            this.hasArg = hasArg;
            this.processing = processing;
            this.hidden = hidden;
            this.name = name;
            this.shortname = shortname;
            this.shortname2 = shortname2;
            this.terminalOption = isTerminal;
        }
        public Option(boolean hasArg,
                      Processing<T> processing,
                      boolean hidden,
                      String name,
                      String shortname,
                      boolean isTerminal)
        {
            this(hasArg, processing, false, name, shortname, "", isTerminal);
        }

        public Option(boolean hasArg, Processing<T> processing, String name, String shortname, boolean isTerminal) {
            this(hasArg, processing, false, name, shortname, "", isTerminal);
        }

        public Option(boolean hasArg, Processing<T> processing, String name, String shortname, String shortname2) {
            this(hasArg, processing, false, name, shortname, shortname2, false);
        }

        public Option(boolean hasArg, Processing<T> processing, String name, String shortname) {
            this(hasArg, processing, false, name, shortname, "", false);
        }

        public Option(boolean hasArg, Processing<T> processing, boolean hidden, String name) {
            this(hasArg, processing, hidden, name, "", "", false);
        }

        public Option(boolean hasArg, Processing<T> processing, String name) {
            this(hasArg, processing, false, name, "", false);
        }

        public boolean isHidden() {
            return hidden;
        }

        public boolean isTerminal() {
            return terminalOption;
        }

        public boolean matches(String opt) {
            return opt.equals(name) ||
                   opt.equals(shortname) ||
                   opt.equals(shortname2) ||
                   hasArg && opt.startsWith("--") && opt.startsWith(name + "=");
         }

        public boolean ignoreRest() {
            return false;
        }

        void process(T task, String opt, String arg) throws BadArgs {
            processing.process(task, opt, arg);
        }

        public String getName() {
            return name;
        }

        public String resourceName() {
            return resourcePrefix() + name.substring(2);
        }

        public String getShortname() {
            return shortname;
        }

        public String resourcePrefix() {
            return "main.opt.";
        }

        @Override
        public int compareTo(Object object) {
            if (!(object instanceof Option<?>)) {
                throw new RuntimeException("comparing non-Option");
            }

            Option<?> option = (Option<?>)object;

            return name.compareTo(option.name);
        }

    }

    private static class PluginOption extends Option<PluginsHelper> {
        public PluginOption(boolean hasArg,
                Processing<PluginsHelper> processing, boolean hidden, String name, String shortname) {
            super(hasArg, processing, hidden, name, shortname, false);
        }

        public PluginOption(boolean hasArg,
                Processing<PluginsHelper> processing, boolean hidden, String name) {
            super(hasArg, processing, hidden, name, "", false);
        }

        public String resourcePrefix() {
            return "plugin.opt.";
        }
    }

    private final class PluginsHelper {

        private ModuleLayer pluginsLayer = ModuleLayer.boot();
        private final List<Plugin> plugins;
        private String lastSorter;
        private boolean listPlugins;
        private Path existingImage;

        // plugin to args maps. Each plugin may be used more than once in command line.
        // Each such occurrence results in a Map of arguments. So, there could be multiple
        // args maps per plugin instance.
        private final Map<Plugin, List<Map<String, String>>> pluginToMaps = new HashMap<>();
        private final List<PluginOption> pluginsOptions = new ArrayList<>();
        private final List<PluginOption> mainOptions = new ArrayList<>();

        private PluginsHelper(String pp) throws BadArgs {

            if (pp != null) {
                String[] dirs = pp.split(File.pathSeparator);
                List<Path> paths = new ArrayList<>(dirs.length);
                for (String dir : dirs) {
                    paths.add(Paths.get(dir));
                }

                pluginsLayer = createPluginsLayer(paths);
            }

            plugins = PluginRepository.getPlugins(pluginsLayer);

            Set<String> optionsSeen = new HashSet<>();
            for (Plugin plugin : plugins) {
                if (!Utils.isDisabled(plugin)) {
                    addOrderedPluginOptions(plugin, optionsSeen);
                }
            }
            mainOptions.add(new PluginOption(true, (task, opt, arg) -> {
                    for (Plugin plugin : plugins) {
                        if (plugin.getName().equals(arg)) {
                            pluginToMaps.remove(plugin);
                            return;
                        }
                    }
                    throw newBadArgs("err.no.such.plugin", arg);
                },
                false, "--disable-plugin"));
            mainOptions.add(new PluginOption(true, (task, opt, arg) -> {
                Path path = Paths.get(arg);
                if (!Files.exists(path) || !Files.isDirectory(path)) {
                    throw newBadArgs("err.image.must.exist", path);
                }
                existingImage = path.toAbsolutePath();
            }, true, "--post-process-path"));
            mainOptions.add(new PluginOption(true,
                    (task, opt, arg) -> {
                        lastSorter = arg;
                    },
                    true, "--resources-last-sorter"));
            mainOptions.add(new PluginOption(false,
                    (task, opt, arg) -> {
                        listPlugins = true;
                    },
                    false, "--list-plugins"));
        }

        private List<Map<String, String>> argListFor(Plugin plugin) {
            List<Map<String, String>> mapList = pluginToMaps.get(plugin);
            if (mapList == null) {
                mapList = new ArrayList<>();
                pluginToMaps.put(plugin, mapList);
            }
            return mapList;
        }

        private void addEmptyArgumentMap(Plugin plugin) {
            argListFor(plugin).add(Collections.emptyMap());
        }

        private Map<String, String> addArgumentMap(Plugin plugin) {
            Map<String, String> map = new HashMap<>();
            argListFor(plugin).add(map);
            return map;
        }

        private void addOrderedPluginOptions(Plugin plugin,
            Set<String> optionsSeen) throws BadArgs {
            String option = plugin.getOption();
            if (option == null) {
                return;
            }

            // make sure that more than one plugin does not use the same option!
            if (optionsSeen.contains(option)) {
                throw new BadArgs("err.plugin.mutiple.options",
                        option);
            }
            optionsSeen.add(option);

            PluginOption plugOption
                    = new PluginOption(plugin.hasArguments(),
                            (task, opt, arg) -> {
                                if (!Utils.isFunctional(plugin)) {
                                    throw newBadArgs("err.provider.not.functional",
                                            option);
                                }

                                if (! plugin.hasArguments()) {
                                    addEmptyArgumentMap(plugin);
                                    return;
                                }

                                Map<String, String> m = addArgumentMap(plugin);
                                // handle one or more arguments
                                if (arg.indexOf(':') == -1) {
                                    // single argument case
                                    m.put(option, arg);
                                } else {
                                    // This option can accept more than one arguments
                                    // like --option_name=arg_value:arg2=value2:arg3=value3

                                    // ":" followed by word char condition takes care of args that
                                    // like Windows absolute paths "C:\foo", "C:/foo" [cygwin] etc.
                                    // This enforces that key names start with a word character.
                                    String[] args = arg.split(":(?=\\w)", -1);
                                    String firstArg = args[0];
                                    if (firstArg.isEmpty()) {
                                        throw newBadArgs("err.provider.additional.arg.error",
                                            option, arg);
                                    }
                                    m.put(option, firstArg);
                                    // process the additional arguments
                                    for (int i = 1; i < args.length; i++) {
                                        String addArg = args[i];
                                        int eqIdx = addArg.indexOf('=');
                                        if (eqIdx == -1) {
                                            throw newBadArgs("err.provider.additional.arg.error",
                                                option, arg);
                                        }

                                        String addArgName = addArg.substring(0, eqIdx);
                                        String addArgValue = addArg.substring(eqIdx+1);
                                        if (addArgName.isEmpty() || addArgValue.isEmpty()) {
                                            throw newBadArgs("err.provider.additional.arg.error",
                                                option, arg);
                                        }
                                        m.put(addArgName, addArgValue);
                                    }
                                }
                            },
                            false, "--" + option);
            pluginsOptions.add(plugOption);

            if (Utils.isFunctional(plugin)) {
                if (Utils.isAutoEnabled(plugin)) {
                    addEmptyArgumentMap(plugin);
                }

                if (plugin instanceof DefaultCompressPlugin) {
                    plugOption
                        = new PluginOption(false,
                            (task, opt, arg) -> {
                                Map<String, String> m = addArgumentMap(plugin);
                                m.put(DefaultCompressPlugin.NAME, DefaultCompressPlugin.LEVEL_2);
                            }, false, "--compress", "-c");
                    mainOptions.add(plugOption);
                } else if (plugin instanceof StripDebugPlugin) {
                    plugOption
                        = new PluginOption(false,
                            (task, opt, arg) -> {
                                addArgumentMap(plugin);
                            }, false, "--strip-debug", "-G");
                    mainOptions.add(plugOption);
                } else if (plugin instanceof ExcludeJmodSectionPlugin) {
                    plugOption = new PluginOption(false, (task, opt, arg) -> {
                            Map<String, String> m = addArgumentMap(plugin);
                            m.put(ExcludeJmodSectionPlugin.NAME,
                                  ExcludeJmodSectionPlugin.MAN_PAGES);
                        }, false, "--no-man-pages");
                    mainOptions.add(plugOption);

                    plugOption = new PluginOption(false, (task, opt, arg) -> {
                        Map<String, String> m = addArgumentMap(plugin);
                        m.put(ExcludeJmodSectionPlugin.NAME,
                              ExcludeJmodSectionPlugin.INCLUDE_HEADER_FILES);
                    }, false, "--no-header-files");
                    mainOptions.add(plugOption);
                }
            }
        }

        private PluginOption getOption(String name) throws BadArgs {
            for (PluginOption o : pluginsOptions) {
                if (o.matches(name)) {
                    return o;
                }
            }
            for (PluginOption o : mainOptions) {
                if (o.matches(name)) {
                    return o;
                }
            }
            return null;
        }

        private PluginsConfiguration getPluginsConfig(Path output, Map<String, String> launchers
                    ) throws IOException, BadArgs {
            if (output != null) {
                if (Files.exists(output)) {
                    throw new PluginException(PluginsResourceBundle.
                            getMessage("err.dir.already.exits", output));
                }
            }

            List<Plugin> pluginsList = new ArrayList<>();
            for (Entry<Plugin, List<Map<String, String>>> entry : pluginToMaps.entrySet()) {
                Plugin plugin = entry.getKey();
                List<Map<String, String>> argsMaps = entry.getValue();

                // same plugin option may be used multiple times in command line.
                // we call configure once for each occurrence. It is upto the plugin
                // to 'merge' and/or 'override' arguments.
                for (Map<String, String> map : argsMaps) {
                    try {
                        plugin.configure(Collections.unmodifiableMap(map));
                    } catch (IllegalArgumentException e) {
                        if (JlinkTask.DEBUG) {
                            System.err.println("Plugin " + plugin.getName() + " threw exception with config: " + map);
                            e.printStackTrace();
                        }
                        throw e;
                    }
                }

                if (!Utils.isDisabled(plugin)) {
                    pluginsList.add(plugin);
                }
            }

            // recreate or postprocessing don't require an output directory.
            ImageBuilder builder = null;
            if (output != null) {
                builder = new DefaultImageBuilder(output, launchers);
            }

            return new Jlink.PluginsConfiguration(pluginsList,
                    builder, lastSorter);
        }
    }

    private static final class ResourceBundleHelper {

        private final ResourceBundle bundle;
        private final ResourceBundle pluginBundle;

        ResourceBundleHelper(String path) {
            Locale locale = Locale.getDefault();
            try {
                bundle = ResourceBundle.getBundle(path, locale);
                pluginBundle = ResourceBundle.getBundle("jdk.tools.jlink.resources.plugins", locale);
            } catch (MissingResourceException e) {
                throw new InternalError("Cannot find jlink resource bundle for locale " + locale);
            }
        }

        String getMessage(String key, Object... args) {
            String val;
            try {
                val = bundle.getString(key);
            } catch (MissingResourceException e) {
                // XXX OK, check in plugin bundle
                val = pluginBundle.getString(key);
            }
            return MessageFormat.format(val, args);
        }

    }

    public final class OptionsHelper<T> {

        private final List<Option<T>> options;
        private String[] command;
        private String defaults;

        OptionsHelper(List<Option<T>> options) {
            this.options = options;
        }

        private boolean hasArgument(String optionName) throws BadArgs {
            Option<?> opt = getOption(optionName);
            if (opt == null) {
                opt = pluginOptions.getOption(optionName);
                if (opt == null) {
                    throw new BadArgs("err.unknown.option", optionName).
                            showUsage(true);
                }
            }
            return opt.hasArg;
        }

        public boolean shouldListPlugins() {
            return pluginOptions.listPlugins;
        }

        private String getPluginsPath(String[] args) throws BadArgs {
            return null;
        }

        /**
         * Handles all options.  This method stops processing the argument
         * at the first non-option argument i.e. not starts with `-`, or
         * at the first terminal option and returns the remaining arguments,
         * if any.
         */
        public List<String> handleOptions(T task, String[] args) throws BadArgs {
            // findbugs warning, copy instead of keeping a reference.
            command = Arrays.copyOf(args, args.length);

            // Must extract it prior to do any option analysis.
            // Required to interpret custom plugin options.
            // Unit tests can call Task multiple time in same JVM.
            pluginOptions = new PluginsHelper(null);

            // process options
            for (int i = 0; i < args.length; i++) {
                if (args[i].startsWith("-")) {
                    String name = args[i];
                    PluginOption pluginOption = null;
                    Option<T> option = getOption(name);
                    if (option == null) {
                        pluginOption = pluginOptions.getOption(name);
                        if (pluginOption == null) {
                            throw new BadArgs("err.unknown.option", name).
                                    showUsage(true);
                        }
                    }
                    Option<?> opt = pluginOption == null ? option : pluginOption;
                    String param = null;
                    if (opt.hasArg) {
                        if (name.startsWith("--") && name.indexOf('=') > 0) {
                            param = name.substring(name.indexOf('=') + 1,
                                    name.length());
                        } else if (i + 1 < args.length) {
                            param = args[++i];
                        }
                        if (param == null || param.isEmpty()
                                || (param.length() >= 2 && param.charAt(0) == '-'
                                && param.charAt(1) == '-')) {
                            throw new BadArgs("err.missing.arg", name).
                                    showUsage(true);
                        }
                    }
                    if (pluginOption != null) {
                        pluginOption.process(pluginOptions, name, param);
                    } else {
                        option.process(task, name, param);
                        if (option.isTerminal()) {
                            return ++i < args.length
                                        ? Stream.of(Arrays.copyOfRange(args, i, args.length))
                                                .collect(Collectors.toList())
                                        : Collections.emptyList();

                        }
                    }
                    if (opt.ignoreRest()) {
                        i = args.length;
                    }
                } else {
                    return Stream.of(Arrays.copyOfRange(args, i, args.length))
                                 .collect(Collectors.toList());
                }
            }
            return Collections.emptyList();
        }

        private Option<T> getOption(String name) {
            for (Option<T> o : options) {
                if (o.matches(name)) {
                    return o;
                }
            }
            return null;
        }

        public void showHelp(String progName) {
            log.println(bundleHelper.getMessage("main.usage", progName));
            Stream.concat(options.stream(), pluginOptions.mainOptions.stream())
                .filter(option -> !option.isHidden())
                .sorted()
                .forEach(option -> {
                     log.println(bundleHelper.getMessage(option.resourceName()));
                });

            log.println(bundleHelper.getMessage("main.command.files"));
        }

        public void listPlugins() {
            log.println("\n" + bundleHelper.getMessage("main.extended.help"));
            List<Plugin> pluginList = PluginRepository.
                    getPlugins(pluginOptions.pluginsLayer);

            for (Plugin plugin : Utils.getSortedPlugins(pluginList)) {
                showPlugin(plugin, log);
            }

            log.println("\n" + bundleHelper.getMessage("main.extended.help.footer"));
        }

        private void showPlugin(Plugin plugin, PrintWriter log) {
            if (showsPlugin(plugin)) {
                log.println("\n" + bundleHelper.getMessage("main.plugin.name")
                        + ": " + plugin.getName());

                // print verbose details for non-builtin plugins
                if (!Utils.isBuiltin(plugin)) {
                    log.println(bundleHelper.getMessage("main.plugin.class")
                         + ": " + plugin.getClass().getName());
                    log.println(bundleHelper.getMessage("main.plugin.module")
                         + ": " + plugin.getClass().getModule().getName());
                    Category category = plugin.getType();
                    log.println(bundleHelper.getMessage("main.plugin.category")
                         + ": " + category.getName());
                    log.println(bundleHelper.getMessage("main.plugin.state")
                        + ": " + plugin.getStateDescription());
                }

                String option = plugin.getOption();
                if (option != null) {
                    log.println(bundleHelper.getMessage("main.plugin.option")
                        + ": --" + plugin.getOption()
                        + (plugin.hasArguments()? ("=" + plugin.getArgumentsDescription()) : ""));
                }

                // description can be long spanning more than one line and so
                // print a newline after description label.
                log.println(bundleHelper.getMessage("main.plugin.description")
                        + ": " + plugin.getDescription());
            }
        }

        String[] getInputCommand() {
            return command;
        }

        String getDefaults() {
            return defaults;
        }

        public ModuleLayer getPluginsLayer() {
            return pluginOptions.pluginsLayer;
        }
    }

    private PluginsHelper pluginOptions;
    private PrintWriter log;
    private final ResourceBundleHelper bundleHelper;

    public TaskHelper(String path) {
        if (!JLINK_BUNDLE.equals(path) && !JIMAGE_BUNDLE.equals(path)) {
            throw new IllegalArgumentException("Invalid Bundle");
        }
        this.bundleHelper = new ResourceBundleHelper(path);
    }

    public <T> OptionsHelper<T> newOptionsHelper(Class<T> clazz,
            Option<?>[] options) {
        List<Option<T>> optionsList = new ArrayList<>();
        for (Option<?> o : options) {
            @SuppressWarnings("unchecked")
            Option<T> opt = (Option<T>) o;
            optionsList.add(opt);
        }
        return new OptionsHelper<>(optionsList);
    }

    public BadArgs newBadArgs(String key, Object... args) {
        return new BadArgs(key, args);
    }

    public String getMessage(String key, Object... args) {
        return bundleHelper.getMessage(key, args);
    }

    public void setLog(PrintWriter log) {
        this.log = log;
    }

    public void reportError(String key, Object... args) {
        log.println(bundleHelper.getMessage("error.prefix") + " "
                + bundleHelper.getMessage(key, args));
    }

    public void reportUnknownError(String message) {
        log.println(bundleHelper.getMessage("error.prefix") + " " + message);
    }

    public void warning(String key, Object... args) {
        log.println(bundleHelper.getMessage("warn.prefix") + " "
                + bundleHelper.getMessage(key, args));
    }

    public PluginsConfiguration getPluginsConfig(Path output, Map<String, String> launchers)
            throws IOException, BadArgs {
        return pluginOptions.getPluginsConfig(output, launchers);
    }

    public Path getExistingImage() {
        return pluginOptions.existingImage;
    }

    public void showVersion(boolean full) {
        log.println(version(full ? "full" : "release"));
    }

    public String version(String key) {
        return System.getProperty("java.version");
    }

    static ModuleLayer createPluginsLayer(List<Path> paths) {

        Path[] dirs = paths.toArray(new Path[0]);
        ModuleFinder finder = ModulePath.of(Runtime.version(), true, dirs);
        Configuration bootConfiguration = ModuleLayer.boot().configuration();
        try {
            Configuration cf = bootConfiguration
                .resolveAndBind(ModuleFinder.of(),
                                finder,
                                Collections.emptySet());
            ClassLoader scl = ClassLoader.getSystemClassLoader();
            return ModuleLayer.boot().defineModulesWithOneLoader(cf, scl);
        } catch (Exception ex) {
            // Malformed plugin modules (e.g.: same package in multiple modules).
            throw new PluginException("Invalid modules in the plugins path: " + ex);
        }
    }

    // Display all plugins
    private static boolean showsPlugin(Plugin plugin) {
        return (!Utils.isDisabled(plugin) && plugin.getOption() != null);
    }
}

jdk/tools/jlink/internal/TaskHelper.java

 

JDK 11 jdk.jshell.jmod - JShell Tool

JDK 11 jdk.jfr.jmod - JFR Module

Download and Use JDK 11

⇑⇑ FAQ for JDK (Java Development Kit)

2018-11-09, 2854👍, 0💬