1 /* 2 * Copyright (c) 2013, 2016, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.testlibrary.tasks; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import static java.util.Arrays.asList; 29 import static java.util.Collections.EMPTY_LIST; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.function.Function; 33 import java.util.stream.Collectors; 34 import static java.util.stream.Collectors.toList; 35 import java.util.stream.Stream; 36 37 /** 38 * A task to configure and run the Java launcher. 39 */ 40 public class JavaTask extends AbstractTask<JavaTask> { 41 private String classpath; 42 private String modulepath; 43 private String className; 44 private String moduleName; 45 private List<String> vmOptions; 46 private List<String> classArgs; 47 private List<String> addExports; 48 private List<String> addModules; 49 private List<String> standardOptions; 50 51 /** 52 * Create a task to run the Java launcher, using {@code EXEC} mode. 53 */ 54 public JavaTask() { 55 super(Task.Mode.EXEC); 56 standardOptions = Stream.of("test.vm.opts", "test.java.opts") 57 .map(p -> System.getProperty(p)) 58 .filter(p -> p != null && !p.isEmpty()) 59 .map(o -> asList(o.split(" +"))) 60 .flatMap(l -> l.stream()).collect(toList()); 61 } 62 63 /** 64 * Sets the classpath. 65 * @param classpath the classpath 66 * @return this task object 67 */ 68 public JavaTask classpath(String classpath) { 69 this.classpath = classpath; 70 return this; 71 } 72 73 /** 74 * Sets the modulepath. 75 * @param modulepath the modulepath 76 * @return this task object 77 */ 78 public JavaTask modulepath(String modulepath) { 79 this.modulepath = modulepath; 80 return this; 81 } 82 83 /** 84 * Sets the {@code --add-exports} option. 85 * @param addExports value for the option 86 * @return this task object 87 */ 88 public JavaTask addExports(String... addExports) { 89 this.addExports = Arrays.asList(addExports); 90 return this; 91 } 92 93 /** 94 * Sets the {@code --add-modules} option. 95 * @param addModules value for the option 96 * @return this task object 97 */ 98 public JavaTask addModules(String... addModules) { 99 this.addModules = Arrays.asList(addModules); 100 return this; 101 } 102 103 /** 104 * Sets the VM options. 105 * @param vmOptions the options 106 * @return this task object 107 */ 108 public JavaTask vmOptions(String... vmOptions) { 109 this.vmOptions = Arrays.asList(vmOptions); 110 return this; 111 } 112 113 /** 114 * Sets the name of the class to be executed. 115 * @param className the name of the class 116 * @return this task object 117 */ 118 public JavaTask className(String className) { 119 this.className = className; 120 return this; 121 } 122 123 /** 124 * Sets the name of the module which contains class to be executed. If empty, 125 * the main class is assumed to be in the unnamed module. 126 * @param moduleName the name of the module 127 * @return this task object 128 */ 129 public JavaTask moduleName(String moduleName) { 130 this.moduleName = moduleName; 131 return this; 132 } 133 134 /** 135 * Sets the arguments for the class to be executed. 136 * @param classArgs the arguments 137 * @return this task object 138 */ 139 public JavaTask classArgs(String... classArgs) { 140 this.classArgs = Arrays.asList(classArgs); 141 return this; 142 } 143 144 /** 145 * Sets that the standard VM and java options would not be passed 146 * to the new VM instance. If this method is not called, the default behavior 147 * is that the options will be passed to the new VM instance. 148 * 149 * @return this task object 150 */ 151 public JavaTask ignoreStandardOptions() { 152 standardOptions = EMPTY_LIST; 153 return this; 154 } 155 156 /** 157 * Filters the standard VM and java options. 158 * @param filter a filter 159 * @return 160 */ 161 public JavaTask filterStandardOption(Function<List<String>, List<String>> filter) { 162 standardOptions = filter.apply(standardOptions); 163 return this; 164 } 165 166 /** 167 * Filters the standard VM and java options by taking away a particular option 168 * and a specified number or parameters after it. 169 * 170 * @param option the option, such as {@code --limit-modules} 171 * @param valueCount number of parameters to remove after the option. 172 * @return this task object 173 */ 174 public JavaTask ignoreStandardOption(String option, int valueCount) { 175 return filterStandardOption(os -> { 176 List<String> filtered = new ArrayList<>(); 177 for(int i = 0; i < os.size(); i++) { 178 if(os.get(i).equals(option)) 179 i += valueCount; 180 else 181 filtered.add(os.get(i)); 182 } 183 return filtered; 184 }); 185 } 186 187 /** 188 * Filters the standard VM and java options so that there are no options which 189 * affects a set of resolvable modules or a set of accessible APIs. 190 * 191 * @return this task object 192 */ 193 public JavaTask ignoreStandardModuleOptions() { 194 moduleOptions.entrySet().stream() 195 .forEach(e -> ignoreStandardOption(e.getKey(), e.getValue())); 196 return this; 197 } 198 199 /** 200 * {@inheritDoc} 201 * @return the name "java" 202 */ 203 @Override 204 public String name() { 205 return "java"; 206 } 207 208 /** 209 * Calls the Java launcher with the arguments as currently configured. 210 * @return a Result object indicating the outcome of the task 211 * and the content of any output written to stdout or stderr. 212 * @throws TaskError if the outcome of the task is not as expected. 213 */ 214 @Override 215 public Task.Result run() { 216 List<String> args = new ArrayList<>(standardOptions); 217 if (classpath != null) { 218 args.add("--class-path"); 219 args.add(classpath); 220 } 221 if (modulepath != null) { 222 args.add("--module-path"); 223 args.add(modulepath); 224 } 225 if (addExports != null) { 226 args.add("--add-exports"); 227 args.add(addExports.stream().collect(Collectors.joining(","))); 228 } 229 if (addModules != null) { 230 args.add("--add-modules"); 231 args.add(addModules.stream().collect(Collectors.joining(","))); 232 } 233 if (vmOptions != null) 234 args.addAll(vmOptions); 235 if (className != null) 236 if (moduleName != null) { 237 args.add("-m"); 238 args.add(moduleName + "/" + className); 239 } else 240 args.add(className); 241 if (classArgs != null) 242 args.addAll(classArgs); 243 return run(Tool.JAVA, args); 244 } 245 246 //this is a list of options to ignore in ignoreStandardModuleOptions() 247 private static final Map<String, Integer> moduleOptions = 248 Map.of("--limit-modules", 1, 249 "--upgrade-module-path", 1, 250 "--add-modules", 1, 251 "--add-reads", 1, 252 "--add-exports", 1, 253 "--patch-module", 1); 254 }