/* * Copyright (c) 2013, 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 com.oracle.java.testlibrary; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import sun.management.VMManagement; public final class ProcessTools { private ProcessTools() { } /** * Pumps stdout and stderr from running the process into a String. * * @param processHandler ProcessHandler to run. * @return Output from process. * @throws IOException If an I/O error occurs. */ public static OutputBuffer getOutput(ProcessBuilder processBuilder) throws IOException { return getOutput(processBuilder.start()); } /** * Pumps stdout and stderr the running process into a String. * * @param process Process to pump. * @return Output from process. * @throws IOException If an I/O error occurs. */ public static OutputBuffer getOutput(Process process) throws IOException { ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream(); ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); StreamPumper outPumper = new StreamPumper(process.getInputStream(), stdoutBuffer); StreamPumper errPumper = new StreamPumper(process.getErrorStream(), stderrBuffer); Thread outPumperThread = new Thread(outPumper); Thread errPumperThread = new Thread(errPumper); outPumperThread.setDaemon(true); errPumperThread.setDaemon(true); outPumperThread.start(); errPumperThread.start(); try { process.waitFor(); outPumperThread.join(); errPumperThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; } return new OutputBuffer(stdoutBuffer.toString(), stderrBuffer.toString()); } /** * Get the process id of the current running Java process * * @return Process id */ public static int getProcessId() throws Exception { // Get the current process id using a reflection hack RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); Field jvm = runtime.getClass().getDeclaredField("jvm"); jvm.setAccessible(true); VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); pid_method.setAccessible(true); int pid = (Integer) pid_method.invoke(mgmt); return pid; } /** * Get the string containing input arguments passed to the VM * * @return arguments */ public static String getVmInputArguments() { RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); List args = runtime.getInputArguments(); StringBuilder result = new StringBuilder(); for (String arg : args) result.append(arg).append(' '); return result.toString(); } /** * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) * * @return String[] with platform specific arguments, empty if there are none */ public static String[] getPlatformSpecificVMArgs() { if (Platform.is64bit() && Platform.isSolaris()) { return new String[] { "-d64" }; } return new String[] {}; } /** * Create ProcessBuilder using the java launcher from the jdk to be tested and * with any platform specific arguments prepended */ public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception { return createJavaProcessBuilder(false, command); } public static ProcessBuilder createJavaProcessBuilder(boolean addTestVmAndJavaOptions, String... command) throws Exception { String javapath = JDKToolFinder.getJDKTool("java"); ArrayList args = new ArrayList<>(); args.add(javapath); Collections.addAll(args, getPlatformSpecificVMArgs()); if (addTestVmAndJavaOptions) { Collections.addAll(args, Utils.getTestJavaOpts()); } Collections.addAll(args, command); // Reporting StringBuilder cmdLine = new StringBuilder(); for (String cmd : args) { cmdLine.append(cmd).append(' '); } System.out.println("Command line: [" + cmdLine.toString() + "]"); return new ProcessBuilder(args.toArray(new String[args.size()])); } /** * Executes a test jvm process, waits for it to finish and returns the process output. * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. * The java from the test.jdk is used to execute the command. * * The command line will be like: * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds * * @param cmds User specifed arguments. * @return The output from the process. */ public static OutputAnalyzer executeTestJvm(String... cmds) throws Throwable { ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds)); return executeProcess(pb); } /** * Executes a process, waits for it to finish and returns the process output. * @param pb The ProcessBuilder to execute. * @return The output from the process. */ public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Throwable { OutputAnalyzer output = null; try { output = new OutputAnalyzer(pb.start()); return output; } catch (Throwable t) { System.out.println("executeProcess() failed: " + t); throw t; } finally { System.out.println(getProcessLog(pb, output)); } } /** * Executes a process, waits for it to finish and returns the process output. * @param cmds The command line to execute. * @return The output from the process. */ public static OutputAnalyzer executeProcess(String... cmds) throws Throwable { return executeProcess(new ProcessBuilder(cmds)); } /** * Used to log command line, stdout, stderr and exit code from an executed process. * @param pb The executed process. * @param output The output from the process. */ public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) { String stderr = output == null ? "null" : output.getStderr(); String stdout = output == null ? "null" : output.getStdout(); String exitValue = output == null ? "null": Integer.toString(output.getExitValue()); StringBuilder logMsg = new StringBuilder(); final String nl = System.getProperty("line.separator"); logMsg.append("--- ProcessLog ---" + nl); logMsg.append("cmd: " + getCommandLine(pb) + nl); logMsg.append("exitvalue: " + exitValue + nl); logMsg.append("stderr: " + stderr + nl); logMsg.append("stdout: " + stdout + nl); return logMsg.toString(); } /** * @return The full command line for the ProcessBuilder. */ public static String getCommandLine(ProcessBuilder pb) { if (pb == null) { return "null"; } StringBuilder cmd = new StringBuilder(); for (String s : pb.command()) { cmd.append(s).append(" "); } return cmd.toString().trim(); } }