< prev index next >

src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java

Print this page




  61 import jdk.tools.jlink.plugin.ResourcePool;
  62 import jdk.tools.jlink.plugin.ResourcePoolEntry;
  63 import jdk.tools.jlink.plugin.ResourcePoolModule;
  64 import jdk.tools.jlink.plugin.PluginException;
  65 
  66 /**
  67  *
  68  * Default Image Builder. This builder creates the default runtime image layout.
  69  */
  70 public final class DefaultImageBuilder implements ImageBuilder {
  71 
  72     /**
  73      * The default java executable Image.
  74      */
  75     static final class DefaultExecutableImage implements ExecutableImage {
  76 
  77         private final Path home;
  78         private final List<String> args;
  79         private final Set<String> modules;
  80 
  81         public DefaultExecutableImage(Path home, Set<String> modules) {
  82             this(home, modules, createArgs(home));
  83         }
  84 
  85         private DefaultExecutableImage(Path home, Set<String> modules,
  86                 List<String> args) {
  87             Objects.requireNonNull(home);
  88             Objects.requireNonNull(args);
  89             if (!Files.exists(home)) {
  90                 throw new IllegalArgumentException("Invalid image home");
  91             }
  92             this.home = home;
  93             this.modules = Collections.unmodifiableSet(modules);
  94             this.args = Collections.unmodifiableList(args);
  95         }
  96 
  97         private static List<String> createArgs(Path home) {
  98             Objects.requireNonNull(home);
  99             List<String> javaArgs = new ArrayList<>();
 100             javaArgs.add(home.resolve("bin").
 101                     resolve(getJavaProcessName()).toString());
 102             return javaArgs;

 103         }
 104 
 105         @Override
 106         public Path getHome() {
 107             return home;
 108         }
 109 
 110         @Override
 111         public Set<String> getModules() {
 112             return modules;
 113         }
 114 
 115         @Override
 116         public List<String> getExecutionArgs() {
 117             return args;
 118         }
 119 
 120         @Override
 121         public void storeLaunchArgs(List<String> args) {
 122             try {
 123                 patchScripts(this, args);
 124             } catch (IOException ex) {
 125                 throw new UncheckedIOException(ex);
 126             }
 127         }
 128     }
 129 
 130     private final Path root;
 131     private final Path mdir;
 132     private final Set<String> modules = new HashSet<>();

 133 
 134     /**
 135      * Default image builder constructor.
 136      *
 137      * @param root The image root directory.
 138      * @throws IOException
 139      */
 140     public DefaultImageBuilder(Path root) throws IOException {
 141         Objects.requireNonNull(root);
 142 
 143         this.root = root;
 144         this.mdir = root.resolve("lib");
 145         Files.createDirectories(mdir);
 146     }
 147 
 148     private void storeFiles(Set<String> modules, Properties release) throws IOException {
 149         if (release != null) {
 150             addModules(release, modules);
 151             File r = new File(root.toFile(), "release");
 152             try (FileOutputStream fo = new FileOutputStream(r)) {


 154             }
 155         }
 156     }
 157 
 158     private void addModules(Properties props, Set<String> modules) throws IOException {
 159         StringBuilder builder = new StringBuilder();
 160         int i = 0;
 161         for (String m : modules) {
 162             builder.append(m);
 163             if (i < modules.size() - 1) {
 164                 builder.append(",");
 165             }
 166             i++;
 167         }
 168         props.setProperty("MODULES", builder.toString());
 169     }
 170 
 171     @Override
 172     public void storeFiles(ResourcePool files) {
 173         try {




 174             files.entries().forEach(f -> {
 175                 if (!f.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)) {
 176                     try {
 177                         accept(f);
 178                     } catch (IOException ioExp) {
 179                         throw new UncheckedIOException(ioExp);
 180                     }
 181                 }
 182             });
 183             files.moduleView().modules().forEach(m -> {
 184                 // Only add modules that contain packages
 185                 if (!m.packages().isEmpty()) {
 186                     modules.add(m.name());
 187                 }
 188             });
 189             storeFiles(modules, releaseProperties(files));

 190 
 191             if (Files.getFileStore(root).supportsFileAttributeView(PosixFileAttributeView.class)) {
 192                 // launchers in the bin directory need execute permission
 193                 Path bin = root.resolve("bin");
 194                 if (Files.isDirectory(bin)) {
 195                     Files.list(bin)
 196                             .filter(f -> !f.toString().endsWith(".diz"))
 197                             .filter(f -> Files.isRegularFile(f))
 198                             .forEach(this::setExecutable);
 199                 }
 200 
 201                 // jspawnhelper is in lib or lib/<arch>
 202                 Path lib = root.resolve("lib");
 203                 if (Files.isDirectory(lib)) {
 204                     Files.find(lib, 2, (path, attrs) -> {
 205                         return path.getFileName().toString().equals("jspawnhelper")
 206                                 || path.getFileName().toString().equals("jexec");
 207                     }).forEach(this::setExecutable);
 208                 }
 209             }
 210 
 211             prepareApplicationFiles(files, modules);
 212         } catch (IOException ex) {
 213             throw new PluginException(ex);
 214         }
 215     }
 216 
 217     private Properties releaseProperties(ResourcePool pool) throws IOException {
 218         Properties props = new Properties();
 219         Optional<ResourcePoolModule> javaBase = pool.moduleView().findModule("java.base");
 220         javaBase.ifPresent(mod -> {
 221             // fill release information available from transformed "java.base" module!
 222             ModuleDescriptor desc = mod.descriptor();
 223             desc.osName().ifPresent(s -> props.setProperty("OS_NAME", s));
 224             desc.osVersion().ifPresent(s -> props.setProperty("OS_VERSION", s));
 225             desc.osArch().ifPresent(s -> props.setProperty("OS_ARCH", s));
 226             props.setProperty("JAVA_VERSION", System.getProperty("java.version"));
 227         });
 228 





 229         Optional<ResourcePoolEntry> release = pool.findEntry("/java.base/release");
 230         if (release.isPresent()) {
 231             try (InputStream is = release.get().content()) {
 232                 props.load(is);
 233             }
 234         }
 235 
 236         return props;
 237     }
 238 
 239     /**
 240      * Generates launcher scripts.
 241      *
 242      * @param imageContent The image content.
 243      * @param modules The set of modules that the runtime image contains.
 244      * @throws IOException
 245      */
 246     protected void prepareApplicationFiles(ResourcePool imageContent, Set<String> modules) throws IOException {
 247         // generate launch scripts for the modules with a main class
 248         for (String module : modules) {


 356     }
 357 
 358     private Path destFile(String dir, String filename) {
 359         return root.resolve(dir).resolve(filename);
 360     }
 361 
 362     private void writeEntry(InputStream in, Path dstFile) throws IOException {
 363         Objects.requireNonNull(in);
 364         Objects.requireNonNull(dstFile);
 365         Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
 366         Files.copy(in, dstFile);
 367     }
 368 
 369     private void writeSymEntry(Path dstFile, Path target) throws IOException {
 370         Objects.requireNonNull(dstFile);
 371         Objects.requireNonNull(target);
 372         Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
 373         Files.createLink(dstFile, target);
 374     }
 375 
 376     private static String nativeDir(String filename) {
 377         if (isWindows()) {
 378             if (filename.endsWith(".dll") || filename.endsWith(".diz")
 379                     || filename.endsWith(".pdb") || filename.endsWith(".map")) {
 380                 return "bin";
 381             } else {
 382                 return "lib";
 383             }
 384         } else {
 385             return "lib";
 386         }
 387     }
 388 
 389     private static boolean isWindows() {
 390         return System.getProperty("os.name").startsWith("Windows");
 391     }
 392 
 393     /**
 394      * chmod ugo+x file
 395      */
 396     private void setExecutable(Path file) {
 397         try {
 398             Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
 399             perms.add(PosixFilePermission.OWNER_EXECUTE);
 400             perms.add(PosixFilePermission.GROUP_EXECUTE);
 401             perms.add(PosixFilePermission.OTHERS_EXECUTE);
 402             Files.setPosixFilePermissions(file, perms);
 403         } catch (IOException ioe) {
 404             throw new UncheckedIOException(ioe);
 405         }
 406     }
 407 
 408     private static void createUtf8File(File file, String content) throws IOException {
 409         try (OutputStream fout = new FileOutputStream(file);
 410                 Writer output = new OutputStreamWriter(fout, "UTF-8")) {


 435                                 append(pattern);
 436                         for (String s : args) {
 437                             builder.append(s).append(" ");
 438                         }
 439                         String remain = str.substring(index + pattern.length());
 440                         builder.append(remain);
 441                         str = builder.toString();
 442                         try (BufferedWriter writer = Files.newBufferedWriter(p,
 443                                 StandardCharsets.ISO_8859_1,
 444                                 StandardOpenOption.WRITE)) {
 445                             writer.write(str);
 446                         }
 447                     }
 448                 } catch (IOException ex) {
 449                     throw new RuntimeException(ex);
 450                 }
 451             });
 452         }
 453     }
 454 
 455     private static String getJavaProcessName() {
 456         return isWindows() ? "java.exe" : "java";
 457     }
 458 
 459     public static ExecutableImage getExecutableImage(Path root) {
 460         if (Files.exists(root.resolve("bin").resolve(getJavaProcessName()))) {


 461             return new DefaultExecutableImage(root, retrieveModules(root));
 462         }
 463         return null;
 464     }
 465 
 466     private static Set<String> retrieveModules(Path root) {
 467         Path releaseFile = root.resolve("release");
 468         Set<String> modules = new HashSet<>();
 469         if (Files.exists(releaseFile)) {
 470             Properties release = new Properties();
 471             try (FileInputStream fi = new FileInputStream(releaseFile.toFile())) {
 472                 release.load(fi);
 473             } catch (IOException ex) {
 474                 System.err.println("Can't read release file " + ex);
 475             }
 476             String mods = release.getProperty("MODULES");
 477             if (mods != null) {
 478                 String[] arr = mods.split(",");
 479                 for (String m : arr) {
 480                     modules.add(m.trim());


  61 import jdk.tools.jlink.plugin.ResourcePool;
  62 import jdk.tools.jlink.plugin.ResourcePoolEntry;
  63 import jdk.tools.jlink.plugin.ResourcePoolModule;
  64 import jdk.tools.jlink.plugin.PluginException;
  65 
  66 /**
  67  *
  68  * Default Image Builder. This builder creates the default runtime image layout.
  69  */
  70 public final class DefaultImageBuilder implements ImageBuilder {
  71 
  72     /**
  73      * The default java executable Image.
  74      */
  75     static final class DefaultExecutableImage implements ExecutableImage {
  76 
  77         private final Path home;
  78         private final List<String> args;
  79         private final Set<String> modules;
  80 
  81         DefaultExecutableImage(Path home, Set<String> modules) {





  82             Objects.requireNonNull(home);

  83             if (!Files.exists(home)) {
  84                 throw new IllegalArgumentException("Invalid image home");
  85             }
  86             this.home = home;
  87             this.modules = Collections.unmodifiableSet(modules);
  88             this.args = createArgs(home);
  89         }
  90 
  91         private static List<String> createArgs(Path home) {
  92             Objects.requireNonNull(home);
  93             List<String> javaArgs = new ArrayList<>();
  94             Path binDir = home.resolve("bin");
  95             String java = Files.exists(binDir.resolve("java"))? "java" : "java.exe";
  96             javaArgs.add(binDir.resolve(java).toString());
  97             return Collections.unmodifiableList(javaArgs);
  98         }
  99 
 100         @Override
 101         public Path getHome() {
 102             return home;
 103         }
 104 
 105         @Override
 106         public Set<String> getModules() {
 107             return modules;
 108         }
 109 
 110         @Override
 111         public List<String> getExecutionArgs() {
 112             return args;
 113         }
 114 
 115         @Override
 116         public void storeLaunchArgs(List<String> args) {
 117             try {
 118                 patchScripts(this, args);
 119             } catch (IOException ex) {
 120                 throw new UncheckedIOException(ex);
 121             }
 122         }
 123     }
 124 
 125     private final Path root;
 126     private final Path mdir;
 127     private final Set<String> modules = new HashSet<>();
 128     private String targetOsName;
 129 
 130     /**
 131      * Default image builder constructor.
 132      *
 133      * @param root The image root directory.
 134      * @throws IOException
 135      */
 136     public DefaultImageBuilder(Path root) throws IOException {
 137         Objects.requireNonNull(root);
 138 
 139         this.root = root;
 140         this.mdir = root.resolve("lib");
 141         Files.createDirectories(mdir);
 142     }
 143 
 144     private void storeFiles(Set<String> modules, Properties release) throws IOException {
 145         if (release != null) {
 146             addModules(release, modules);
 147             File r = new File(root.toFile(), "release");
 148             try (FileOutputStream fo = new FileOutputStream(r)) {


 150             }
 151         }
 152     }
 153 
 154     private void addModules(Properties props, Set<String> modules) throws IOException {
 155         StringBuilder builder = new StringBuilder();
 156         int i = 0;
 157         for (String m : modules) {
 158             builder.append(m);
 159             if (i < modules.size() - 1) {
 160                 builder.append(",");
 161             }
 162             i++;
 163         }
 164         props.setProperty("MODULES", builder.toString());
 165     }
 166 
 167     @Override
 168     public void storeFiles(ResourcePool files) {
 169         try {
 170             // populate release properties up-front. targetOsName
 171             // field is assigned from there and used elsewhere.
 172             Properties release = releaseProperties(files);
 173 
 174             files.entries().forEach(f -> {
 175                 if (!f.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)) {
 176                     try {
 177                         accept(f);
 178                     } catch (IOException ioExp) {
 179                         throw new UncheckedIOException(ioExp);
 180                     }
 181                 }
 182             });
 183             files.moduleView().modules().forEach(m -> {
 184                 // Only add modules that contain packages
 185                 if (!m.packages().isEmpty()) {
 186                     modules.add(m.name());
 187                 }
 188             });
 189 
 190             storeFiles(modules, release);
 191 
 192             if (Files.getFileStore(root).supportsFileAttributeView(PosixFileAttributeView.class)) {
 193                 // launchers in the bin directory need execute permission
 194                 Path bin = root.resolve("bin");
 195                 if (Files.isDirectory(bin)) {
 196                     Files.list(bin)
 197                             .filter(f -> !f.toString().endsWith(".diz"))
 198                             .filter(f -> Files.isRegularFile(f))
 199                             .forEach(this::setExecutable);
 200                 }
 201 
 202                 // jspawnhelper is in lib or lib/<arch>
 203                 Path lib = root.resolve("lib");
 204                 if (Files.isDirectory(lib)) {
 205                     Files.find(lib, 2, (path, attrs) -> {
 206                         return path.getFileName().toString().equals("jspawnhelper")
 207                                 || path.getFileName().toString().equals("jexec");
 208                     }).forEach(this::setExecutable);
 209                 }
 210             }
 211 
 212             prepareApplicationFiles(files, modules);
 213         } catch (IOException ex) {
 214             throw new PluginException(ex);
 215         }
 216     }
 217 
 218     private Properties releaseProperties(ResourcePool pool) throws IOException {
 219         Properties props = new Properties();
 220         Optional<ResourcePoolModule> javaBase = pool.moduleView().findModule("java.base");
 221         javaBase.ifPresent(mod -> {
 222             // fill release information available from transformed "java.base" module!
 223             ModuleDescriptor desc = mod.descriptor();
 224             desc.osName().ifPresent(s -> props.setProperty("OS_NAME", s));
 225             desc.osVersion().ifPresent(s -> props.setProperty("OS_VERSION", s));
 226             desc.osArch().ifPresent(s -> props.setProperty("OS_ARCH", s));
 227             props.setProperty("JAVA_VERSION", System.getProperty("java.version"));
 228         });
 229 
 230         this.targetOsName = props.getProperty("OS_NAME");
 231         if (this.targetOsName == null) {
 232             throw new RuntimeException("can't determine target OS from java.base descriptor");
 233         }
 234 
 235         Optional<ResourcePoolEntry> release = pool.findEntry("/java.base/release");
 236         if (release.isPresent()) {
 237             try (InputStream is = release.get().content()) {
 238                 props.load(is);
 239             }
 240         }
 241 
 242         return props;
 243     }
 244 
 245     /**
 246      * Generates launcher scripts.
 247      *
 248      * @param imageContent The image content.
 249      * @param modules The set of modules that the runtime image contains.
 250      * @throws IOException
 251      */
 252     protected void prepareApplicationFiles(ResourcePool imageContent, Set<String> modules) throws IOException {
 253         // generate launch scripts for the modules with a main class
 254         for (String module : modules) {


 362     }
 363 
 364     private Path destFile(String dir, String filename) {
 365         return root.resolve(dir).resolve(filename);
 366     }
 367 
 368     private void writeEntry(InputStream in, Path dstFile) throws IOException {
 369         Objects.requireNonNull(in);
 370         Objects.requireNonNull(dstFile);
 371         Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
 372         Files.copy(in, dstFile);
 373     }
 374 
 375     private void writeSymEntry(Path dstFile, Path target) throws IOException {
 376         Objects.requireNonNull(dstFile);
 377         Objects.requireNonNull(target);
 378         Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
 379         Files.createLink(dstFile, target);
 380     }
 381 
 382     private String nativeDir(String filename) {
 383         if (isWindows()) {
 384             if (filename.endsWith(".dll") || filename.endsWith(".diz")
 385                     || filename.endsWith(".pdb") || filename.endsWith(".map")) {
 386                 return "bin";
 387             } else {
 388                 return "lib";
 389             }
 390         } else {
 391             return "lib";
 392         }
 393     }
 394 
 395     private boolean isWindows() {
 396         return targetOsName.startsWith("Windows");
 397     }
 398 
 399     /**
 400      * chmod ugo+x file
 401      */
 402     private void setExecutable(Path file) {
 403         try {
 404             Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
 405             perms.add(PosixFilePermission.OWNER_EXECUTE);
 406             perms.add(PosixFilePermission.GROUP_EXECUTE);
 407             perms.add(PosixFilePermission.OTHERS_EXECUTE);
 408             Files.setPosixFilePermissions(file, perms);
 409         } catch (IOException ioe) {
 410             throw new UncheckedIOException(ioe);
 411         }
 412     }
 413 
 414     private static void createUtf8File(File file, String content) throws IOException {
 415         try (OutputStream fout = new FileOutputStream(file);
 416                 Writer output = new OutputStreamWriter(fout, "UTF-8")) {


 441                                 append(pattern);
 442                         for (String s : args) {
 443                             builder.append(s).append(" ");
 444                         }
 445                         String remain = str.substring(index + pattern.length());
 446                         builder.append(remain);
 447                         str = builder.toString();
 448                         try (BufferedWriter writer = Files.newBufferedWriter(p,
 449                                 StandardCharsets.ISO_8859_1,
 450                                 StandardOpenOption.WRITE)) {
 451                             writer.write(str);
 452                         }
 453                     }
 454                 } catch (IOException ex) {
 455                     throw new RuntimeException(ex);
 456                 }
 457             });
 458         }
 459     }
 460 




 461     public static ExecutableImage getExecutableImage(Path root) {
 462         Path binDir = root.resolve("bin");
 463         if (Files.exists(binDir.resolve("java")) ||
 464             Files.exists(binDir.resolve("java.exe"))) {
 465             return new DefaultExecutableImage(root, retrieveModules(root));
 466         }
 467         return null;
 468     }
 469 
 470     private static Set<String> retrieveModules(Path root) {
 471         Path releaseFile = root.resolve("release");
 472         Set<String> modules = new HashSet<>();
 473         if (Files.exists(releaseFile)) {
 474             Properties release = new Properties();
 475             try (FileInputStream fi = new FileInputStream(releaseFile.toFile())) {
 476                 release.load(fi);
 477             } catch (IOException ex) {
 478                 System.err.println("Can't read release file " + ex);
 479             }
 480             String mods = release.getProperty("MODULES");
 481             if (mods != null) {
 482                 String[] arr = mods.split(",");
 483                 for (String m : arr) {
 484                     modules.add(m.trim());
< prev index next >