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 processHandler ProcessHandler 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 * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) 113 * 114 * @return String[] with platform specific arguments, empty if there are none 115 */ 116 public static String[] getPlatformSpecificVMArgs() { 117 118 if (Platform.is64bit() && Platform.isSolaris()) { 119 return new String[] { "-d64" }; 120 } 121 122 return new String[] {}; 123 } 124 125 /** 126 * Create ProcessBuilder using the java launcher from the jdk to be tested and 127 * with any platform specific arguments prepended 128 */ 129 public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception { 130 return createJavaProcessBuilder(false, command); 131 } 132 133 public static ProcessBuilder createJavaProcessBuilder(boolean addTestVmAndJavaOptions, String... command) throws Exception { 134 String javapath = JDKToolFinder.getJDKTool("java"); 135 136 ArrayList<String> args = new ArrayList<>(); 137 args.add(javapath); 138 Collections.addAll(args, getPlatformSpecificVMArgs()); 139 140 args.add("-cp"); 141 args.add(System.getProperty("java.class.path")); 142 143 if (addTestVmAndJavaOptions) { 144 Collections.addAll(args, Utils.getTestJavaOpts()); 145 } 146 147 Collections.addAll(args, command); 148 149 // Reporting 150 StringBuilder cmdLine = new StringBuilder(); 151 for (String cmd : args) { 152 cmdLine.append(cmd).append(' '); 153 } 154 System.out.println("Command line: [" + cmdLine.toString() + "]"); 155 156 return new ProcessBuilder(args.toArray(new String[args.size()])); 157 } 158 159 /** 160 * Executes a test jvm process, waits for it to finish and returns the process output. 161 * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. 162 * The java from the test.jdk is used to execute the command. 163 * 164 * The command line will be like: 165 * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds 166 * 167 * @param cmds User specifed arguments. 168 * @return The output from the process. 169 */ 170 public static OutputAnalyzer executeTestJvm(String... cmds) throws Throwable { 171 ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds)); 172 return executeProcess(pb); 173 } 174 175 /** 176 * Executes a process, waits for it to finish and returns the process output. 177 * The process will have exited before this method returns. 178 * @param pb The ProcessBuilder to execute. 179 * @return The {@linkplain OutputAnalyzer} instance wrapping the process. 180 */ 181 public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Exception { 182 OutputAnalyzer output = null; 183 Process p = null; 184 boolean failed = false; 185 try { 186 p = pb.start(); 187 output = new OutputAnalyzer(p); 188 p.waitFor(); 189 190 return output; 191 } catch (Throwable t) { 192 if (p != null) { 193 p.destroyForcibly().waitFor(); 194 } 195 196 failed = true; 197 System.out.println("executeProcess() failed: " + t); 198 throw t; 199 } finally { 200 if (failed) { 201 System.err.println(getProcessLog(pb, output)); 202 } 203 } 204 } 205 206 /** 207 * Executes a process, waits for it to finish and returns the process output. 208 * @param cmds The command line to execute. 209 * @return The output from the process. 210 */ 211 public static OutputAnalyzer executeProcess(String... cmds) throws Throwable { 212 return executeProcess(new ProcessBuilder(cmds)); 213 } 214 215 /** 216 * Used to log command line, stdout, stderr and exit code from an executed process. 217 * @param pb The executed process. 218 * @param output The output from the process. 219 */ 220 public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) { 221 String stderr = output == null ? "null" : output.getStderr(); 222 String stdout = output == null ? "null" : output.getStdout(); 223 String exitValue = output == null ? "null": Integer.toString(output.getExitValue()); 224 StringBuilder logMsg = new StringBuilder(); 225 final String nl = System.getProperty("line.separator"); 226 logMsg.append("--- ProcessLog ---" + nl); 227 logMsg.append("cmd: " + getCommandLine(pb) + nl); 228 logMsg.append("exitvalue: " + exitValue + nl); 229 logMsg.append("stderr: " + stderr + nl); 230 logMsg.append("stdout: " + stdout + nl); 231 return logMsg.toString(); 232 } 233 234 /** 235 * @return The full command line for the ProcessBuilder. 236 */ 237 public static String getCommandLine(ProcessBuilder pb) { 238 if (pb == null) { 239 return "null"; 240 } 241 StringBuilder cmd = new StringBuilder(); 242 for (String s : pb.command()) { 243 cmd.append(s).append(" "); 244 } 245 return cmd.toString().trim(); 246 } 247 }