1 /* 2 * Copyright (c) 2013, 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. 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.test.lib; 25 26 import java.io.ByteArrayOutputStream; 27 import java.io.IOException; 28 import java.lang.management.ManagementFactory; 29 import java.lang.management.RuntimeMXBean; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 34 public final class ProcessTools { 35 36 private ProcessTools() { 37 } 38 39 /** 40 * Pumps stdout and stderr from running the process into a String. 41 * 42 * @param processBuilder ProcessBuilder to run. 43 * @return Output from process. 44 * @throws IOException If an I/O error occurs. 45 */ 46 public static OutputBuffer getOutput(ProcessBuilder processBuilder) throws IOException { 47 return getOutput(processBuilder.start()); 48 } 49 50 /** 51 * Pumps stdout and stderr the running process into a String. 52 * 53 * @param process Process to pump. 54 * @return Output from process. 55 * @throws IOException If an I/O error occurs. 56 */ 57 public static OutputBuffer getOutput(Process process) throws IOException { 58 ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream(); 59 ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); 60 StreamPumper outPumper = new StreamPumper(process.getInputStream(), stdoutBuffer); 61 StreamPumper errPumper = new StreamPumper(process.getErrorStream(), stderrBuffer); 62 Thread outPumperThread = new Thread(outPumper); 63 Thread errPumperThread = new Thread(errPumper); 64 65 outPumperThread.setDaemon(true); 66 errPumperThread.setDaemon(true); 67 68 outPumperThread.start(); 69 errPumperThread.start(); 70 71 try { 72 process.waitFor(); 73 outPumperThread.join(); 74 errPumperThread.join(); 75 } catch (InterruptedException e) { 76 Thread.currentThread().interrupt(); 77 return null; 78 } 79 80 return new OutputBuffer(stdoutBuffer.toString(), stderrBuffer.toString()); 81 } 82 83 /** 84 * Get the process id of the current running Java process 85 * 86 * @return Process id 87 */ 88 public static int getProcessId() throws Exception { 89 RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); 90 int pid = Integer.parseInt(runtime.getName().split("@")[0]); 91 92 return pid; 93 } 94 95 /** 96 * Get the string containing input arguments passed to the VM 97 * 98 * @return arguments 99 */ 100 public static String getVmInputArguments() { 101 RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); 102 103 List<String> args = runtime.getInputArguments(); 104 StringBuilder result = new StringBuilder(); 105 for (String arg : args) 106 result.append(arg).append(' '); 107 108 return result.toString(); 109 } 110 111 /** 112 * Gets the array of strings containing input arguments passed to the VM 113 * 114 * @return arguments 115 */ 116 public static String[] getVmInputArgs() { 117 RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); 118 List<String> args = runtime.getInputArguments(); 119 return args.toArray(new String[args.size()]); 120 } 121 122 /** 123 * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) 124 * 125 * @return String[] with platform specific arguments, empty if there are none 126 */ 127 public static String[] getPlatformSpecificVMArgs() { 128 129 if (Platform.is64bit() && Platform.isSolaris()) { 130 return new String[] { "-d64" }; 131 } 132 133 return new String[] {}; 134 } 135 136 /** 137 * Create ProcessBuilder using the java launcher from the jdk to be tested and 138 * with any platform specific arguments prepended 139 */ 140 public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception { 141 return createJavaProcessBuilder(false, command); 142 } 143 144 public static ProcessBuilder createJavaProcessBuilder(boolean addTestVmAndJavaOptions, String... command) throws Exception { 145 String javapath = JDKToolFinder.getJDKTool("java"); 146 147 ArrayList<String> args = new ArrayList<>(); 148 args.add(javapath); 149 Collections.addAll(args, getPlatformSpecificVMArgs()); 150 151 args.add("-cp"); 152 args.add(System.getProperty("java.class.path")); 153 154 if (addTestVmAndJavaOptions) { 155 Collections.addAll(args, Utils.getTestJavaOpts()); 156 } 157 158 Collections.addAll(args, command); 159 160 // Reporting 161 StringBuilder cmdLine = new StringBuilder(); 162 for (String cmd : args) { 163 cmdLine.append(cmd).append(' '); 164 } 165 System.out.println("Command line: [" + cmdLine.toString() + "]"); 166 167 return new ProcessBuilder(args.toArray(new String[args.size()])); 168 } 169 170 /** 171 * Executes a test jvm process, waits for it to finish and returns the process output. 172 * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. 173 * The java from the test.jdk is used to execute the command. 174 * 175 * The command line will be like: 176 * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds 177 * 178 * @param cmds User specifed arguments. 179 * @return The output from the process. 180 */ 181 public static OutputAnalyzer executeTestJvm(String... cmds) throws Throwable { 182 ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds)); 183 return executeProcess(pb); 184 } 185 186 /** 187 * Executes a test jvm process, waits for it to finish and returns the process output. 188 * The default jvm options from the test, jtreg, test.vm.opts and test.java.opts, are added. 189 * The java from the test.jdk is used to execute the command. 190 * 191 * The command line will be like: 192 * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds 193 * 194 * @param cmds User specifed arguments. 195 * @return The output from the process. 196 */ 197 public static OutputAnalyzer executeTestJvmAllArgs(String... cmds) throws Throwable { 198 List<String> argsList = new ArrayList<>(); 199 String[] testArgs = getVmInputArgs(); 200 Collections.addAll(argsList, testArgs); 201 Collections.addAll(argsList, Utils.addTestJavaOpts(cmds)); 202 ProcessBuilder pb = createJavaProcessBuilder(argsList.toArray(new String[argsList.size()])); 203 return executeProcess(pb); 204 } 205 206 /** 207 * Executes a process, waits for it to finish and returns the process output. 208 * The process will have exited before this method returns. 209 * @param pb The ProcessBuilder to execute. 210 * @return The {@linkplain OutputAnalyzer} instance wrapping the process. 211 */ 212 public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Exception { 213 OutputAnalyzer output = null; 214 Process p = null; 215 boolean failed = false; 216 try { 217 p = pb.start(); 218 output = new OutputAnalyzer(p); 219 p.waitFor(); 220 221 return output; 222 } catch (Throwable t) { 223 if (p != null) { 224 p.destroyForcibly().waitFor(); 225 } 226 227 failed = true; 228 System.out.println("executeProcess() failed: " + t); 229 throw t; 230 } finally { 231 if (failed) { 232 System.err.println(getProcessLog(pb, output)); 233 } 234 } 235 } 236 237 /** 238 * Executes a process, waits for it to finish and returns the process output. 239 * @param cmds The command line to execute. 240 * @return The output from the process. 241 */ 242 public static OutputAnalyzer executeProcess(String... cmds) throws Throwable { 243 return executeProcess(new ProcessBuilder(cmds)); 244 } 245 246 /** 247 * Used to log command line, stdout, stderr and exit code from an executed process. 248 * @param pb The executed process. 249 * @param output The output from the process. 250 */ 251 public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) { 252 String stderr = output == null ? "null" : output.getStderr(); 253 String stdout = output == null ? "null" : output.getStdout(); 254 String exitValue = output == null ? "null": Integer.toString(output.getExitValue()); 255 StringBuilder logMsg = new StringBuilder(); 256 final String nl = System.getProperty("line.separator"); 257 logMsg.append("--- ProcessLog ---" + nl); 258 logMsg.append("cmd: " + getCommandLine(pb) + nl); 259 logMsg.append("exitvalue: " + exitValue + nl); 260 logMsg.append("stderr: " + stderr + nl); 261 logMsg.append("stdout: " + stdout + nl); 262 return logMsg.toString(); 263 } 264 265 /** 266 * @return The full command line for the ProcessBuilder. 267 */ 268 public static String getCommandLine(ProcessBuilder pb) { 269 if (pb == null) { 270 return "null"; 271 } 272 StringBuilder cmd = new StringBuilder(); 273 for (String s : pb.command()) { 274 cmd.append(s).append(" "); 275 } 276 return cmd.toString().trim(); 277 } 278 }