/* * Copyright (c) 2013, 2016, 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 jdk.testlibrary.tasks; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import static java.util.Arrays.asList; import static java.util.Arrays.stream; import static java.util.Collections.EMPTY_LIST; import java.util.List; import java.util.Map; import java.util.function.Function; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import java.util.stream.Stream; /** * A task to configure and run the Java launcher. */ public class JavaTask extends AbstractTask { /** * {@code --class-path} */ public static final String CLASS_PATH = "--class-path"; /** * {@code --module-path} */ public static final String MODULE_PATH = "--module-path"; /** * {@code --upgrade-module-path} */ public static final String UPGRADE_MODULE_PATH = "--upgrade-module-path"; /** * {@code --add-modules} */ public static final String ADD_MODULES = "--add-modules"; /** * {@code --limit-modules} */ public static final String LIMIT_MODULES = "--limit-modules"; /** * {@code --add-exports} */ public static final String ADD_EXPORTS = "--add-exports"; /** * {@code --add-reads} */ public static final String ADD_READS = "--add-reads"; /** * {@code --patch-module} */ public static final String PATCH_MODULE = "--patch-module"; private List classPath; private List modulePath; private List upgradeModulePath; private String mainClass; private String module; private List vmOptions; private List classArgs; private List limitModules; private List addModules; private List standardOptions; private List addExports = new ArrayList<>(); private List addReads = new ArrayList<>(); private List patchModule = new ArrayList<>(); /** * Create a task to run the Java launcher, using {@code EXEC} mode. */ public JavaTask() { super(Task.Mode.EXEC); standardOptions = Stream.of("test.vm.opts", "test.java.opts") .map(p -> System.getProperty(p)) .filter(p -> p != null && !p.isEmpty()) .map(o -> asList(o.split(" +"))) .flatMap(l -> l.stream()).collect(toList()); } /** * Sets the classpath. * @param classPath the classpath * @return this task object */ public JavaTask classPath(String... classPath) { this.classPath = stream(classPath).collect(toList()); return this; } /** * Sets the classpath. * @param classPath the classpath * @return this task object */ public JavaTask classPath(Path... classPath) { this.classPath = stream(classPath) .map(Object::toString).collect(toList()); return this; } /** * Sets the module path. * @param modulePath the module path * @return this task object */ public JavaTask modulePath(String... modulePath) { this.modulePath = stream(modulePath).collect(toList()); return this; } /** * Sets the module path. * @param modulePath the module path * @return this task object */ public JavaTask modulePath(Path... modulePath) { this.modulePath = stream(modulePath) .map(Object::toString).collect(toList()); return this; } /** * Sets the upgrade module path. * @param upgradeModulePath the upgrade module path * @return this task object */ public JavaTask upgradeModulePath(String... upgradeModulePath) { this.upgradeModulePath = stream(upgradeModulePath).collect(toList()); return this; } /** * Sets the upgrade module path. * @param upgradeModulePath the upgrade module path * @return this task object */ public JavaTask upgradeModulePath(Path... upgradeModulePath) { this.upgradeModulePath = stream(upgradeModulePath) .map(Object::toString).collect(toList()); return this; } /** * Adds single occurrence of the {@code --add-exports} option. * @param addExports argument for the option. * @return this task object */ public JavaTask addExports(String addExports) { this.addExports.add(addExports); return this; } /** * Adds single occurrence of the {@code --add-exports} option. * @param source source module * @param pkg exported package * @param targets target modules * @return this task object */ public JavaTask addExports(String source, String pkg, String... targets) { return addExports(source + "/" + pkg + "=" + stream(targets).collect(joining(","))); } /** * Sets the {@code --add-modules} option. * @param addModules parameter for the option * @return this task object */ public JavaTask addModules(String... addModules) { this.addModules = asList(addModules); return this; } /** * Adds single occurrence of the {@code --add-reads} option. * @param addReads argument for the option * @return this task object */ public JavaTask addReads(String addReads) { this.addReads.add(addReads); return this; } /** * Adds single occurrence of the {@code --add-reads} option. * @param source source module * @param targets target modules * @return this task object */ public JavaTask addReads(String source, String... targets) { return addReads(source + "=" + stream(targets).collect(joining(","))); } /** * Adds single occurrence of the {@code --patch-module} option. * @param patchModule argument for the option * @return this task object */ public JavaTask patchModule(String patchModule) { this.patchModule.add(patchModule); return this; } /** * Adds single occurrence of the {@code --patch-module} option. * @param module module to be overridden or augmented * @param files jar files and directories * @return this task object */ public JavaTask patchModule(String module, String... files) { return patchModule(module + "=" + stream(files).collect(joining(","))); } /** * Adds single occurrence of the {@code --patch-module} option. * @param module module to be overridden or augmented * @param files jar files and directories * @return this task object */ public JavaTask patchModule(String module, Path... files) { return patchModule(module + "=" + stream(files).map(Object::toString).collect(joining(","))); } /** * Sets the {@code --limit-modules} option. * @param limitModules parameter for the option * @return this task object */ public JavaTask limitModules(String... limitModules) { this.limitModules = asList(limitModules); return this; } /** * Sets the VM options. * @param vmOptions the options * @return this task object */ public JavaTask vmOptions(String... vmOptions) { this.vmOptions = asList(vmOptions); return this; } /** * Sets the name of the class to be executed. * @param mainClass the name of the class * @return this task object */ public JavaTask mainClass(String mainClass) { this.mainClass = mainClass; return this; } /** * Sets the name of the module which contains class to be executed. If empty, * the main class is assumed to be in the unnamed module. * @param module the name of the module * @return this task object */ public JavaTask module(String module) { this.module = module; return this; } /** * Sets the name of the module and the main class name to be executed. * @param module the name of the module * @param mainClass the name of the class * @return this task object */ public JavaTask module(String module, String mainClass) { this.module = module; this.mainClass = mainClass; return this; } /** * Sets the arguments for the class to be executed. * @param classArgs the arguments * @return this task object */ public JavaTask classArgs(String... classArgs) { this.classArgs = Arrays.asList(classArgs); return this; } /** * Sets that the standard VM and java options would not be passed * to the new VM instance. If this method is not called, the default behavior * is that the options will be passed to the new VM instance. * * @return this task object */ public JavaTask ignoreStandardOptions() { standardOptions = EMPTY_LIST; return this; } /** * Filters the standard VM and java options. * @param filter a filter * @return this task object */ public JavaTask filterStandardOption(Function, List> filter) { standardOptions = filter.apply(standardOptions); return this; } /** * Filters the standard VM and java options by taking away a particular option * and a specified number or parameters after it. * * @param option the option, such as {@code --limit-modules} * @param parameterCount number of parameters to remove after the option. * @return this task object */ public JavaTask ignoreStandardOption(String option, int parameterCount) { return filterStandardOption(os -> { List filtered = new ArrayList<>(); for(int i = 0; i < os.size(); i++) { if(os.get(i).equals(option)) i += parameterCount; else filtered.add(os.get(i)); } return filtered; }); } /** * Filters the standard VM and java options so that there are no options which * affects a set of resolvable modules or a set of accessible APIs. * * @return this task object */ public JavaTask ignoreStandardModuleOptions() { moduleOptions.entrySet().stream() .forEach(e -> ignoreStandardOption(e.getKey(), e.getValue())); return this; } /** * {@inheritDoc} * @return the name "java" */ @Override public String name() { return "java"; } /** * Calls the Java launcher with the arguments as currently configured. * @return a Result object indicating the outcome of the task * and the content of any output written to stdout or stderr. * @throws TaskError if the outcome of the task is not as expected. */ @Override public Task.Result run() { List args = new ArrayList<>(standardOptions); if (classPath != null) { args.add(CLASS_PATH); args.add(classPath.stream().collect(joining(","))); } if (modulePath != null) { args.add(MODULE_PATH); args.add(modulePath.stream().collect(joining(","))); } if (upgradeModulePath != null) { args.add(UPGRADE_MODULE_PATH); args.add(upgradeModulePath.stream().collect(joining(","))); } if (addExports != null) addExports.stream().forEach(s -> { args.add(ADD_EXPORTS); args.add(s); }); if (addReads != null) addReads.stream().forEach(s -> { args.add(ADD_READS); args.add(s); }); if (patchModule != null) patchModule.stream().forEach(s -> { args.add(PATCH_MODULE); args.add(s); }); if (addModules != null) { args.add(ADD_MODULES); args.add(addModules.stream().collect(joining(","))); } if (limitModules != null) { args.add(LIMIT_MODULES); args.add(limitModules.stream().collect(joining(","))); } if (vmOptions != null) args.addAll(vmOptions); if (mainClass != null) if (module != null) { args.add("-m"); args.add(module + "/" + mainClass); } else args.add(mainClass); if (classArgs != null) args.addAll(classArgs); return run(Tool.JAVA, args); } //this is a list of options to ignore in ignoreStandardModuleOptions() private static final Map moduleOptions = Map.of(LIMIT_MODULES, 1, UPGRADE_MODULE_PATH, 1, ADD_MODULES, 1, ADD_READS, 1, ADD_EXPORTS, 1, PATCH_MODULE, 1); }