Path: blob/master/test/jdk/java/rmi/testlibrary/JavaVM.java
41149 views
/*1* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.BufferedReader;24import java.io.ByteArrayOutputStream;25import java.io.DataInputStream;26import java.io.File;27import java.io.IOException;28import java.io.InputStreamReader;29import java.io.OutputStream;30import java.util.Arrays;31import java.util.StringTokenizer;32import java.util.concurrent.TimeoutException;3334/**35* RMI regression test utility class that uses Runtime.exec to spawn a36* java process that will run a named java class.37*/38public class JavaVM {3940static class CachedOutputStream extends OutputStream {41ByteArrayOutputStream ba;42OutputStream os;4344public CachedOutputStream(OutputStream os) {45this.os = os;46this.ba = new ByteArrayOutputStream();47}4849public void write(int b) throws IOException {50ba.write(b);51os.write(b);52}5354public void reset() throws IOException {55os.flush();56ba.reset();57}58}5960public static final long POLLTIME_MS = 100L;6162protected Process vm = null;6364private String classname = "";65protected String args = "";66protected String options = "";67protected CachedOutputStream outputStream = new CachedOutputStream(System.out);68protected CachedOutputStream errorStream = new CachedOutputStream(System.err);69private String policyFileName = null;70private StreamPipe outPipe;71private StreamPipe errPipe;7273private static void mesg(Object mesg) {74System.err.println("JAVAVM: " + mesg.toString());75}7677/** string name of the program execd by JavaVM */78private static String javaProgram = "java";7980static {81try {82javaProgram = TestLibrary.getProperty("java.home", "") +83File.separator + "bin" + File.separator + javaProgram;84} catch (SecurityException se) {85}86}8788public JavaVM(String classname,89String options, String args) {90this.classname = classname;91this.options = options;92this.args = args;93}9495public JavaVM(String classname,96String options, String args,97OutputStream out, OutputStream err) {98this(classname, options, args);99this.outputStream = new CachedOutputStream(out);100this.errorStream = new CachedOutputStream(err);101}102103// Prepends passed opts array to current options104public void addOptions(String... opts) {105String newOpts = "";106for (int i = 0 ; i < opts.length ; i ++) {107newOpts += " " + opts[i];108}109newOpts += " ";110options = newOpts + options;111}112113// Prepends passed arguments array to current args114public void addArguments(String... arguments) {115String newArgs = "";116for (int i = 0 ; i < arguments.length ; i ++) {117newArgs += " " + arguments[i];118}119newArgs += " ";120args = newArgs + args;121}122123public void setPolicyFile(String policyFileName) {124this.policyFileName = policyFileName;125}126127/**128* This method is used for setting VM options on spawned VMs.129* It returns the extra command line options required130* to turn on jcov code coverage analysis.131*/132protected static String getCodeCoverageOptions() {133return TestLibrary.getExtraProperty("jcov.options","");134}135136/**137* Exec the VM as specified in this object's constructor.138*/139private void start0() throws IOException {140outputStream.reset();141errorStream.reset();142143if (vm != null)144throw new IllegalStateException("JavaVM already started");145146/*147* If specified, add option for policy file148*/149if (policyFileName != null) {150String option = "-Djava.security.policy=" + policyFileName;151addOptions(new String[] { option });152}153154addOptions(new String[] {155getCodeCoverageOptions(),156TestParams.testJavaOpts,157TestParams.testVmOpts158});159160StringTokenizer optionsTokenizer = new StringTokenizer(options);161StringTokenizer argsTokenizer = new StringTokenizer(args);162int optionsCount = optionsTokenizer.countTokens();163int argsCount = argsTokenizer.countTokens();164165String javaCommand[] = new String[optionsCount + argsCount + 2];166int count = 0;167168javaCommand[count++] = JavaVM.javaProgram;169while (optionsTokenizer.hasMoreTokens()) {170javaCommand[count++] = optionsTokenizer.nextToken();171}172javaCommand[count++] = classname;173while (argsTokenizer.hasMoreTokens()) {174javaCommand[count++] = argsTokenizer.nextToken();175}176177mesg("command = " + Arrays.asList(javaCommand).toString());178179vm = Runtime.getRuntime().exec(javaCommand);180}181182public void start() throws IOException {183start0();184185/* output from the exec'ed process may optionally be captured. */186outPipe = StreamPipe.plugTogether(vm.getInputStream(), this.outputStream);187errPipe = StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream);188}189190public void destroy() {191if (vm != null) {192vm.destroyForcibly();193}194vm = null;195}196197/**198* Return exit value for vm process.199* @return exit value for vm process200* @throws IllegalThreadStateException if the vm process has not yet terminated201*/202public int exitValue() {203return vm.exitValue();204}205206/**207* Destroy the vm process, and do necessary cleanup.208*/209public void cleanup() {210destroy();211}212213/**214* Destroys the VM, waits for it to terminate, and returns215* its exit status.216*217* @throws IllegalStateException if the VM has already been destroyed218* @throws InterruptedException if the caller is interrupted while waiting219*/220public int terminate() throws InterruptedException {221if (vm == null) {222throw new IllegalStateException("JavaVM already destroyed");223}224225vm.destroy();226int status = waitFor();227vm = null;228return status;229}230231232/**233* Waits for the subprocess to exit, joins the pipe threads to ensure that234* all output is collected, and returns its exit status.235*/236public int waitFor() throws InterruptedException {237if (vm == null)238throw new IllegalStateException("can't wait for JavaVM that isn't running");239240int status = vm.waitFor();241outPipe.join();242errPipe.join();243return status;244}245246/**247* Causes the current thread to wait the vm process to exit, if necessary,248* wait until the vm process has terminated, or the specified waiting time249* elapses. Release allocated input/output after vm process has terminated.250* @param timeout the maximum milliseconds to wait.251* @return exit value for vm process.252* @throws InterruptedException if the current thread is interrupted253* while waiting.254* @throws TimeoutException if subprocess does not end after timeout255* milliseconds passed256*/257public int waitFor(long timeout)258throws InterruptedException, TimeoutException {259if (vm == null)260throw new IllegalStateException("can't wait for JavaVM that isn't running");261long deadline = TestLibrary.computeDeadline(System.currentTimeMillis(), timeout);262263while (true) {264try {265int status = vm.exitValue();266outPipe.join();267errPipe.join();268return status;269} catch (IllegalThreadStateException ignore) { }270271if (System.currentTimeMillis() > deadline)272throw new TimeoutException();273274Thread.sleep(POLLTIME_MS);275}276}277278/**279* Starts the subprocess, waits for it to exit, and returns its exit status.280*/281public int execute() throws IOException, InterruptedException {282start();283return waitFor();284}285}286287288