ProcessBuilder.java revision 0
2362N/A * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Sun designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Sun in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 2362N/A * CA 95054 USA or visit www.sun.com if you need additional information or 0N/A * This class is used to create operating system processes. 0N/A * <p>Each <code>ProcessBuilder</code> instance manages a collection 0N/A * of process attributes. The {@link #start()} method creates a new 0N/A * {@link Process} instance with those attributes. The {@link 0N/A * #start()} method can be invoked repeatedly from the same instance 0N/A * to create new subprocesses with identical or related attributes. 0N/A * <p>Each process builder manages these process attributes: 0N/A * <li>a <i>command</i>, a list of strings which signifies the 0N/A * external program file to be invoked and its arguments, if any. 0N/A * Which string lists represent a valid operating system command is 0N/A * system-dependent. For example, it is common for each conceptual 0N/A * argument to be an element in this list, but there are operating * systems where programs are expected to tokenize command line * strings themselves - on such a system a Java implementation might * require commands to contain exactly two elements. * <li>an <i>environment</i>, which is a system-dependent mapping from * <i>variables</i> to <i>values</i>. The initial value is a copy of * the environment of the current process (see {@link System#getenv()}). * <li>a <i>working directory</i>. The default value is the current * working directory of the current process, usually the directory * named by the system property <code>user.dir</code>. * <li>a <i>redirectErrorStream</i> property. Initially, this property * is <code>false</code>, meaning that the standard output and error * output of a subprocess are sent to two separate streams, which can * be accessed using the {@link Process#getInputStream()} and {@link * Process#getErrorStream()} methods. If the value is set to * <code>true</code>, the standard error is merged with the standard * output. This makes it easier to correlate error messages with the * corresponding output. In this case, the merged data can be read * from the stream returned by {@link Process#getInputStream()}, while * reading from the stream returned by {@link * Process#getErrorStream()} will get an immediate end of file. * <p>Modifying a process builder's attributes will affect processes * subsequently started by that object's {@link #start()} method, but * will never affect previously started processes or the Java process * <p>Most error checking is performed by the {@link #start()} method. * It is possible to modify the state of an object so that {@link * #start()} will fail. For example, setting the command attribute to * an empty list will not throw an exception unless {@link #start()} * <p><strong>Note that this class is not synchronized.</strong> * If multiple threads access a <code>ProcessBuilder</code> instance * concurrently, and at least one of the threads modifies one of the * attributes structurally, it <i>must</i> be synchronized externally. * <p>Starting a new process which uses the default working directory * and environment is easy: * Process p = new ProcessBuilder("myCommand", "myArg").start(); * <p>Here is an example that starts a process with a modified working * directory and environment: * ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2"); * Map<String, String> env = pb.environment(); * env.put("VAR1", "myValue"); * env.remove("OTHERVAR"); * env.put("VAR2", env.get("VAR1") + "suffix"); * pb.directory(new File("myDir")); * Process p = pb.start(); * <p>To start a process with an explicit set of environment * variables, first call {@link java.util.Map#clear() Map.clear()} * before adding environment variables. * Constructs a process builder with the specified operating * system program and arguments. This constructor does <i>not</i> * make a copy of the <code>command</code> list. Subsequent * updates to the list will be reflected in the state of the * process builder. It is not checked whether * <code>command</code> corresponds to a valid operating system * @param command The list containing the program and its arguments * @throws NullPointerException * If the argument is <code>null</code> * Constructs a process builder with the specified operating * system program and arguments. This is a convenience * constructor that sets the process builder's command to a string * list containing the same strings as the <code>command</code> * array, in the same order. It is not checked whether * <code>command</code> corresponds to a valid operating system * @param command A string array containing the program and its arguments * Sets this process builder's operating system program and * arguments. This method does <i>not</i> make a copy of the * <code>command</code> list. Subsequent updates to the list will * be reflected in the state of the process builder. It is not * checked whether <code>command</code> corresponds to a valid * operating system command.</p> * @param command The list containing the program and its arguments * @return This process builder * @throws NullPointerException * If the argument is <code>null</code> * Sets this process builder's operating system program and * arguments. This is a convenience method that sets the command * to a string list containing the same strings as the * <code>command</code> array, in the same order. It is not * checked whether <code>command</code> corresponds to a valid * operating system command.</p> * @param command A string array containing the program and its arguments * @return This process builder * Returns this process builder's operating system program and * arguments. The returned list is <i>not</i> a copy. Subsequent * updates to the list will be reflected in the state of this * @return This process builder's program and its arguments * Returns a string map view of this process builder's environment. * Whenever a process builder is created, the environment is * initialized to a copy of the current process environment (see * {@link System#getenv()}). Subprocesses subsequently started by * this object's {@link #start()} method will use this map as * <p>The returned object may be modified using ordinary {@link * java.util.Map Map} operations. These modifications will be * visible to subprocesses started via the {@link #start()} * method. Two <code>ProcessBuilder</code> instances always * contain independent process environments, so changes to the * returned map will never be reflected in any other * <code>ProcessBuilder</code> instance or the values returned by * {@link System#getenv System.getenv}. * <p>If the system does not support environment variables, an * <p>The returned map does not permit null keys or values. * Attempting to insert or query the presence of a null key or * value will throw a {@link NullPointerException}. * Attempting to query the presence of a key or value which is not * of type {@link String} will throw a {@link ClassCastException}. * <p>The behavior of the returned map is system-dependent. A * system may not allow modifications to environment variables or * may forbid certain variable names or values. For this reason, * attempts to modify the map may fail with * {@link UnsupportedOperationException} or * {@link IllegalArgumentException} * if the modification is not permitted by the operating system. * <p>Since the external format of environment variable names and * values is system-dependent, there may not be a one-to-one * mapping between them and Java's Unicode strings. Nevertheless, * the map is implemented in such a way that environment variables * which are not modified by Java code will have an unmodified * native representation in the subprocess. * <p>The returned map and its collection views may not obey the * general contract of the {@link Object#equals} and * {@link Object#hashCode} methods. * <p>The returned map is typically case-sensitive on all platforms. * <p>If a security manager exists, its * {@link SecurityManager#checkPermission checkPermission} * method is called with a * <code>{@link RuntimePermission}("getenv.*")</code> * permission. This may result in a {@link SecurityException} being * <p>When passing information to a Java subprocess, * <a href=System.html#EnvironmentVSSystemProperties>system properties</a> * are generally preferred over environment variables.</p> * @return This process builder's environment * @throws SecurityException * If a security manager exists and its * {@link SecurityManager#checkPermission checkPermission} * method doesn't allow access to the process environment * @see Runtime#exec(String[],String[],java.io.File) // Only for use by Runtime.exec(...envp...) // Before 1.5, we blindly passed invalid envstrings // We would like to throw an exception, but do not, // for compatibility with old broken code. // Silently discard any trailing junk. // Silently ignore envstrings lacking the required `='. * Returns this process builder's working directory. * Subprocesses subsequently started by this object's {@link * #start()} method will use this as their working directory. * The returned value may be <code>null</code> -- this means to use * the working directory of the current Java process, usually the * directory named by the system property <code>user.dir</code>, * as the working directory of the child process.</p> * @return This process builder's working directory * Sets this process builder's working directory. * Subprocesses subsequently started by this object's {@link * #start()} method will use this as their working directory. * The argument may be <code>null</code> -- this means to use the * working directory of the current Java process, usually the * directory named by the system property <code>user.dir</code>, * as the working directory of the child process.</p> * @param directory The new working directory * @return This process builder * Tells whether this process builder merges standard error and * <p>If this property is <code>true</code>, then any error output * generated by subprocesses subsequently started by this object's * {@link #start()} method will be merged with the standard * output, so that both can be read using the * {@link Process#getInputStream()} method. This makes it easier * to correlate error messages with the corresponding output. * The initial value is <code>false</code>.</p> * @return This process builder's <code>redirectErrorStream</code> property * Sets this process builder's <code>redirectErrorStream</code> property. * <p>If this property is <code>true</code>, then any error output * generated by subprocesses subsequently started by this object's * {@link #start()} method will be merged with the standard * output, so that both can be read using the * {@link Process#getInputStream()} method. This makes it easier * to correlate error messages with the corresponding output. * The initial value is <code>false</code>.</p> * @param redirectErrorStream The new property value * @return This process builder * Starts a new process using the attributes of this process builder. * <p>The new process will * invoke the command and arguments given by {@link #command()}, * in a working directory as given by {@link #directory()}, * with a process environment as given by {@link #environment()}. * <p>This method checks that the command is a valid operating * system command. Which commands are valid is system-dependent, * but at the very least the command must be a non-empty list of * <p>If there is a security manager, its * {@link SecurityManager#checkExec checkExec} * method is called with the first component of this object's * <code>command</code> array as its argument. This may result in * a {@link SecurityException} being thrown. * <p>Starting an operating system process is highly system-dependent. * Among the many things that can go wrong are: * <li>The operating system program file was not found. * <li>Access to the program file was denied. * <li>The working directory does not exist. * <p>In such cases an exception will be thrown. The exact nature * of the exception is system-dependent, but it will always be a * subclass of {@link IOException}. * <p>Subsequent modifications to this process builder will not * affect the returned {@link Process}.</p> * @return A new {@link Process} object for managing the subprocess * @throws NullPointerException * If an element of the command list is null * @throws IndexOutOfBoundsException * If the command is an empty list (has size <code>0</code>) * @throws SecurityException * If a security manager exists and its * {@link SecurityManager#checkExec checkExec} * method doesn't allow creation of the subprocess * @see Runtime#exec(String[], String[], java.io.File) * @see SecurityManager#checkExec(String) // Must convert to array first -- a malicious user-supplied // list might try to circumvent the security check. // Throws IndexOutOfBoundsException if command is empty // It's much easier for us to create a high-quality error // message than the low-level C code which found the problem. "Cannot run program \"" +
prog +
"\"" + (
dir ==
null ?
"" :
" (in directory \"" +
dir +
"\")")