blob: ecb63cd0a96172f9c144efdc207c6794927c6d32 [file] [log] [blame]
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 jdk.tools.jlink.internal;
import java.lang.reflect.Layer;
import java.nio.ByteOrder;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import jdk.tools.jlink.plugin.Plugin;
import jdk.tools.jlink.plugin.PluginException;
import jdk.tools.jlink.builder.ImageBuilder;
/**
* API to call jlink.
*/
public final class Jlink {
/**
* Create a plugin.
*
* @param name Plugin name
* @param configuration Plugin configuration.
* @param pluginsLayer Plugins Layer. null means boot layer.
* @return A new plugin or null if plugin is unknown.
*/
public static Plugin newPlugin(String name,
Map<String, String> configuration, Layer pluginsLayer) {
Objects.requireNonNull(name);
Objects.requireNonNull(configuration);
pluginsLayer = pluginsLayer == null ? Layer.boot() : pluginsLayer;
return PluginRepository.newPlugin(configuration, name, pluginsLayer);
}
/**
* A complete plugin configuration. Instances of this class are used to
* configure jlink.
*/
public static final class PluginsConfiguration {
private final List<Plugin> plugins;
private final ImageBuilder imageBuilder;
private final String lastSorterPluginName;
/**
* Empty plugins configuration.
*/
public PluginsConfiguration() {
this(Collections.emptyList());
}
/**
* Plugins configuration.
*
* @param plugins List of plugins.
*/
public PluginsConfiguration(List<Plugin> plugins) {
this(plugins, null, null);
}
/**
* Plugins configuration with a last sorter and an ImageBuilder. No
* sorting can occur after the last sorter plugin. The ImageBuilder is
* in charge to layout the image content on disk.
*
* @param plugins List of transformer plugins.
* @param imageBuilder Image builder.
* @param lastSorterPluginName Name of last sorter plugin, no sorting
* can occur after it.
*/
public PluginsConfiguration(List<Plugin> plugins,
ImageBuilder imageBuilder, String lastSorterPluginName) {
this.plugins = plugins == null ? Collections.emptyList()
: plugins;
this.imageBuilder = imageBuilder;
this.lastSorterPluginName = lastSorterPluginName;
}
/**
* @return the plugins
*/
public List<Plugin> getPlugins() {
return plugins;
}
/**
* @return the imageBuilder
*/
public ImageBuilder getImageBuilder() {
return imageBuilder;
}
/**
* @return the lastSorterPluginName
*/
public String getLastSorterPluginName() {
return lastSorterPluginName;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("imagebuilder=").append(imageBuilder).append("\n");
StringBuilder pluginsBuilder = new StringBuilder();
for (Plugin p : plugins) {
pluginsBuilder.append(p).append(",");
}
builder.append("plugins=").append(pluginsBuilder).append("\n");
builder.append("lastsorter=").append(lastSorterPluginName).append("\n");
return builder.toString();
}
}
/**
* Jlink configuration. Instances of this class are used to configure jlink.
*/
public static final class JlinkConfiguration {
private final List<Path> modulepaths;
private final Path output;
private final Set<String> modules;
private final Set<String> limitmods;
private final ByteOrder endian;
/**
* 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
* @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;
}
/**
* 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());
}
/**
* @return the modulepaths
*/
public List<Path> getModulepaths() {
return modulepaths;
}
/**
* @return the byte ordering
*/
public ByteOrder getByteOrder() {
return endian;
}
/**
* @return the output
*/
public Path getOutput() {
return output;
}
/**
* @return the modules
*/
public Set<String> getModules() {
return modules;
}
/**
* @return the limitmods
*/
public Set<String> getLimitmods() {
return limitmods;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("output=").append(output).append("\n");
StringBuilder pathsBuilder = new StringBuilder();
for (Path p : modulepaths) {
pathsBuilder.append(p).append(",");
}
builder.append("modulepaths=").append(pathsBuilder).append("\n");
StringBuilder modsBuilder = new StringBuilder();
for (String p : modules) {
modsBuilder.append(p).append(",");
}
builder.append("modules=").append(modsBuilder).append("\n");
StringBuilder limitsBuilder = new StringBuilder();
for (String p : limitmods) {
limitsBuilder.append(p).append(",");
}
builder.append("limitmodules=").append(limitsBuilder).append("\n");
builder.append("endian=").append(endian).append("\n");
return builder.toString();
}
}
/**
* Jlink instance constructor, if a security manager is set, the jlink
* permission is checked.
*/
public Jlink() {
if (System.getSecurityManager() != null) {
System.getSecurityManager().
checkPermission(new JlinkPermission("jlink"));
}
}
/**
* Build the image.
*
* @param config Jlink config, must not be null.
* @throws PluginException
*/
public void build(JlinkConfiguration config) {
build(config, null);
}
/**
* Build the image with a plugin configuration.
*
* @param config Jlink config, must not be null.
* @param pluginsConfig Plugins config, can be null
* @throws PluginException
*/
public void build(JlinkConfiguration config, PluginsConfiguration pluginsConfig) {
Objects.requireNonNull(config);
if (pluginsConfig == null) {
pluginsConfig = new PluginsConfiguration();
}
// add all auto-enabled plugins from boot layer
pluginsConfig = addAutoEnabledPlugins(pluginsConfig);
try {
JlinkTask.createImage(config, pluginsConfig);
} catch (Exception ex) {
throw new PluginException(ex);
}
}
private PluginsConfiguration addAutoEnabledPlugins(PluginsConfiguration pluginsConfig) {
List<Plugin> plugins = new ArrayList<>(pluginsConfig.getPlugins());
List<Plugin> bootPlugins = PluginRepository.getPlugins(Layer.boot());
for (Plugin bp : bootPlugins) {
if (Utils.isAutoEnabled(bp)) {
try {
bp.configure(Collections.emptyMap());
} catch (IllegalArgumentException e) {
if (JlinkTask.DEBUG) {
System.err.println("Plugin " + bp.getName() + " threw exception with config: {}");
e.printStackTrace();
}
throw e;
}
plugins.add(bp);
}
}
return new PluginsConfiguration(plugins, pluginsConfig.getImageBuilder(),
pluginsConfig.getLastSorterPluginName());
}
/**
* Post process the image with a plugin configuration.
*
* @param image Existing image.
* @param plugins Plugins cannot be null
*/
public void postProcess(ExecutableImage image, List<Plugin> plugins) {
Objects.requireNonNull(image);
Objects.requireNonNull(plugins);
try {
JlinkTask.postProcessImage(image, plugins);
} catch (Exception ex) {
throw new PluginException(ex);
}
}
}