8174826: jlink support for linking in service provider modules
Reviewed-by: alanb, anazarov
This commit is contained in:
parent
b9cff83140
commit
340ebfef08
jdk
src/jdk.jlink/share/classes/jdk/tools
jimage
jlink
internal
resources
test/tools/jlink
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 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
|
||||
@ -35,8 +35,12 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.jimage.BasicImageReader;
|
||||
import jdk.internal.jimage.ImageHeader;
|
||||
import jdk.internal.jimage.ImageLocation;
|
||||
@ -99,7 +103,7 @@ class JImageTask {
|
||||
}
|
||||
|
||||
static class OptionsValues {
|
||||
Task task = Task.LIST;
|
||||
Task task = null;
|
||||
String directory = ".";
|
||||
String include = "";
|
||||
boolean fullVersion;
|
||||
@ -172,24 +176,31 @@ class JImageTask {
|
||||
}
|
||||
|
||||
try {
|
||||
List<String> unhandled = OPTION_HELPER.handleOptions(this, args);
|
||||
String command;
|
||||
String[] remaining = args;
|
||||
try {
|
||||
command = args[0];
|
||||
options.task = Enum.valueOf(Task.class, args[0].toUpperCase(Locale.ENGLISH));
|
||||
remaining = args.length > 1 ? Arrays.copyOfRange(args, 1, args.length)
|
||||
: new String[0];
|
||||
} catch (IllegalArgumentException ex) {
|
||||
command = null;
|
||||
options.task = null;
|
||||
}
|
||||
|
||||
if(!unhandled.isEmpty()) {
|
||||
try {
|
||||
options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
|
||||
}
|
||||
// process arguments
|
||||
List<String> unhandled = OPTION_HELPER.handleOptions(this, remaining);
|
||||
for (String f : unhandled) {
|
||||
options.jimages.add(new File(f));
|
||||
}
|
||||
|
||||
for(int i = 1; i < unhandled.size(); i++) {
|
||||
options.jimages.add(new File(unhandled.get(i)));
|
||||
}
|
||||
} else if (!options.help && !options.version && !options.fullVersion) {
|
||||
throw TASK_HELPER.newBadArgs("err.invalid.task", "<unspecified>");
|
||||
if (options.task == null && !options.help && !options.version && !options.fullVersion) {
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.task",
|
||||
command != null ? command : "<unspecified>");
|
||||
}
|
||||
|
||||
if (options.help) {
|
||||
if (unhandled.isEmpty()) {
|
||||
if (options.task == null) {
|
||||
log.println(TASK_HELPER.getMessage("main.usage", PROGNAME));
|
||||
Arrays.asList(RECOGNIZED_OPTIONS).stream()
|
||||
.filter(option -> !option.isHidden())
|
||||
@ -203,15 +214,19 @@ class JImageTask {
|
||||
log.println(TASK_HELPER.getMessage("main.usage." +
|
||||
options.task.toString().toLowerCase()));
|
||||
} catch (MissingResourceException ex) {
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.task", command);
|
||||
}
|
||||
}
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (options.version || options.fullVersion) {
|
||||
TASK_HELPER.showVersion(options.fullVersion);
|
||||
if (options.task == null && !unhandled.isEmpty()) {
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.task",
|
||||
Stream.of(args).collect(Collectors.joining(" ")));
|
||||
}
|
||||
|
||||
TASK_HELPER.showVersion(options.fullVersion);
|
||||
if (unhandled.isEmpty()) {
|
||||
return EXIT_OK;
|
||||
}
|
||||
@ -435,7 +450,7 @@ class JImageTask {
|
||||
iterate(this::listTitle, null, this::verify);
|
||||
break;
|
||||
default:
|
||||
throw TASK_HELPER.newBadArgs("err.invalid.task",
|
||||
throw TASK_HELPER.newBadArgs("err.not.a.task",
|
||||
options.task.name()).showUsage(true);
|
||||
}
|
||||
return true;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -24,6 +24,8 @@
|
||||
*/
|
||||
package jdk.tools.jlink.internal;
|
||||
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.reflect.Layer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Path;
|
||||
@ -33,6 +35,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.module.ModulePath;
|
||||
import jdk.tools.jlink.plugin.Plugin;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
import jdk.tools.jlink.builder.ImageBuilder;
|
||||
@ -147,8 +151,8 @@ public final class Jlink {
|
||||
private final Path output;
|
||||
private final Set<String> modules;
|
||||
private final Set<String> limitmods;
|
||||
|
||||
private final ByteOrder endian;
|
||||
private final ModuleFinder finder;
|
||||
|
||||
/**
|
||||
* jlink configuration,
|
||||
@ -160,31 +164,23 @@ public final class Jlink {
|
||||
* @param endian Jimage byte order. Native order by default
|
||||
*/
|
||||
public JlinkConfiguration(Path output,
|
||||
List<Path> modulepaths,
|
||||
Set<String> modules,
|
||||
Set<String> limitmods,
|
||||
ByteOrder endian) {
|
||||
this.output = output;
|
||||
this.modulepaths = modulepaths == null ? Collections.emptyList() : modulepaths;
|
||||
this.modules = modules == null ? Collections.emptySet() : modules;
|
||||
this.limitmods = limitmods == null ? Collections.emptySet() : limitmods;
|
||||
this.endian = endian == null ? ByteOrder.nativeOrder() : endian;
|
||||
}
|
||||
List<Path> modulepaths,
|
||||
Set<String> modules,
|
||||
Set<String> limitmods,
|
||||
ByteOrder endian) {
|
||||
if (Objects.requireNonNull(modulepaths).isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty module path");
|
||||
}
|
||||
if (Objects.requireNonNull(modules).isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty modules");
|
||||
}
|
||||
|
||||
/**
|
||||
* jlink configuration,
|
||||
*
|
||||
* @param output Output directory, must not exist.
|
||||
* @param modulepaths Modules paths
|
||||
* @param modules Root modules to resolve
|
||||
* @param limitmods Limit the universe of observable modules
|
||||
*/
|
||||
public JlinkConfiguration(Path output,
|
||||
List<Path> modulepaths,
|
||||
Set<String> modules,
|
||||
Set<String> limitmods) {
|
||||
this(output, modulepaths, modules, limitmods,
|
||||
ByteOrder.nativeOrder());
|
||||
this.output = output;
|
||||
this.modulepaths = modulepaths;
|
||||
this.modules = modules;
|
||||
this.limitmods = Objects.requireNonNull(limitmods);
|
||||
this.endian = Objects.requireNonNull(endian);
|
||||
this.finder = moduleFinder();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,6 +218,45 @@ public final class Jlink {
|
||||
return limitmods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link ModuleFinder} that finds all observable modules
|
||||
* for this jlink configuration.
|
||||
*/
|
||||
public ModuleFinder finder() {
|
||||
return finder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Configuration} of the given module path,
|
||||
* root modules with full service binding.
|
||||
*/
|
||||
public Configuration resolveAndBind()
|
||||
{
|
||||
return Configuration.empty().resolveAndBind(finder,
|
||||
ModuleFinder.of(),
|
||||
modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Configuration} of the given module path,
|
||||
* root modules with no service binding.
|
||||
*/
|
||||
public Configuration resolve()
|
||||
{
|
||||
return Configuration.empty().resolve(finder,
|
||||
ModuleFinder.of(),
|
||||
modules);
|
||||
}
|
||||
|
||||
private ModuleFinder moduleFinder() {
|
||||
Path[] entries = modulepaths.toArray(new Path[0]);
|
||||
ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
|
||||
if (!limitmods.isEmpty()) {
|
||||
finder = JlinkTask.limitFinder(finder, limitmods, modules);
|
||||
}
|
||||
return finder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -110,6 +110,12 @@ public class JlinkTask {
|
||||
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
|
||||
@ -140,6 +146,9 @@ public class JlinkTask {
|
||||
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"),
|
||||
@ -185,6 +194,7 @@ public class JlinkTask {
|
||||
static class OptionsValues {
|
||||
boolean help;
|
||||
String saveoptsfile;
|
||||
boolean verbose;
|
||||
boolean version;
|
||||
boolean fullVersion;
|
||||
final List<Path> modulePath = new ArrayList<>();
|
||||
@ -195,6 +205,8 @@ public class JlinkTask {
|
||||
Path packagedModulesPath;
|
||||
ByteOrder endian = ByteOrder.nativeOrder();
|
||||
boolean ignoreSigning = false;
|
||||
boolean bindServices = false;
|
||||
boolean suggestProviders = false;
|
||||
}
|
||||
|
||||
int run(String[] args) {
|
||||
@ -203,7 +215,11 @@ public class JlinkTask {
|
||||
new PrintWriter(System.err, true));
|
||||
}
|
||||
try {
|
||||
optionsHelper.handleOptionsNoUnhandled(this, args);
|
||||
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;
|
||||
@ -217,17 +233,24 @@ public class JlinkTask {
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (taskHelper.getExistingImage() == null) {
|
||||
if (options.modulePath.isEmpty()) {
|
||||
throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true);
|
||||
}
|
||||
createImage();
|
||||
} else {
|
||||
if (taskHelper.getExistingImage() != null) {
|
||||
postProcessOnly(taskHelper.getExistingImage());
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (options.saveoptsfile != null) {
|
||||
Files.write(Paths.get(options.saveoptsfile), getSaveOpts().getBytes());
|
||||
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;
|
||||
@ -266,25 +289,13 @@ public class JlinkTask {
|
||||
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(),
|
||||
createImageProvider(config,
|
||||
null,
|
||||
IGNORE_SIGNING_DEFAULT,
|
||||
false,
|
||||
false,
|
||||
null);
|
||||
|
||||
// Then create the Plugin Stack
|
||||
@ -319,20 +330,24 @@ public class JlinkTask {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
private JlinkConfiguration initJlinkConfig() throws BadArgs {
|
||||
if (options.addMods.isEmpty()) {
|
||||
throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules")
|
||||
.showUsage(true);
|
||||
.showUsage(true);
|
||||
}
|
||||
|
||||
Set<String> roots = new HashSet<>();
|
||||
for (String mod : options.addMods) {
|
||||
if (mod.equals(ALL_MODULE_PATH)) {
|
||||
ModuleFinder finder = modulePathFinder();
|
||||
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)
|
||||
@ -343,40 +358,34 @@ public class JlinkTask {
|
||||
}
|
||||
}
|
||||
|
||||
ModuleFinder finder = newModuleFinder(options.modulePath,
|
||||
options.limitMods,
|
||||
roots);
|
||||
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(finder,
|
||||
roots,
|
||||
options.endian,
|
||||
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));
|
||||
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
|
||||
@ -405,22 +414,32 @@ public class JlinkTask {
|
||||
return Paths.get(uri);
|
||||
}
|
||||
|
||||
private static ImageProvider createImageProvider(ModuleFinder finder,
|
||||
Set<String> roots,
|
||||
ByteOrder order,
|
||||
|
||||
private static ImageProvider createImageProvider(JlinkConfiguration config,
|
||||
Path retainModulesPath,
|
||||
boolean ignoreSigning,
|
||||
boolean bindService,
|
||||
boolean verbose,
|
||||
PrintWriter log)
|
||||
throws IOException
|
||||
{
|
||||
if (roots.isEmpty()) {
|
||||
throw new IllegalArgumentException("empty modules and limitmods");
|
||||
}
|
||||
Configuration cf = bindService ? config.resolveAndBind()
|
||||
: config.resolve();
|
||||
|
||||
Configuration cf = Configuration.empty()
|
||||
.resolve(finder,
|
||||
ModuleFinder.of(),
|
||||
roots);
|
||||
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());
|
||||
|
||||
String msg = String.format("%n%s:", taskHelper.getMessage("providers.header"));
|
||||
printProviders(log, msg, references);
|
||||
}
|
||||
|
||||
// emit a warning for any incubating modules in the configuration
|
||||
if (log != null) {
|
||||
@ -438,16 +457,16 @@ public class JlinkTask {
|
||||
|
||||
Map<String, Path> mods = cf.modules().stream()
|
||||
.collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
|
||||
return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
|
||||
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.
|
||||
*/
|
||||
private static ModuleFinder limitFinder(ModuleFinder finder,
|
||||
Set<String> roots,
|
||||
Set<String> otherMods) {
|
||||
public static ModuleFinder limitFinder(ModuleFinder finder,
|
||||
Set<String> roots,
|
||||
Set<String> otherMods) {
|
||||
|
||||
// resolve all root modules
|
||||
Configuration cf = Configuration.empty()
|
||||
@ -484,6 +503,147 @@ public class JlinkTask {
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* 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().forEach(s ->
|
||||
uses.computeIfAbsent(s, _k -> new HashSet<>()).add(md.name()))
|
||||
);
|
||||
return uses;
|
||||
}
|
||||
|
||||
private static void printProviders(PrintWriter log,
|
||||
String header,
|
||||
Set<ModuleReference> modules) {
|
||||
printProviders(log, header, modules, uses(modules));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(PrintWriter log,
|
||||
String header,
|
||||
Set<ModuleReference> modules,
|
||||
Map<String, Set<String>> uses) {
|
||||
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));
|
||||
});
|
||||
|
||||
if (!providers.isEmpty()) {
|
||||
log.println(header);
|
||||
}
|
||||
|
||||
// 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));
|
||||
});
|
||||
|
||||
String msg = String.format("%n%s:", taskHelper.getMessage("suggested.providers.header"));
|
||||
printProviders(log, msg, finder.findAll(), uses(mrefs));
|
||||
|
||||
} 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)));
|
||||
}
|
||||
|
||||
String msg = String.format("%n%s:", taskHelper.getMessage("suggested.providers.header"));
|
||||
printProviders(log, msg, mrefs, uses);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -46,6 +46,7 @@ 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;
|
||||
@ -101,8 +102,15 @@ public final class TaskHelper {
|
||||
final boolean hidden;
|
||||
final String name;
|
||||
final String shortname;
|
||||
final boolean terminalOption;
|
||||
|
||||
public Option(boolean hasArg, Processing<T> processing, boolean hidden, String name, String shortname) {
|
||||
public Option(boolean hasArg,
|
||||
Processing<T> processing,
|
||||
boolean hidden,
|
||||
String name,
|
||||
String shortname,
|
||||
boolean isTerminal)
|
||||
{
|
||||
if (!name.startsWith("--")) {
|
||||
throw new RuntimeException("option name missing --, " + name);
|
||||
}
|
||||
@ -115,24 +123,33 @@ public final class TaskHelper {
|
||||
this.hidden = hidden;
|
||||
this.name = name;
|
||||
this.shortname = shortname;
|
||||
this.terminalOption = 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) {
|
||||
this(hasArg, processing, false, name, shortname);
|
||||
this(hasArg, processing, false, name, shortname, false);
|
||||
}
|
||||
|
||||
public Option(boolean hasArg, Processing<T> processing, boolean hidden, String name) {
|
||||
this(hasArg, processing, hidden, name, "");
|
||||
this(hasArg, processing, hidden, name, "", false);
|
||||
}
|
||||
|
||||
public Option(boolean hasArg, Processing<T> processing, String name) {
|
||||
this(hasArg, processing, false, 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) ||
|
||||
@ -179,12 +196,12 @@ public final class TaskHelper {
|
||||
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);
|
||||
super(hasArg, processing, hidden, name, shortname, false);
|
||||
}
|
||||
|
||||
public PluginOption(boolean hasArg,
|
||||
Processing<PluginsHelper> processing, boolean hidden, String name) {
|
||||
super(hasArg, processing, hidden, name, "");
|
||||
super(hasArg, processing, hidden, name, "", false);
|
||||
}
|
||||
|
||||
public String resourcePrefix() {
|
||||
@ -498,21 +515,13 @@ public final class TaskHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
// used by jimage. Return unhandled arguments like "create", "describe".
|
||||
/**
|
||||
* 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 {
|
||||
return handleOptions(task, args, true);
|
||||
}
|
||||
|
||||
// used by jlink. No unhandled arguments like "create", "describe".
|
||||
void handleOptionsNoUnhandled(T task, String[] args) throws BadArgs {
|
||||
handleOptions(task, args, false);
|
||||
}
|
||||
|
||||
// shared code that handles options for both jlink and jimage. jimage uses arguments like
|
||||
// "create", "describe" etc. as "task names". Those arguments are unhandled here and returned
|
||||
// as "unhandled arguments list". jlink does not want such arguments. "collectUnhandled" flag
|
||||
// tells whether to allow for unhandled arguments or not.
|
||||
private List<String> handleOptions(T task, String[] args, boolean collectUnhandled) throws BadArgs {
|
||||
// findbugs warning, copy instead of keeping a reference.
|
||||
command = Arrays.copyOf(args, args.length);
|
||||
|
||||
@ -521,7 +530,6 @@ public final class TaskHelper {
|
||||
// Unit tests can call Task multiple time in same JVM.
|
||||
pluginOptions = new PluginsHelper(null);
|
||||
|
||||
List<String> rest = collectUnhandled? new ArrayList<>() : null;
|
||||
// process options
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].startsWith("-")) {
|
||||
@ -531,7 +539,6 @@ public final class TaskHelper {
|
||||
if (option == null) {
|
||||
pluginOption = pluginOptions.getOption(name);
|
||||
if (pluginOption == null) {
|
||||
|
||||
throw new BadArgs("err.unknown.option", name).
|
||||
showUsage(true);
|
||||
}
|
||||
@ -556,20 +563,23 @@ public final class TaskHelper {
|
||||
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 {
|
||||
if (collectUnhandled) {
|
||||
rest.add(args[i]);
|
||||
} else {
|
||||
throw new BadArgs("err.orphan.argument", args[i]).
|
||||
showUsage(true);
|
||||
}
|
||||
return Stream.of(Arrays.copyOfRange(args, i, args.length))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
return rest;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private Option<T> getOption(String name) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 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
|
||||
@ -34,6 +34,7 @@ import jdk.tools.jlink.plugin.Plugin;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -93,9 +94,12 @@ public final class AppRuntimeImageBuilder {
|
||||
|
||||
public void build() throws IOException {
|
||||
// jlink main arguments
|
||||
Jlink.JlinkConfiguration jlinkConfig = new Jlink.JlinkConfiguration(
|
||||
new File("").toPath(), // Unused
|
||||
modulePath, addModules, limitModules);
|
||||
Jlink.JlinkConfiguration jlinkConfig =
|
||||
new Jlink.JlinkConfiguration(new File("").toPath(), // Unused
|
||||
modulePath,
|
||||
addModules,
|
||||
limitModules,
|
||||
ByteOrder.nativeOrder());
|
||||
|
||||
// plugin configuration
|
||||
List<Plugin> plugins = new ArrayList<Plugin>();
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# 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
|
||||
@ -24,15 +24,12 @@
|
||||
#
|
||||
|
||||
main.usage.summary=\
|
||||
Usage: {0} <options> --module-path <modulepath> --add-modules <mods> --output\n\
|
||||
\<path> use --help for a list of possible options
|
||||
Usage: {0} <options> --module-path <modulepath> --add-modules <module>[,<module>...]\n\
|
||||
\Use --help for a list of possible options
|
||||
|
||||
main.usage=\
|
||||
Usage: {0} <options> --module-path <modulepath> --add-modules <mods> --output\n\
|
||||
\<path> Possible options include:
|
||||
|
||||
error.prefix=Error:
|
||||
warn.prefix=Warning:
|
||||
Usage: {0} <options> --module-path <modulepath> --add-modules <module>[,<module>...]\n\
|
||||
\Possible options include:
|
||||
|
||||
main.opt.help=\
|
||||
\ -h, --help Print this help message
|
||||
@ -54,9 +51,18 @@ main.opt.output=\
|
||||
\ --output <path> Location of output path
|
||||
|
||||
main.opt.launcher=\
|
||||
\ --launcher <command>=<module> Launcher command name for the module\n\
|
||||
\ --launcher <command>=<module>/<main>\n\
|
||||
\ Launcher command name for the module and the main class
|
||||
\ --launcher <name>=<module>[/<mainclass>]\n\
|
||||
\ Add a launcher command of the given\n\
|
||||
\ name for the module and the main class\n\
|
||||
\ if specified
|
||||
|
||||
main.opt.bind-services=\
|
||||
\ --bind-services Do full service binding
|
||||
|
||||
main.opt.suggest-providers=\
|
||||
\ --suggest-providers [<name>,...] Suggest providers of services used by\n\
|
||||
\ the modules that would be linked, or\n\
|
||||
\ of the given service types
|
||||
|
||||
main.command.files=\
|
||||
\ @<filename> Read options from file
|
||||
@ -75,6 +81,9 @@ main.opt.ignore-signing-information=\
|
||||
\ signed modular JARs are not copied to\n\
|
||||
\ the runtime image.
|
||||
|
||||
main.opt.verbose=\
|
||||
\ -v, --verbose Enable verbose tracing
|
||||
|
||||
main.msg.bug=\
|
||||
An exception has occurred in jlink. \
|
||||
Please file a bug at the Java Bug Database (http://bugreport.java.com/bugreport/) \
|
||||
@ -95,6 +104,9 @@ main.extended.help.footer=\
|
||||
\n\
|
||||
|
||||
|
||||
error.prefix=Error:
|
||||
warn.prefix=Warning:
|
||||
|
||||
err.unknown.byte.order:unknown byte order {0}
|
||||
err.launcher.main.class.empty:launcher main class name cannot be empty: {0}
|
||||
err.launcher.module.name.empty:launcher module name cannot be empty: {0}
|
||||
@ -111,12 +123,12 @@ err.file.error=cannot access file: {0}
|
||||
err.dir.exists={0} already exists
|
||||
err.badpattern=bad pattern {0}
|
||||
err.unknown.option=unknown option: {0}
|
||||
err.orphan.argument=orphan argument: {0}
|
||||
err.missing.arg=no value given for {0}
|
||||
err.internal.error=internal error: {0} {1} {2}
|
||||
err.invalid.arg.for.option=invalid argument for option: {0}
|
||||
err.option.after.class=option must be specified before classes: {0}
|
||||
err.option.unsupported={0} not supported: {1}
|
||||
err.orphan.arguments=invalid argument: {0}
|
||||
err.config.defaults=property {0} is missing from configuration
|
||||
err.config.defaults.value=wrong value in defaults property: {0}
|
||||
err.bom.generation=bom file generation failed: {0}
|
||||
@ -126,3 +138,7 @@ err.signing=signed modular JAR {0} is currently not supported,\
|
||||
warn.signing=WARNING: signed modular JAR {0} is currently not supported
|
||||
warn.invalid.arg=invalid classname or pathname not exist: {0}
|
||||
warn.split.package=package {0} defined in {1} {2}
|
||||
warn.unused.services=Services specified in --suggest-providers not used: {0}
|
||||
no.suggested.providers=--bind-services option is specified. No additional providers suggested.
|
||||
suggested.providers.header=Suggested providers
|
||||
providers.header=Providers
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -25,6 +25,7 @@ import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@ -135,11 +136,6 @@ public class IntegrationTest {
|
||||
}
|
||||
System.out.println(jl);
|
||||
|
||||
JlinkConfiguration config
|
||||
= new JlinkConfiguration(null, null, null, null);
|
||||
|
||||
System.out.println(config);
|
||||
|
||||
Plugin p = Jlink.newPlugin("toto", Collections.emptyMap(), null);
|
||||
if (p != null) {
|
||||
throw new Exception("Plugin should be null");
|
||||
@ -163,7 +159,7 @@ public class IntegrationTest {
|
||||
Set<String> limits = new HashSet<>();
|
||||
limits.add("java.management");
|
||||
JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
|
||||
modulePaths, mods, limits, null);
|
||||
modulePaths, mods, limits, ByteOrder.nativeOrder());
|
||||
|
||||
List<Plugin> lst = new ArrayList<>();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -274,7 +274,7 @@ public class JLinkTest {
|
||||
String[] userOptions = {"--compress", "2", "foo" };
|
||||
String moduleName = "orphanarg1";
|
||||
helper.generateDefaultJModule(moduleName, "composite2");
|
||||
helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: foo");
|
||||
helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: foo");
|
||||
}
|
||||
|
||||
// orphan argument - JDK-8166810
|
||||
@ -282,7 +282,7 @@ public class JLinkTest {
|
||||
String[] userOptions = {"--output", "foo", "bar" };
|
||||
String moduleName = "orphanarg2";
|
||||
helper.generateDefaultJModule(moduleName, "composite2");
|
||||
helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: bar");
|
||||
helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: bar");
|
||||
}
|
||||
|
||||
// basic check for --help - JDK-8173717
|
||||
|
200
jdk/test/tools/jlink/bindservices/BindServices.java
Normal file
200
jdk/test/tools/jlink/bindservices/BindServices.java
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static jdk.testlibrary.Asserts.assertTrue;
|
||||
import static jdk.testlibrary.ProcessTools.*;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8174826
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.compiler jdk.jlink
|
||||
* @build BindServices CompilerUtils jdk.testlibrary.ProcessTools
|
||||
* @run testng BindServices
|
||||
*/
|
||||
|
||||
public class BindServices {
|
||||
private static final String JAVA_HOME = System.getProperty("java.home");
|
||||
private static final String TEST_SRC = System.getProperty("test.src");
|
||||
|
||||
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
|
||||
private static final Path MODS_DIR = Paths.get("mods");
|
||||
|
||||
private static final String MODULE_PATH =
|
||||
Paths.get(JAVA_HOME, "jmods").toString() +
|
||||
File.pathSeparator + MODS_DIR.toString();
|
||||
|
||||
// the names of the modules in this test
|
||||
private static String[] modules = new String[] {"m1", "m2", "m3"};
|
||||
|
||||
|
||||
private static boolean hasJmods() {
|
||||
if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) {
|
||||
System.err.println("Test skipped. NO jmods directory");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiles all modules used by the test
|
||||
*/
|
||||
@BeforeTest
|
||||
public void compileAll() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
for (String mn : modules) {
|
||||
Path msrc = SRC_DIR.resolve(mn);
|
||||
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
|
||||
"--module-source-path", SRC_DIR.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noServiceBinding() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
Path dir = Paths.get("noServiceBinding");
|
||||
|
||||
// no service binding and does not link m2,m3 providers.
|
||||
JLink.run("--output", dir.toString(),
|
||||
"--module-path", MODULE_PATH,
|
||||
"--add-modules", "m1").output();
|
||||
|
||||
testImage(dir, "m1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fullServiceBinding() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
Path dir = Paths.get("fullServiceBinding");
|
||||
|
||||
// full service binding
|
||||
// m2 is a provider used by m1. During service binding, when m2 is
|
||||
// resolved, m2 uses p2.T that causes m3 to be linked as it is a
|
||||
// provider to p2.T
|
||||
JLink.run("--output", dir.toString(),
|
||||
"--module-path", MODULE_PATH,
|
||||
"--add-modules", "m1",
|
||||
"--bind-services",
|
||||
"--limit-modules", "m1,m2,m3,java.base");
|
||||
|
||||
testImage(dir, "m1", "m2", "m3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVerbose() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
Path dir = Paths.get("verbose");
|
||||
|
||||
List<String> output =
|
||||
JLink.run("--output", dir.toString(),
|
||||
"--module-path", MODULE_PATH,
|
||||
"--add-modules", "m1",
|
||||
"--bind-services",
|
||||
"--verbose",
|
||||
"--limit-modules", "m1,m2,m3,java.base").output();
|
||||
|
||||
List<String> expected = List.of(
|
||||
"module m1 (" + MODS_DIR.resolve("m1").toUri().toString() + ")",
|
||||
"module m2 (" + MODS_DIR.resolve("m2").toUri().toString() + ")",
|
||||
"module m3 (" + MODS_DIR.resolve("m3").toUri().toString() + ")",
|
||||
"module m1 provides p1.S, used by m1",
|
||||
"module m2 provides p1.S, used by m1",
|
||||
"module m2 provides p2.T, used by m2",
|
||||
"module m3 provides p2.T, used by m2"
|
||||
);
|
||||
|
||||
assertTrue(output.containsAll(expected));
|
||||
|
||||
testImage(dir, "m1", "m2", "m3");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests the given ${java.home} to only contain the specified modules
|
||||
*/
|
||||
private void testImage(Path javaHome, String... modules) throws Throwable {
|
||||
Path java = javaHome.resolve("bin").resolve("java");
|
||||
String[] cmd = Stream.concat(
|
||||
Stream.of(java.toString(), "-m", "m1/p1.Main"),
|
||||
Stream.of(modules)).toArray(String[]::new);
|
||||
|
||||
assertTrue(executeProcess(cmd).outputTo(System.out)
|
||||
.errorTo(System.out)
|
||||
.getExitValue() == 0);
|
||||
}
|
||||
|
||||
static class JLink {
|
||||
static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
|
||||
.orElseThrow(() ->
|
||||
new RuntimeException("jlink tool not found")
|
||||
);
|
||||
|
||||
static JLink run(String... options) {
|
||||
JLink jlink = new JLink();
|
||||
assertTrue(jlink.execute(options) == 0);
|
||||
return jlink;
|
||||
}
|
||||
|
||||
final List<String> output = new ArrayList<>();
|
||||
private int execute(String... options) {
|
||||
System.out.println("jlink " +
|
||||
Stream.of(options).collect(Collectors.joining(" ")));
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(writer);
|
||||
int rc = JLINK_TOOL.run(pw, pw, options);
|
||||
System.out.println(writer.toString());
|
||||
Stream.of(writer.toString().split("\\v"))
|
||||
.map(String::trim)
|
||||
.forEach(output::add);
|
||||
return rc;
|
||||
}
|
||||
|
||||
boolean contains(String s) {
|
||||
return output.contains(s);
|
||||
}
|
||||
|
||||
List<String> output() {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
209
jdk/test/tools/jlink/bindservices/SuggestProviders.java
Normal file
209
jdk/test/tools/jlink/bindservices/SuggestProviders.java
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static jdk.testlibrary.Asserts.assertTrue;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8174826
|
||||
* @library /lib/testlibrary
|
||||
* @modules jdk.charsets jdk.compiler jdk.jlink
|
||||
* @build SuggestProviders CompilerUtils
|
||||
* @run testng SuggestProviders
|
||||
*/
|
||||
|
||||
public class SuggestProviders {
|
||||
private static final String JAVA_HOME = System.getProperty("java.home");
|
||||
private static final String TEST_SRC = System.getProperty("test.src");
|
||||
|
||||
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
|
||||
private static final Path MODS_DIR = Paths.get("mods");
|
||||
|
||||
private static final String MODULE_PATH =
|
||||
Paths.get(JAVA_HOME, "jmods").toString() +
|
||||
File.pathSeparator + MODS_DIR.toString();
|
||||
|
||||
// the names of the modules in this test
|
||||
private static String[] modules = new String[] {"m1", "m2", "m3"};
|
||||
|
||||
|
||||
private static boolean hasJmods() {
|
||||
if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) {
|
||||
System.err.println("Test skipped. NO jmods directory");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiles all modules used by the test
|
||||
*/
|
||||
@BeforeTest
|
||||
public void compileAll() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
for (String mn : modules) {
|
||||
Path msrc = SRC_DIR.resolve(mn);
|
||||
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
|
||||
"--module-source-path", SRC_DIR.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suggestProviders() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
List<String> output = JLink.run("--module-path", MODULE_PATH,
|
||||
"--add-modules", "m1",
|
||||
"--suggest-providers").output();
|
||||
// check a subset of services used by java.base
|
||||
List<String> expected = List.of(
|
||||
"uses java.lang.System$LoggerFinder",
|
||||
"uses java.net.ContentHandlerFactory",
|
||||
"uses java.net.spi.URLStreamHandlerProvider",
|
||||
"uses java.nio.channels.spi.AsynchronousChannelProvider",
|
||||
"uses java.nio.channels.spi.SelectorProvider",
|
||||
"uses java.nio.charset.spi.CharsetProvider",
|
||||
"uses java.nio.file.spi.FileSystemProvider",
|
||||
"uses java.nio.file.spi.FileTypeDetector",
|
||||
"uses java.security.Provider",
|
||||
"uses java.util.spi.ToolProvider",
|
||||
"uses p1.S",
|
||||
"module jdk.charsets provides java.nio.charset.spi.CharsetProvider, used by java.base",
|
||||
"module jdk.compiler provides java.util.spi.ToolProvider, used by java.base",
|
||||
"module jdk.jlink provides java.util.spi.ToolProvider, used by java.base",
|
||||
"module m1 provides p1.S, used by m1",
|
||||
"module m2 provides p1.S, used by m1"
|
||||
);
|
||||
|
||||
assertTrue(output.containsAll(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providersForServices() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
List<String> output =
|
||||
JLink.run("--module-path", MODULE_PATH,
|
||||
"--add-modules", "m1",
|
||||
"--suggest-providers",
|
||||
"java.nio.charset.spi.CharsetProvider,p1.S,p2.T").output();
|
||||
|
||||
System.out.println(output);
|
||||
List<String> expected = List.of(
|
||||
"module jdk.charsets provides java.nio.charset.spi.CharsetProvider, used by java.base",
|
||||
"module m1 provides p1.S, used by m1",
|
||||
"module m2 provides p1.S, used by m1",
|
||||
"module m2 provides p2.T, used by m2",
|
||||
"module m3 provides p2.T, used by m2"
|
||||
);
|
||||
|
||||
assertTrue(output.containsAll(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unusedService() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
List<String> output =
|
||||
JLink.run("--module-path", MODULE_PATH,
|
||||
"--add-modules", "m1",
|
||||
"--suggest-providers",
|
||||
"nonExistentType").output();
|
||||
|
||||
System.out.println(output);
|
||||
List<String> expected = List.of(
|
||||
"Services specified in --suggest-providers not used: nonExistentType"
|
||||
);
|
||||
|
||||
assertTrue(output.containsAll(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noSuggestProviders() throws Throwable {
|
||||
if (!hasJmods()) return;
|
||||
|
||||
List<String> output =
|
||||
JLink.run("--module-path", MODULE_PATH,
|
||||
"--add-modules", "m1",
|
||||
"--bind-services",
|
||||
"--limit-modules", "m1,m2,m3,java.base",
|
||||
"--suggest-providers").output();
|
||||
|
||||
String expected = "--bind-services option is specified. No additional providers suggested.";
|
||||
assertTrue(output.contains(expected));
|
||||
|
||||
}
|
||||
|
||||
static class JLink {
|
||||
static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
|
||||
.orElseThrow(() ->
|
||||
new RuntimeException("jlink tool not found")
|
||||
);
|
||||
|
||||
static JLink run(String... options) {
|
||||
JLink jlink = new JLink();
|
||||
assertTrue(jlink.execute(options) == 0);
|
||||
return jlink;
|
||||
}
|
||||
|
||||
final List<String> output = new ArrayList<>();
|
||||
private int execute(String... options) {
|
||||
System.out.println("jlink " +
|
||||
Stream.of(options).collect(Collectors.joining(" ")));
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(writer);
|
||||
int rc = JLINK_TOOL.run(pw, pw, options);
|
||||
System.out.println(writer.toString());
|
||||
Stream.of(writer.toString().split("\\v"))
|
||||
.map(String::trim)
|
||||
.forEach(output::add);
|
||||
return rc;
|
||||
}
|
||||
|
||||
boolean contains(String s) {
|
||||
return output.contains(s);
|
||||
}
|
||||
|
||||
List<String> output() {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
28
jdk/test/tools/jlink/bindservices/src/m1/module-info.java
Normal file
28
jdk/test/tools/jlink/bindservices/src/m1/module-info.java
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module m1 {
|
||||
exports p1;
|
||||
uses p1.S;
|
||||
provides p1.S with p1.Impl;
|
||||
}
|
30
jdk/test/tools/jlink/bindservices/src/m1/p1/Impl.java
Normal file
30
jdk/test/tools/jlink/bindservices/src/m1/p1/Impl.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package p1;
|
||||
|
||||
public class Impl implements S {
|
||||
public String name() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
}
|
53
jdk/test/tools/jlink/bindservices/src/m1/p1/Main.java
Normal file
53
jdk/test/tools/jlink/bindservices/src/m1/p1/Main.java
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package p1;
|
||||
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* This tests if JAVA_HOME is linked only with the specified modules.
|
||||
*/
|
||||
public class Main {
|
||||
public static void main(String... args) {
|
||||
Set<String> modules = ModuleFinder.ofSystem().findAll().stream()
|
||||
.map(mref -> mref.descriptor().name())
|
||||
.filter(mn -> !mn.equals("java.base"))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<String> notLinked = Stream.of(args).filter(mn -> !modules.contains(mn))
|
||||
.collect(Collectors.toSet());
|
||||
if (!notLinked.isEmpty()) {
|
||||
throw new RuntimeException("Expected modules not linked in the image: "
|
||||
+ notLinked);
|
||||
}
|
||||
Stream.of(args).forEach(modules::remove);
|
||||
|
||||
if (!modules.isEmpty()) {
|
||||
throw new RuntimeException("Unexpected modules linked in the image: "
|
||||
+ modules);
|
||||
}
|
||||
}
|
||||
}
|
28
jdk/test/tools/jlink/bindservices/src/m1/p1/S.java
Normal file
28
jdk/test/tools/jlink/bindservices/src/m1/p1/S.java
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package p1;
|
||||
|
||||
public interface S {
|
||||
String name();
|
||||
}
|
30
jdk/test/tools/jlink/bindservices/src/m2/module-info.java
Normal file
30
jdk/test/tools/jlink/bindservices/src/m2/module-info.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module m2 {
|
||||
requires m1;
|
||||
exports p2;
|
||||
uses p2.T;
|
||||
provides p1.S with p2.Impl;
|
||||
provides p2.T with p2.Impl;
|
||||
}
|
33
jdk/test/tools/jlink/bindservices/src/m2/p2/Impl.java
Normal file
33
jdk/test/tools/jlink/bindservices/src/m2/p2/Impl.java
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package p2;
|
||||
|
||||
public class Impl implements p1.S, T {
|
||||
public String name() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
}
|
||||
}
|
28
jdk/test/tools/jlink/bindservices/src/m2/p2/T.java
Normal file
28
jdk/test/tools/jlink/bindservices/src/m2/p2/T.java
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package p2;
|
||||
|
||||
public interface T {
|
||||
void run();
|
||||
}
|
27
jdk/test/tools/jlink/bindservices/src/m3/module-info.java
Normal file
27
jdk/test/tools/jlink/bindservices/src/m3/module-info.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module m3 {
|
||||
requires m2;
|
||||
provides p2.T with p3.Impl;
|
||||
}
|
29
jdk/test/tools/jlink/bindservices/src/m3/p3/Impl.java
Normal file
29
jdk/test/tools/jlink/bindservices/src/m3/p3/Impl.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package p3;
|
||||
|
||||
public class Impl implements p2.T {
|
||||
public void run() {
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user