All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.bedrock.runtime.java.options.JavaModules Maven / Gradle / Ivy

/*
 * File: UseModules.java
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * The contents of this file are subject to the terms and conditions of
 * the Common Development and Distribution License 1.0 (the "License").
 *
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the License by consulting the LICENSE.txt file
 * distributed with this file, or by consulting https://oss.oracle.com/licenses/CDDL
 *
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file LICENSE.txt.
 *
 * MODIFICATIONS:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 */

package com.oracle.bedrock.runtime.java.options;

import com.oracle.bedrock.ComposableOption;
import com.oracle.bedrock.Option;
import com.oracle.bedrock.OptionsByType;
import com.oracle.bedrock.runtime.java.ClassPath;
import com.oracle.bedrock.runtime.java.JavaApplication;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * An {@link Option} to specify that a {@link JavaApplication} should run using Java 9 modules.
 * 

* Copyright (c) 2017. All Rights Reserved. Oracle Corporation.
* Oracle is a registered trademark of Oracle Corporation and/or its affiliates. * * @author JK */ public class JavaModules implements ComposableOption, JvmOption { /** * Is modular mode enabled? */ private final boolean enabled; /** * The modules to add. */ private final Set modules; /** * The modules to exclude. */ private final Set excludes; /** * The modules to export. */ private final Set exports; /** * The modules to patch. */ private final Set patches; /** * The values to use in the --add-reads parameter. */ private final Set reading; /** * The values to use in the --add-opens parameter. */ private final Set opens; /** * The optional class path to use. */ private final ClassPath classPath; /** * The system property to check to determine whether modules should be used. */ public static final String PROP_USE_MODULES = "com.oracle.bedrock.modules.enabled"; /** * Constructs a {@link JavaModules} for the specified value. * * @param enabled if modular mode is enabled * @param modules the set of modules to add and export to bedrock */ private JavaModules(boolean enabled, Set modules, Set excludes, Set exports, Set patches, Set reading, Set opens, ClassPath classPath) { this.enabled = enabled; this.modules = modules; this.excludes = excludes; this.exports = exports; this.patches = patches; this.reading = reading; this.opens = opens; this.classPath = classPath; } /** * Obtains a {@link JavaModules} option that enables * running an application as a post Java 9 modular process. * * @return a {@link JavaModules} option to enable * a modular JVM process */ public static JavaModules enabled() { return new JavaModules(true, Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), ClassPath.ofSystem()); } /** * Obtains a {@link JavaModules} option that enables * running an application as a Java process using class * path instead of modules. * * @return a {@link JavaModules} option to disable * a modular JVM process */ public static JavaModules disabled() { return new JavaModules(false, Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), ClassPath.ofSystem()); } /** * Obtains a {@link JavaModules} option that enables * running an application as a Java process using class * path instead of modules. * * @return a {@link JavaModules} option to disable * a modular JVM process */ @OptionsByType.Default public static JavaModules automatic() { RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); List arguments = bean.getInputArguments(); return automatic(useModules(), arguments); } static JavaModules automatic(boolean useModules, List arguments) { Set patches = new HashSet<>(); Set modules = new HashSet<>(); Set reads = new HashSet<>(); Set opens = new HashSet<>(); Set exports = new HashSet<>(); int end = arguments.size() - 1; for (int i = 0; i <= end; i++) { String arg = arguments.get(i); if (arg.startsWith("--patch-module=")) { patches.add(arg.substring(15)); } else if (arg.equals("--patch-module") && i < end) { patches.add(arguments.get(++i)); } else if (arg.startsWith("--add-modules=")) { modules.add(arg.substring(14)); } else if (arg.equals("--add-modules") && i < end) { modules.add(arguments.get(++i)); } else if (arg.startsWith("--add-reads=")) { reads.add(arg.substring(12)); } else if (arg.equals("--add-reads") && i < end) { reads.add(arguments.get(++i)); } else if (arg.startsWith("--add-opens=")) { opens.add(arg.substring(12)); } else if (arg.equals("--add-opens") && i < end) { opens.add(arguments.get(++i)); } else if (arg.startsWith("--add-exports=")) { exports.add(arg.substring(14)); } else if (arg.equals("--add-exports") && i < end) { exports.add(arguments.get(++i)); } } return new JavaModules(useModules, modules, Collections.emptySet(), exports, patches, reads, opens, ClassPath.ofSystem()); } /** * Returns {@code true} if modules should be used, based on the * value of the {@link #PROP_USE_MODULES} system property. * * @return {@code true} if modules should be used */ public static boolean useModules() { String useModulesProperty = System.getProperty(PROP_USE_MODULES); if (useModulesProperty == null || useModulesProperty.isBlank()) { String modulePath = System.getProperty("jdk.module.path"); return modulePath != null && !modulePath.isBlank(); } return Boolean.parseBoolean(useModulesProperty); } /** * Obtain a copy of this {@link JavaModules} option * with the specified modules in the {@code --add-modules} * option. * * @param modules the modules to list in the {@code --add-modules} * JVM option * * @return a copy of this {@link JavaModules} option * with the specified modules in the * {@code --add-modules} option. */ public JavaModules adding(String... modules) { if (modules.length == 0) { return this; } return new JavaModules(true, toSet(this.modules, modules), this.excludes, this.exports, this.patches, this.reading, this.opens, this.classPath); } /** * Obtain a copy of this {@link JavaModules} option * excluding the specified modules from the {@code --add-modules} * option. * * @param modules the modules to exclude from the {@code --add-modules} * JVM option * * @return a copy of this {@link JavaModules} option * with the specified modules excluded from the * {@code --add-modules} option. */ public JavaModules excluding(String... modules) { if (modules.length == 0) { return this; } return new JavaModules(true, this.modules, toSet(this.excludes, modules), this.exports, this.patches, this.reading, this.opens, this.classPath); } /** * Obtain a copy of this {@link JavaModules} option * with the specified modules in the {@code --add-exports} * option. * * @param exports the module export statement to list * in the {@code --add-exports} JVM option * * @return a copy of this {@link JavaModules} option * with the specified modules in the * {@code --add-exports} option. */ public JavaModules exporting(String... exports) { return new JavaModules(true, this.modules, this.excludes, toSet(this.exports, exports), this.patches, this.reading, this.opens, this.classPath); } /** * Obtain a copy of this {@link JavaModules} option * with the specified modules in the {@code --add-exports} * option. * * @param toModule the name of the module to export to * @param modules the modules to list in the * {@code --add-exports} JVM option * * @return a copy of this {@link JavaModules} option * with the specified modules in the * {@code --add-exports} option */ public JavaModules exportingTo(String toModule, String... modules) { if (modules.length == 0) { return this; } Set exports = new LinkedHashSet<>(this.exports); Arrays.stream(modules) .map(m -> m + "/" + m + "=" + toModule) .forEach(exports::add); return new JavaModules(true, this.modules, this.excludes, exports, this.patches, this.reading, this.opens, this.classPath); } /** * Obtain a copy of this {@link JavaModules} option * with the specified modules exported to * {@code com.oracle.bedrock.runtime} in the * {@code --add-exports} option. * * @param modules the modules to export to Bedrock in the * {@code --add-exports} JVM option * * @return a copy of this {@link JavaModules} option * with the specified modules exported to * {@code com.oracle.bedrock.runtime} in the * {@code --add-exports} option */ public JavaModules exportingToBedrock(String... modules) { return exportingTo("com.oracle.bedrock.runtime", modules); } /** * Obtain a copy of this {@link JavaModules} option * with the specified modules in the {@code --add-opens} * option. * * @param module the module name to open * @param _package the name of the package within the provided * module * @param targetModule the name of the module the code within * the specified module and * package should be opened to * * @return a copy of this {@link JavaModules} option * with the specified modules/packages exported opened via * the {@code --add-opens} option */ public JavaModules opens(String module, String _package, String targetModule) { if (module == null || _package == null || targetModule == null) { return this; } Set opens = new LinkedHashSet<>(this.opens); opens.add(module + '/' + _package + '=' + targetModule); return new JavaModules(true, this.modules, this.excludes, this.exports, this.patches, this.reading, opens, this.classPath); } /** * Obtain a copy of this {@link JavaModules} option * with the specified patch module statements in * the {@code --patch-module} JVM option. * * @param patches the patch module statements to list * in the {@code --patch-module} JVM option * * @return a copy of this {@link JavaModules} option * with the specified module patch statements in * the {@code --patch-module} JVM option. */ public JavaModules patching(String... patches) { if (patches.length == 0) { return this; } return new JavaModules(true, this.modules, this.excludes, this.exports, toSet(this.patches, patches), this.reading, this.opens, this.classPath); } /** * Obtain a copy of this {@link JavaModules} option * with the specified reads module statements in * the {@code --add-reads} JVM option. * * @param reads the reads module statements to list * in the {@code --add-reads} JVM option * * @return a copy of this {@link JavaModules} option * with the specified reads module statements in * the {@code --add-reads} JVM option. */ public JavaModules reading(String... reads) { if (reads.length == 0) { return this; } return new JavaModules(true, this.modules, this.excludes, this.exports, this.patches, toSet(this.reading, reads), this.opens, this.classPath); } /** * Set the {@link ClassPath} to use as well as a module path. * * @param classPath the {@link ClassPath} to use as well as a module path * * @return a copy of this {@link JavaModules} option * with the specified classpath. */ public JavaModules withClassPath(ClassPath classPath) { if (classPath == null) { classPath = ClassPath.ofSystem(); } return new JavaModules(true, this.modules, this.excludes, this.exports, this.patches, this.reading, this.opens, classPath); } /** * Add a {@link ClassPath} to use as well as a module path, appending the * {@link ClassPath} to any other classpath that this {@link JavaModules} * may already have. * * @param classPath a {@link ClassPath} to use as well as a module path * * @return a copy of this {@link JavaModules} option * with the specified addition of the classpath. */ public JavaModules appendingToClassPath(ClassPath classPath) { if (classPath == null || classPath.isEmpty()) { return this; } return new JavaModules(true, this.modules, this.excludes, this.exports, this.patches, this.reading, this.opens, new ClassPath(this.classPath, classPath)); } /** * Obtain the {@link ClassPath} to use as well as a module path. * * @return the {@link ClassPath} to use as well as a module path */ public ClassPath getClassPath() { return classPath; } /** * Determine whether a JVM application should be run with Modules. * * @return {@code true} if a JVM application should be run with Modules */ public boolean isEnabled() { return enabled; } private static Set toSet(Set set, String[] modules) { Set moduleSet; if (modules == null || modules.length == 0) { moduleSet = set; } else { moduleSet = new LinkedHashSet<>(set); Arrays.stream(modules) .filter(Objects::nonNull) .forEach(moduleSet::add); } return moduleSet; } @Override public JavaModules compose(JavaModules other) { Set setAdd = new LinkedHashSet<>(this.modules); Set setExclude = new LinkedHashSet<>(this.excludes); Set setExport = new LinkedHashSet<>(this.exports); Set setPatch = new LinkedHashSet<>(this.patches); Set setReads = new LinkedHashSet<>(this.reading); Set setOpens = new LinkedHashSet<>(this.opens); setAdd.addAll(other.modules); setExclude.addAll(other.excludes); setExport.addAll(other.exports); setPatch.addAll(other.patches); setReads.addAll(other.reading); setOpens.addAll(other.opens); boolean isEnabled = this.enabled && other.enabled; ClassPath classPath = new ClassPath(this.classPath, other.classPath); return new JavaModules(isEnabled, setAdd, setExclude, setExport, setPatch, setReads, setOpens, classPath); } @Override public Iterable resolve(OptionsByType optionsByType) { List opts = new ArrayList<>(); if (enabled) { if (!modules.isEmpty()) { // syntax: --add-modules module[,module...] opts.add("--add-modules"); if (excludes.isEmpty()) { opts.add(String.join(",", modules)); } else { LinkedHashSet set = new LinkedHashSet<>(modules); set.removeAll(excludes); opts.add(String.join(",", set)); } } if (!exports.isEmpty()) { // syntax: --add-exports module/package=target-module(,target-module)* // may be used more than once if (excludes.isEmpty()) { exports.forEach(export -> { opts.add("--add-exports"); opts.add(export); }); } else { for (String export : exports) { String[] parts = export.split("/"); String module = parts[0]; if (!excludes.contains(module) && parts.length > 1) { String[] targetParts = parts[1].split("="); if (targetParts.length > 1) { String exportsToModules = Arrays.stream(targetParts[1].split(",")) .filter(s -> !excludes.contains(s)) .collect(Collectors.joining(",")); if (exportsToModules.length() > 0) { opts.add("--add-exports"); opts.add(module + "/" + targetParts[0] + "=" + exportsToModules); } } } } } } if (!opens.isEmpty()) { // syntax: --add-opens module/package=target-module(,target-module)* // may be used more than once if (excludes.isEmpty()) { opens.forEach(open -> { opts.add("--add-opens"); opts.add(open); }); } else { for (String open : opens) { String[] parts = open.split("/"); String module = parts[0]; if (!excludes.contains(module) && parts.length > 1) { String[] openParts = parts[1].split("="); if (openParts.length > 1 && !excludes.contains(openParts[1])) { opts.add("--add-opens"); opts.add(open); } } } } } if (!patches.isEmpty()) { // syntax: --patch-module module=file(;file)* // may be used more than once if (excludes.isEmpty()) { patches.forEach(patch -> { opts.add("--patch-module"); opts.add(patch); }); } else { for (String patch : patches) { String module = patch.split("=")[0]; if (!excludes.contains(module)) { opts.add("--patch-module"); opts.add(patch); } } } } if (!reading.isEmpty()) { // syntax: --add-reads module=target-module(,target-module)* // may be used more than once if (excludes.isEmpty()) { reading.forEach(read -> { opts.add("--add-reads"); opts.add(read); }); } else { for (String reads : reading) { String[] parts = reads.split("="); String module = parts[0]; if (!excludes.contains(module) && parts.length > 1) { String readsModules = Arrays.stream(parts[1].split(",")) .filter(s -> !excludes.contains(s)) .collect(Collectors.joining(",")); if (readsModules.length() > 0) { opts.add("--add-reads"); opts.add(module + "=" + readsModules); } } } } } } return opts; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } JavaModules modules1 = (JavaModules) o; if (enabled != modules1.enabled) { return false; } if (modules != null ? !modules.equals(modules1.modules) : modules1.modules != null) { return false; } if (excludes != null ? !excludes.equals(modules1.excludes) : modules1.excludes != null) { return false; } if (exports != null ? !exports.equals(modules1.exports) : modules1.exports != null) { return false; } if (patches != null ? !patches.equals(modules1.patches) : modules1.patches != null) { return false; } if (opens != null ? !opens.equals(modules1.opens) : modules1.opens != null) { return false; } return reading != null ? reading.equals(modules1.reading) : modules1.reading == null; } @Override public int hashCode() { int result = (enabled ? 1 : 0); result = 31 * result + (modules != null ? modules.hashCode() : 0); result = 31 * result + (excludes != null ? excludes.hashCode() : 0); result = 31 * result + (exports != null ? exports.hashCode() : 0); result = 31 * result + (patches != null ? patches.hashCode() : 0); result = 31 * result + (opens != null ? opens.hashCode() : 0); result = 31 * result + (reading != null ? reading.hashCode() : 0); return result; } @Override public String toString() { return "JavaModules(" + String.join(" ", resolve(OptionsByType.empty())) + ")"; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy