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