1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.tools.jlink.internal; 26 27 import java.lang.reflect.Layer; 28 import java.nio.ByteOrder; 29 import java.nio.file.Path; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Objects; 35 import java.util.Set; 36 import jdk.tools.jlink.plugin.Plugin; 37 import jdk.tools.jlink.plugin.PluginException; 38 import jdk.tools.jlink.builder.ImageBuilder; 39 40 /** 41 * API to call jlink. 42 */ 43 public final class Jlink { 44 45 /** 46 * Create a plugin. 47 * 48 * @param name Plugin name 49 * @param configuration Plugin configuration. 50 * @param pluginsLayer Plugins Layer. null means boot layer. 51 * @return A new plugin or null if plugin is unknown. 52 */ 53 public static Plugin newPlugin(String name, 54 Map<String, String> configuration, Layer pluginsLayer) { 55 Objects.requireNonNull(name); 56 Objects.requireNonNull(configuration); 57 pluginsLayer = pluginsLayer == null ? Layer.boot() : pluginsLayer; 58 return PluginRepository.newPlugin(configuration, name, pluginsLayer); 59 } 60 61 /** 62 * A complete plugin configuration. Instances of this class are used to 63 * configure jlink. 64 */ 65 public static final class PluginsConfiguration { 66 67 private final List<Plugin> plugins; 68 private final ImageBuilder imageBuilder; 69 private final String lastSorterPluginName; 70 71 /** 72 * Empty plugins configuration. 73 */ 74 public PluginsConfiguration() { 75 this(Collections.emptyList()); 76 } 77 78 /** 79 * Plugins configuration. 80 * 81 * @param plugins List of plugins. 82 */ 83 public PluginsConfiguration(List<Plugin> plugins) { 84 this(plugins, null, null); 85 } 86 87 /** 88 * Plugins configuration with a last sorter and an ImageBuilder. No 89 * sorting can occur after the last sorter plugin. The ImageBuilder is 90 * in charge to layout the image content on disk. 91 * 92 * @param plugins List of transformer plugins. 93 * @param imageBuilder Image builder. 94 * @param lastSorterPluginName Name of last sorter plugin, no sorting 95 * can occur after it. 96 */ 97 public PluginsConfiguration(List<Plugin> plugins, 98 ImageBuilder imageBuilder, String lastSorterPluginName) { 99 this.plugins = plugins == null ? Collections.emptyList() 100 : plugins; 101 this.imageBuilder = imageBuilder; 102 this.lastSorterPluginName = lastSorterPluginName; 103 } 104 105 /** 106 * @return the plugins 107 */ 108 public List<Plugin> getPlugins() { 109 return plugins; 110 } 111 112 /** 113 * @return the imageBuilder 114 */ 115 public ImageBuilder getImageBuilder() { 116 return imageBuilder; 117 } 118 119 /** 120 * @return the lastSorterPluginName 121 */ 122 public String getLastSorterPluginName() { 123 return lastSorterPluginName; 124 } 125 126 @Override 127 public String toString() { 128 StringBuilder builder = new StringBuilder(); 129 builder.append("imagebuilder=").append(imageBuilder).append("\n"); 130 StringBuilder pluginsBuilder = new StringBuilder(); 131 for (Plugin p : plugins) { 132 pluginsBuilder.append(p).append(","); 133 } 134 builder.append("plugins=").append(pluginsBuilder).append("\n"); 135 builder.append("lastsorter=").append(lastSorterPluginName).append("\n"); 136 137 return builder.toString(); 138 } 139 } 140 141 /** 142 * Jlink configuration. Instances of this class are used to configure jlink. 143 */ 144 public static final class JlinkConfiguration { 145 146 private final List<Path> modulepaths; 147 private final Path output; 148 private final Set<String> modules; 149 private final Set<String> limitmods; 150 151 private final ByteOrder endian; 152 153 /** 154 * jlink configuration, 155 * 156 * @param output Output directory, must not exist. 157 * @param modulepaths Modules paths 158 * @param modules Root modules to resolve 159 * @param limitmods Limit the universe of observable modules 160 * @param endian Jimage byte order. Native order by default 161 */ 162 public JlinkConfiguration(Path output, 163 List<Path> modulepaths, 164 Set<String> modules, 165 Set<String> limitmods, 166 ByteOrder endian) { 167 this.output = output; 168 this.modulepaths = modulepaths == null ? Collections.emptyList() : modulepaths; 169 this.modules = modules == null ? Collections.emptySet() : modules; 170 this.limitmods = limitmods == null ? Collections.emptySet() : limitmods; 171 this.endian = endian == null ? ByteOrder.nativeOrder() : endian; 172 } 173 174 /** 175 * jlink configuration, 176 * 177 * @param output Output directory, must not exist. 178 * @param modulepaths Modules paths 179 * @param modules Root modules to resolve 180 * @param limitmods Limit the universe of observable modules 181 */ 182 public JlinkConfiguration(Path output, 183 List<Path> modulepaths, 184 Set<String> modules, 185 Set<String> limitmods) { 186 this(output, modulepaths, modules, limitmods, 187 ByteOrder.nativeOrder()); 188 } 189 190 /** 191 * @return the modulepaths 192 */ 193 public List<Path> getModulepaths() { 194 return modulepaths; 195 } 196 197 /** 198 * @return the byte ordering 199 */ 200 public ByteOrder getByteOrder() { 201 return endian; 202 } 203 204 /** 205 * @return the output 206 */ 207 public Path getOutput() { 208 return output; 209 } 210 211 /** 212 * @return the modules 213 */ 214 public Set<String> getModules() { 215 return modules; 216 } 217 218 /** 219 * @return the limitmods 220 */ 221 public Set<String> getLimitmods() { 222 return limitmods; 223 } 224 225 @Override 226 public String toString() { 227 StringBuilder builder = new StringBuilder(); 228 229 builder.append("output=").append(output).append("\n"); 230 StringBuilder pathsBuilder = new StringBuilder(); 231 for (Path p : modulepaths) { 232 pathsBuilder.append(p).append(","); 233 } 234 builder.append("modulepaths=").append(pathsBuilder).append("\n"); 235 236 StringBuilder modsBuilder = new StringBuilder(); 237 for (String p : modules) { 238 modsBuilder.append(p).append(","); 239 } 240 builder.append("modules=").append(modsBuilder).append("\n"); 241 242 StringBuilder limitsBuilder = new StringBuilder(); 243 for (String p : limitmods) { 244 limitsBuilder.append(p).append(","); 245 } 246 builder.append("limitmodules=").append(limitsBuilder).append("\n"); 247 builder.append("endian=").append(endian).append("\n"); 248 return builder.toString(); 249 } 250 } 251 252 /** 253 * Jlink instance constructor, if a security manager is set, the jlink 254 * permission is checked. 255 */ 256 public Jlink() { 257 if (System.getSecurityManager() != null) { 258 System.getSecurityManager(). 259 checkPermission(new JlinkPermission("jlink")); 260 } 261 } 262 263 /** 264 * Build the image. 265 * 266 * @param config Jlink config, must not be null. 267 * @throws PluginException 268 */ 269 public void build(JlinkConfiguration config) { 270 build(config, null); 271 } 272 273 /** 274 * Build the image with a plugin configuration. 275 * 276 * @param config Jlink config, must not be null. 277 * @param pluginsConfig Plugins config, can be null 278 * @throws PluginException 279 */ 280 public void build(JlinkConfiguration config, PluginsConfiguration pluginsConfig) { 281 Objects.requireNonNull(config); 282 if (pluginsConfig == null) { 283 pluginsConfig = new PluginsConfiguration(); 284 } 285 286 // add all auto-enabled plugins from boot layer 287 pluginsConfig = addAutoEnabledPlugins(pluginsConfig); 288 289 try { 290 JlinkTask.createImage(config, pluginsConfig); 291 } catch (Exception ex) { 292 throw new PluginException(ex); 293 } 294 } 295 296 private PluginsConfiguration addAutoEnabledPlugins(PluginsConfiguration pluginsConfig) { 297 List<Plugin> plugins = new ArrayList<>(pluginsConfig.getPlugins()); 298 List<Plugin> bootPlugins = PluginRepository.getPlugins(Layer.boot()); 299 for (Plugin bp : bootPlugins) { 300 if (Utils.isAutoEnabled(bp)) { 301 try { 302 bp.configure(Collections.emptyMap()); 303 } catch (IllegalArgumentException e) { 304 if (JlinkTask.DEBUG) { 305 System.err.println("Plugin " + bp.getName() + " threw exception with config: {}"); 306 e.printStackTrace(); 307 } 308 throw e; 309 } 310 plugins.add(bp); 311 } 312 } 313 return new PluginsConfiguration(plugins, pluginsConfig.getImageBuilder(), 314 pluginsConfig.getLastSorterPluginName()); 315 } 316 317 /** 318 * Post process the image with a plugin configuration. 319 * 320 * @param image Existing image. 321 * @param plugins Plugins cannot be null 322 */ 323 public void postProcess(ExecutableImage image, List<Plugin> plugins) { 324 Objects.requireNonNull(image); 325 Objects.requireNonNull(plugins); 326 try { 327 JlinkTask.postProcessImage(image, plugins); 328 } catch (Exception ex) { 329 throw new PluginException(ex); 330 } 331 } 332 }