1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
/*
* Copyright (c) 2007, 2014, 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 test.java.awt.regtesthelpers.process;
import java.io.*;
/**
* This class is created to solve interprocess communication problems.
* When you need to write a regression test which should verify inter jvm
* behavior such as DnD data transfer, Clipboard data transfer, focus
* transfer etc., you could use the next scenario:
*
* 1. Write an implementation for the parent JVM, using applet test.
* 2. Write an implementation for the child JVM or native application, using
* main() function.
* 3. Execute child process using ProcessCommunicator.executeChildProcess()
* method.
* 4. You can decide whether the test is passed on the basis of
* ProcessResults class data.
*
* Note: The class is not thread safe. You should access its methods only from
* the same thread.
*/
public class ProcessCommunicator {
private static final String javaHome = System.getProperty("java.home", "");
private static final String javaPath = javaHome + File.separator + "bin" +
File.separator + "java ";
private static String command = "";
private static volatile Process process;
private ProcessCommunicator() {}
/**
* The same as {#link #executeChildProcess(Class,String)} except
* the {@code classPathArgument} parameter. The class path
* parameter is for the debug purposes
*
* @param classToExecute is passed to the child JVM
* @param classPathArguments class path for the child JVM
* @param args arguments that will be passed to the executed class
* @return results of the executed {@code Process}
*/
public static ProcessResults executeChildProcess(final Class classToExecute,
final String classPathArguments, final String [] args)
{
try {
String command = buildCommand(classToExecute, classPathArguments, args);
process = Runtime.getRuntime().exec(command);
return doWaitFor(process);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Executes child {code Process}
*
* @param classToExecute class to be executed as a child java process
* @param args args to be passed in to the child process
* @return results of the executed {@code Process}
*/
public static ProcessResults executeChildProcess(final Class classToExecute,
final String [] args)
{
return executeChildProcess(classToExecute, System.getProperty("java.class.path"), args);
}
/**
* Waits for a process and return its results.
* This is a workaround for {@code Process.waitFor()} never returning.
*
* @return results of the executed {@code Process}
*/
public static ProcessResults doWaitFor(final Process p) {
ProcessResults pres = new ProcessResults();
final InputStream in;
final InputStream err;
try {
in = p.getInputStream();
err = p.getErrorStream();
boolean finished = false;
while (!finished) {
try {
while (in.available() > 0) {
pres.appendToStdOut((char)in.read());
}
while (err.available() > 0) {
pres.appendToStdErr((char)err.read());
}
// Ask the process for its exitValue. If the process
// is not finished, an IllegalThreadStateException
// is thrown. If it is finished, we fall through and
// the variable finished is set to true.
pres.setExitValue(p.exitValue());
finished = true;
}
catch (IllegalThreadStateException e) {
// Process is not finished yet;
// Sleep a little to save on CPU cycles
Thread.currentThread().sleep(500);
}
}
if (in != null) in.close();
if (err != null) err.close();
}
catch (Throwable e) {
System.err.println("doWaitFor(): unexpected exception");
e.printStackTrace();
}
return pres;
}
/**
* Builds command on the basis of the passed class name,
* class path and arguments.
*
* @param classToExecute with class will be executed in the new JVM
* @param classPathArguments java class path (only for test purposes)
* @param args arguments for the new application. This could be used
* to pass some information from the parent to child JVM.
* @return command to execute the {@code Process}
*/
private static String buildCommand(final Class classToExecute,
final String classPathArguments, final String [] args)
{
StringBuilder commandBuilder = new StringBuilder();
commandBuilder.append(javaPath).append(" ");
commandBuilder.append("-cp ").append(System.getProperty("test.classes", ".")).append(File.pathSeparatorChar);
if (classPathArguments.trim().length() > 0) {
commandBuilder.append(classPathArguments).append(" ");
}
commandBuilder.append(" ");
commandBuilder.append(classToExecute.getName());
for (String argument:args) {
commandBuilder.append(" ").append(argument);
}
command = commandBuilder.toString();
return command;
}
/**
* Could be used for the debug purposes.
*
* @return command that was build to execute the child process
*/
public static String getExecutionCommand () {
return command;
}
/**
* Terminates the process created by {@code executeChildProcess} methods.
*/
public static void destroyProcess() {
if (process != null) {
if (process.isAlive()) {
process.destroy();
}
process = null;
}
}
}
|