1 /* 2 * Copyright (c) 1998, 2012, 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 /** 25 * 26 */ 27 28 import java.io.*; 29 import java.util.Arrays; 30 import java.util.Properties; 31 import java.util.StringTokenizer; 32 33 /** 34 * RMI regression test utility class that uses Runtime.exec to spawn a 35 * java process that will run a named java class. 36 */ 37 public class JavaVM { 38 39 protected Process vm = null; 40 41 private String classname = ""; 42 private String args = ""; 43 private String options = ""; 44 private OutputStream outputStream = System.out; 45 private OutputStream errorStream = System.err; 46 private String policyFileName = null; 47 48 // This is used to shorten waiting time at startup. 49 private volatile boolean started = false; 50 private boolean forcesOutput = true; // default behavior 51 52 private static void mesg(Object mesg) { 53 System.err.println("JAVAVM: " + mesg.toString()); 54 } 55 56 /** string name of the program execd by JavaVM */ 57 private static String javaProgram = "java"; 58 59 static { 60 try { 61 javaProgram = TestLibrary.getProperty("java.home", "") + 62 File.separator + "bin" + File.separator + javaProgram; 63 } catch (SecurityException se) { 64 } 65 } 66 67 public JavaVM(String classname) { 68 this.classname = classname; 69 } 70 public JavaVM(String classname, 71 String options, String args) { 72 this.classname = classname; 73 this.options = options; 74 this.args = args; 75 } 76 77 public JavaVM(String classname, 78 String options, String args, 79 OutputStream out, OutputStream err) { 80 this(classname, options, args); 81 this.outputStream = out; 82 this.errorStream = err; 83 } 84 85 /* This constructor will instantiate a JavaVM object for which caller 86 * can ask for forcing initial version output on child vm process 87 * (if forcesVersionOutput is true), or letting the started vm behave freely 88 * (when forcesVersionOutput is false). 89 */ 90 public JavaVM(String classname, 91 String options, String args, 92 OutputStream out, OutputStream err, 93 boolean forcesVersionOutput) { 94 this(classname, options, args, out, err); 95 this.forcesOutput = forcesVersionOutput; 96 } 97 98 99 public void setStarted() { 100 started = true; 101 } 102 103 // Prepends passed opts array to current options 104 public void addOptions(String[] opts) { 105 String newOpts = ""; 106 for (int i = 0 ; i < opts.length ; i ++) { 107 newOpts += " " + opts[i]; 108 } 109 newOpts += " "; 110 options = newOpts + options; 111 } 112 113 // Prepends passed arguments array to current args 114 public void addArguments(String[] arguments) { 115 String newArgs = ""; 116 for (int i = 0 ; i < arguments.length ; i ++) { 117 newArgs += " " + arguments[i]; 118 } 119 newArgs += " "; 120 args = newArgs + args; 121 } 122 123 public void setPolicyFile(String policyFileName) { 124 this.policyFileName = policyFileName; 125 } 126 127 /** 128 * This method is used for setting VM options on spawned VMs. 129 * It returns the extra command line options required 130 * to turn on jcov code coverage analysis. 131 */ 132 protected static String getCodeCoverageOptions() { 133 return TestLibrary.getExtraProperty("jcov.options",""); 134 } 135 136 137 /** 138 * Exec the VM as specified in this object's constructor. 139 */ 140 public void start() throws IOException { 141 142 if (vm != null) return; 143 144 /* 145 * If specified, add option for policy file 146 */ 147 if (policyFileName != null) { 148 String option = "-Djava.security.policy=" + policyFileName; 149 addOptions(new String[] { option }); 150 } 151 152 addOptions(new String[] { getCodeCoverageOptions() }); 153 154 /* 155 * If forcesOutput is true : 156 * We force the new starting vm to output something so that we can know 157 * when it is effectively started by redirecting standard output through 158 * the next StreamPipe call (the vm is considered started when a first 159 * output has been streamed out). 160 * We do this by prepnding a "-showversion" option in the command line. 161 */ 162 if (forcesOutput) { 163 addOptions(new String[] {"-showversion"}); 164 } 165 166 StringTokenizer optionsTokenizer = new StringTokenizer(options); 167 StringTokenizer argsTokenizer = new StringTokenizer(args); 168 int optionsCount = optionsTokenizer.countTokens(); 169 int argsCount = argsTokenizer.countTokens(); 170 171 String javaCommand[] = new String[optionsCount + argsCount + 2]; 172 int count = 0; 173 174 javaCommand[count++] = JavaVM.javaProgram; 175 while (optionsTokenizer.hasMoreTokens()) { 176 javaCommand[count++] = optionsTokenizer.nextToken(); 177 } 178 javaCommand[count++] = classname; 179 while (argsTokenizer.hasMoreTokens()) { 180 javaCommand[count++] = argsTokenizer.nextToken(); 181 } 182 183 mesg("command = " + Arrays.asList(javaCommand).toString()); 184 System.err.println(""); 185 186 vm = Runtime.getRuntime().exec(javaCommand); 187 188 /* output from the execed process may optionally be captured. */ 189 StreamPipe.plugTogether(this, vm.getInputStream(), this.outputStream); 190 StreamPipe.plugTogether(this, vm.getErrorStream(), this.errorStream); 191 192 try { 193 if (forcesOutput) { 194 // Wait distant vm to start, by using waiting time slices of 100 ms. 195 // Wait at most for 2secs, after it considers the vm to be started. 196 final long vmStartSleepTime = 100; 197 final int maxTrials = 20; 198 int numTrials = 0; 199 while (!started && numTrials < maxTrials) { 200 numTrials++; 201 Thread.sleep(vmStartSleepTime); 202 } 203 204 // Outputs running status of distant vm 205 String message = 206 "after " + (numTrials * vmStartSleepTime) + " milliseconds"; 207 if (started) { 208 mesg("distant vm process running, " + message); 209 } 210 else { 211 mesg("unknown running status of distant vm process, " + message); 212 } 213 } 214 else { 215 // Since we have no way to know if the distant vm is started, 216 // we just consider the vm to be started after a 2secs waiting time. 217 Thread.sleep(2000); 218 mesg("distant vm considered to be started after a waiting time of 2 secs"); 219 } 220 } catch (InterruptedException e) { 221 Thread.currentThread().interrupt(); 222 mesg("Thread interrupted while checking if distant vm is started. Giving up check."); 223 mesg("Distant vm state unknown"); 224 return; 225 } 226 } 227 228 public void destroy() { 229 if (vm != null) { 230 vm.destroy(); 231 } 232 vm = null; 233 } 234 235 protected Process getVM() { 236 return vm; 237 } 238 }