1 /*
   2  * Copyright (c) 1998, 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 import java.io.File;
  25 import java.io.IOException;
  26 import java.io.OutputStream;
  27 import java.util.Arrays;
  28 import java.util.StringTokenizer;
  29 
  30 /**
  31  * RMI regression test utility class that uses Runtime.exec to spawn a
  32  * java process that will run a named java class.
  33  */
  34 public class JavaVM {
  35 
  36     protected Process vm = null;
  37 
  38     private String classname = "";
  39     private String args = "";
  40     private String options = "";
  41     private OutputStream outputStream = System.out;
  42     private OutputStream errorStream = System.err;
  43     private String policyFileName = null;
  44     private StreamPipe outPipe;
  45     private StreamPipe errPipe;
  46 
  47     private static void mesg(Object mesg) {
  48         System.err.println("JAVAVM: " + mesg.toString());
  49     }
  50 
  51     /** string name of the program execd by JavaVM */
  52     private static String javaProgram = "java";
  53 
  54     static {
  55         try {
  56             javaProgram = TestLibrary.getProperty("java.home", "") +
  57                 File.separator + "bin" + File.separator + javaProgram;
  58         } catch (SecurityException se) {
  59         }
  60     }
  61 
  62     public JavaVM(String classname,
  63                   String options, String args) {
  64         this.classname = classname;
  65         this.options = options;
  66         this.args = args;
  67     }
  68 
  69     public JavaVM(String classname,
  70                   String options, String args,
  71                   OutputStream out, OutputStream err) {
  72         this(classname, options, args);
  73         this.outputStream = out;
  74         this.errorStream = err;
  75     }
  76 
  77     // Prepends passed opts array to current options
  78     public void addOptions(String[] opts) {
  79         String newOpts = "";
  80         for (int i = 0 ; i < opts.length ; i ++) {
  81             newOpts += " " + opts[i];
  82         }
  83         newOpts += " ";
  84         options = newOpts + options;
  85     }
  86 
  87     // Prepends passed arguments array to current args
  88     public void addArguments(String[] arguments) {
  89         String newArgs = "";
  90         for (int i = 0 ; i < arguments.length ; i ++) {
  91             newArgs += " " + arguments[i];
  92         }
  93         newArgs += " ";
  94         args = newArgs + args;
  95     }
  96 
  97     public void setPolicyFile(String policyFileName) {
  98         this.policyFileName = policyFileName;
  99     }
 100 
 101     /**
 102      * This method is used for setting VM options on spawned VMs.
 103      * It returns the extra command line options required
 104      * to turn on jcov code coverage analysis.
 105      */
 106     protected static String getCodeCoverageOptions() {
 107         return TestLibrary.getExtraProperty("jcov.options","");
 108     }
 109 
 110     /**
 111      * Exec the VM as specified in this object's constructor.
 112      */
 113     public void start() throws IOException {
 114 
 115         if (vm != null)
 116             throw new IllegalStateException("JavaVM already started");
 117 
 118         /*
 119          * If specified, add option for policy file
 120          */
 121         if (policyFileName != null) {
 122             String option = "-Djava.security.policy=" + policyFileName;
 123             addOptions(new String[] { option });
 124         }
 125 
 126         addOptions(new String[] { getCodeCoverageOptions() });
 127 
 128         StringTokenizer optionsTokenizer = new StringTokenizer(options);
 129         StringTokenizer argsTokenizer = new StringTokenizer(args);
 130         int optionsCount = optionsTokenizer.countTokens();
 131         int argsCount = argsTokenizer.countTokens();
 132 
 133         String javaCommand[] = new String[optionsCount + argsCount + 2];
 134         int count = 0;
 135 
 136         javaCommand[count++] = JavaVM.javaProgram;
 137         while (optionsTokenizer.hasMoreTokens()) {
 138             javaCommand[count++] = optionsTokenizer.nextToken();
 139         }
 140         javaCommand[count++] = classname;
 141         while (argsTokenizer.hasMoreTokens()) {
 142             javaCommand[count++] = argsTokenizer.nextToken();
 143         }
 144 
 145         mesg("command = " + Arrays.asList(javaCommand).toString());
 146 
 147         vm = Runtime.getRuntime().exec(javaCommand);
 148 
 149         /* output from the execed process may optionally be captured. */
 150         outPipe = StreamPipe.plugTogether(vm.getInputStream(), this.outputStream);
 151         errPipe = StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream);
 152     }
 153 
 154     public void destroy() {
 155         if (vm != null) {
 156             vm.destroy();
 157         }
 158         vm = null;
 159     }
 160 
 161     /**
 162      * Waits for the subprocess to exit, joins the pipe threads to ensure that
 163      * all output is collected, and returns its exit status.
 164      */
 165     public int waitFor() throws InterruptedException {
 166         if (vm == null)
 167             throw new IllegalStateException("can't wait for JavaVM that isn't running");
 168 
 169         int status = vm.waitFor();
 170         outPipe.join();
 171         errPipe.join();
 172         return status;
 173     }
 174 
 175     /**
 176      * Starts the subprocess, waits for it to exit, and returns its exit status.
 177      */
 178     public int execute() throws IOException, InterruptedException {
 179         start();
 180         return waitFor();
 181     }
 182 }