001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.util.newjvm;
038:
039: import edu.rice.cs.drjava.config.FileOption;
040: import edu.rice.cs.util.swing.Utilities;
041: import edu.rice.cs.plt.io.IOUtil;
042:
043: import java.io.BufferedReader;
044: import java.io.File;
045: import java.io.IOException;
046: import java.io.InputStreamReader;
047: import java.util.Iterator;
048: import java.util.LinkedList;
049: import java.util.Locale;
050:
051: /** A utility class to allow executing another JVM.
052: * @version $Id: ExecJVM.java 4255 2007-08-28 19:17:37Z mgricken $
053: */
054: public final class ExecJVM {
055: private static final String PATH_SEPARATOR = System
056: .getProperty("path.separator");
057: private static final String OS_NAME = System.getProperty("os.name")
058: .toLowerCase(Locale.US);
059:
060: private ExecJVM() {
061: }
062:
063: /** Runs a new JVM.
064: * @param mainClass Class to run
065: * @param classParams Parameters to pass to the main class
066: * @param classPath Array of items to put in classpath of new JVM
067: * @param jvmParams Array of additional command-line parameters to pass to JVM
068: * @return {@link Process} object corresponding to the executed JVM
069: */
070: public static Process runJVM(String mainClass,
071: String[] classParams, String[] classPath,
072: String[] jvmParams, File workDir) throws IOException {
073:
074: final StringBuilder buf = new StringBuilder();
075: for (int i = 0; i < classPath.length; i++) {
076: if (i != 0)
077: buf.append(PATH_SEPARATOR);
078:
079: buf.append(classPath[i]);
080: }
081:
082: return runJVM(mainClass, classParams, buf.toString(),
083: jvmParams, workDir);
084: }
085:
086: /** Runs a new JVM.
087: * @param mainClass Class to run
088: * @param classParams Parameters to pass to the main class
089: * @param classPath Pre-formatted classpath parameter
090: * @param jvmParams Array of additional command-line parameters to pass to JVM
091: *
092: * @return {@link Process} object corresponding to the executed JVM
093: */
094: public static Process runJVM(String mainClass,
095: String[] classParams, String classPath, String[] jvmParams,
096: File workDir) throws IOException {
097:
098: LinkedList<String> args = new LinkedList<String>();
099: args.add("-classpath");
100: args.add(classPath);
101: _addArray(args, jvmParams);
102: String[] jvmWithCP = args.toArray(new String[args.size()]);
103:
104: return _runJVM(mainClass, classParams, jvmWithCP, workDir);
105: }
106:
107: /** Runs a new JVM, propagating the present classpath. It changes the entries in the class path to absolute form.
108: * @param mainClass Class to run
109: * @param classParams Parameters to pass to the main class
110: * @param jvmParams Array of additional command-line parameters to pass to JVM
111: * @return {@link Process} object corresponding to the executed JVM
112: */
113: public static Process runJVMPropagateClassPath(String mainClass,
114: String[] classParams, String[] jvmParams, File workDir)
115: throws IOException {
116: Iterable<File> cp = IOUtil.parsePath(System
117: .getProperty("java.class.path"));
118: cp = IOUtil.getAbsoluteFiles(cp);
119: return runJVM(mainClass, classParams, IOUtil.pathToString(cp),
120: jvmParams, workDir);
121: }
122:
123: /** Runs a new JVM, propagating the present classpath.
124: * @param mainClass Class to run
125: * @param classParams Parameters to pass to the main class
126: * @return {@link Process} object corresponding to the new JVM process
127: */
128: public static Process runJVMPropagateClassPath(String mainClass,
129: String[] classParams, File workDir) throws IOException {
130: return runJVMPropagateClassPath(mainClass, classParams,
131: new String[0], workDir);
132: }
133:
134: /** Creates and runs a new JVM. This method is private now because it cannot change the classpath entries to
135: * absolute paths, so it should not be used.
136: *
137: * @param mainClass Class to run
138: * @param classParams Parameters to pass to the main class
139: * @param jvmParams Array of additional command-line parameters to pass to JVM
140: *
141: * @return {@link Process} object corresponding to the executed JVM
142: */
143: private static Process _runJVM(String mainClass,
144: String[] classParams, String[] jvmParams, File workDir)
145: throws IOException {
146: LinkedList<String> args = new LinkedList<String>();
147: args.add(_getExecutable());
148: _addArray(args, jvmParams);
149: args.add(mainClass);
150: _addArray(args, classParams);
151:
152: String[] argArray = args.toArray(new String[args.size()]);
153:
154: // exec our "java" command in the specified working directory setting
155: Process p;
156: if ((workDir != null) && (workDir != FileOption.NULL_FILE)) {
157: // execute in the working directory
158: if (workDir.exists())
159: p = Runtime.getRuntime().exec(argArray, null, workDir);
160: else {
161: Utilities
162: .showMessageBox(
163: "Working directory does not exist:\n"
164: + workDir
165: + "\nThe setting will be ignored. Press OK to continue.",
166: "Configuration Error");
167: p = Runtime.getRuntime().exec(argArray);
168: }
169: } else {
170: // execute without caring about working directory
171: p = Runtime.getRuntime().exec(argArray);
172: }
173: return p;
174: }
175:
176: /** Empties BufferedReaders by copying lines into LinkedLists.
177: * This is intended for use with the output streams from an ExecJVM process.
178: * Source and destination objects are specified for stdout and for stderr.
179: * @param theProc a Process object whose output will be handled
180: * @param outLines the LinkedList of Strings to be filled with the lines read from outBuf
181: * @param errLines the LinkedList of Strings to be filled with the lines read from errBuf
182: */
183: public static void ventBuffers(Process theProc,
184: LinkedList<String> outLines, LinkedList<String> errLines)
185: throws IOException {
186: // getInputStream actually gives us the stdout from the Process.
187: BufferedReader outBuf = new BufferedReader(
188: new InputStreamReader(theProc.getInputStream()));
189: BufferedReader errBuf = new BufferedReader(
190: new InputStreamReader(theProc.getErrorStream()));
191: String output;
192:
193: if (outBuf.ready()) {
194: output = outBuf.readLine();
195:
196: while (output != null) {
197: // System.out.println("[stdout]: " + output);
198: outLines.add(output);
199: if (outBuf.ready())
200: output = outBuf.readLine();
201: else
202: output = null;
203: }
204: }
205: outBuf.close();
206:
207: if (errBuf.ready()) {
208: output = errBuf.readLine();
209: while (output != null) {
210: // System.out.println("[stderr] " + output);
211: errLines.add(output);
212: if (errBuf.ready()) {
213: output = errBuf.readLine();
214: } else {
215: output = null;
216: }
217: }
218: }
219: errBuf.close();
220: }
221:
222: /** Prints the stdout and stderr of the given process, line by line. Adds a message and tag to identify the source
223: * of the output. Note that this code will print all available stdout before all stderr, since it is impossible
224: * to determine in which order lines were added to the respective buffers.
225: * @param theProc a Process object whose output will be handled
226: * @param msg an initial message to print before output
227: * @param sourceName a short string to identify the process
228: * @throws IOException if there is a problem with the streams
229: */
230: public static void printOutput(Process theProc, String msg,
231: String sourceName) throws IOException {
232: // First, write out our opening message.
233: System.out.println(msg);
234:
235: LinkedList<String> outLines = new LinkedList<String>();
236: LinkedList<String> errLines = new LinkedList<String>();
237:
238: ventBuffers(theProc, outLines, errLines);
239:
240: Iterator<String> it = outLines.iterator();
241: String output;
242: while (it.hasNext()) {
243: output = it.next();
244: System.out.println(" [" + sourceName + " stdout]: "
245: + output);
246: }
247:
248: it = errLines.iterator();
249: while (it.hasNext()) {
250: output = it.next();
251: System.out.println(" [" + sourceName + " stderr]: "
252: + output);
253: }
254: }
255:
256: private static void _addArray(LinkedList<String> list,
257: String[] array) {
258: if (array != null) {
259: for (int i = 0; i < array.length; i++) {
260: list.add(array[i]);
261: }
262: }
263: }
264:
265: /** DOS/Windows family OS's use ; to separate paths. */
266: private static boolean _isDOS() {
267: return PATH_SEPARATOR.equals(";");
268: }
269:
270: private static boolean _isNetware() {
271: return OS_NAME.indexOf("netware") != -1;
272: }
273:
274: /**
275: * Find the java executable.
276: * This logic comes from Ant.
277: */
278: private static String _getExecutable() {
279: // this netware thing is based on comments from ant's code
280: if (_isNetware())
281: return "java";
282:
283: File executable;
284:
285: String java_home = System.getProperty("java.home") + "/";
286:
287: String[] candidates = { java_home + "../bin/java",
288: java_home + "bin/java", java_home + "java", };
289:
290: // search all the candidates to find java
291: for (int i = 0; i < candidates.length; i++) {
292: String current = candidates[i];
293:
294: // try javaw.exe first for dos, otherwise try java.exe for dos
295: if (_isDOS()) {
296: executable = new File(current + "w.exe");
297: if (!executable.exists())
298: executable = new File(current + ".exe");
299: } else
300: executable = new File(current);
301:
302: //System.err.println("checking: " + executable);
303:
304: if (executable.exists()) {
305: //System.err.println("JVM executable found: " + executable.getAbsolutePath());
306: return executable.getAbsolutePath();
307: }
308: }
309:
310: // hope for the best using the system's path!
311: //System.err.println("Could not find java executable, using 'java'!");
312: return "java";
313: }
314: }
|