jdk/src/share/classes/java/lang/ProcessBuilder.java
changeset 2 90ce3da70b43
child 48 dc5744ca15ea
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2003-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package java.lang;
       
    27 
       
    28 import java.io.File;
       
    29 import java.io.IOException;
       
    30 import java.util.ArrayList;
       
    31 import java.util.List;
       
    32 import java.util.Map;
       
    33 
       
    34 /**
       
    35  * This class is used to create operating system processes.
       
    36  *
       
    37  * <p>Each <code>ProcessBuilder</code> instance manages a collection
       
    38  * of process attributes.  The {@link #start()} method creates a new
       
    39  * {@link Process} instance with those attributes.  The {@link
       
    40  * #start()} method can be invoked repeatedly from the same instance
       
    41  * to create new subprocesses with identical or related attributes.
       
    42  *
       
    43  * <p>Each process builder manages these process attributes:
       
    44  *
       
    45  * <ul>
       
    46  *
       
    47  * <li>a <i>command</i>, a list of strings which signifies the
       
    48  * external program file to be invoked and its arguments, if any.
       
    49  * Which string lists represent a valid operating system command is
       
    50  * system-dependent.  For example, it is common for each conceptual
       
    51  * argument to be an element in this list, but there are operating
       
    52  * systems where programs are expected to tokenize command line
       
    53  * strings themselves - on such a system a Java implementation might
       
    54  * require commands to contain exactly two elements.
       
    55  *
       
    56  * <li>an <i>environment</i>, which is a system-dependent mapping from
       
    57  * <i>variables</i> to <i>values</i>.  The initial value is a copy of
       
    58  * the environment of the current process (see {@link System#getenv()}).
       
    59  *
       
    60  * <li>a <i>working directory</i>.  The default value is the current
       
    61  * working directory of the current process, usually the directory
       
    62  * named by the system property <code>user.dir</code>.
       
    63  *
       
    64  * <li>a <i>redirectErrorStream</i> property.  Initially, this property
       
    65  * is <code>false</code>, meaning that the standard output and error
       
    66  * output of a subprocess are sent to two separate streams, which can
       
    67  * be accessed using the {@link Process#getInputStream()} and {@link
       
    68  * Process#getErrorStream()} methods.  If the value is set to
       
    69  * <code>true</code>, the standard error is merged with the standard
       
    70  * output.  This makes it easier to correlate error messages with the
       
    71  * corresponding output.  In this case, the merged data can be read
       
    72  * from the stream returned by {@link Process#getInputStream()}, while
       
    73  * reading from the stream returned by {@link
       
    74  * Process#getErrorStream()} will get an immediate end of file.
       
    75  *
       
    76  * </ul>
       
    77  *
       
    78  * <p>Modifying a process builder's attributes will affect processes
       
    79  * subsequently started by that object's {@link #start()} method, but
       
    80  * will never affect previously started processes or the Java process
       
    81  * itself.
       
    82  *
       
    83  * <p>Most error checking is performed by the {@link #start()} method.
       
    84  * It is possible to modify the state of an object so that {@link
       
    85  * #start()} will fail.  For example, setting the command attribute to
       
    86  * an empty list will not throw an exception unless {@link #start()}
       
    87  * is invoked.
       
    88  *
       
    89  * <p><strong>Note that this class is not synchronized.</strong>
       
    90  * If multiple threads access a <code>ProcessBuilder</code> instance
       
    91  * concurrently, and at least one of the threads modifies one of the
       
    92  * attributes structurally, it <i>must</i> be synchronized externally.
       
    93  *
       
    94  * <p>Starting a new process which uses the default working directory
       
    95  * and environment is easy:
       
    96  *
       
    97  * <blockquote><pre>
       
    98  * Process p = new ProcessBuilder("myCommand", "myArg").start();
       
    99  * </pre></blockquote>
       
   100  *
       
   101  * <p>Here is an example that starts a process with a modified working
       
   102  * directory and environment:
       
   103  *
       
   104  * <blockquote><pre>
       
   105  * ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
       
   106  * Map&lt;String, String&gt; env = pb.environment();
       
   107  * env.put("VAR1", "myValue");
       
   108  * env.remove("OTHERVAR");
       
   109  * env.put("VAR2", env.get("VAR1") + "suffix");
       
   110  * pb.directory(new File("myDir"));
       
   111  * Process p = pb.start();
       
   112  * </pre></blockquote>
       
   113  *
       
   114  * <p>To start a process with an explicit set of environment
       
   115  * variables, first call {@link java.util.Map#clear() Map.clear()}
       
   116  * before adding environment variables.
       
   117  *
       
   118  * @since 1.5
       
   119  */
       
   120 
       
   121 public final class ProcessBuilder
       
   122 {
       
   123     private List<String> command;
       
   124     private File directory;
       
   125     private Map<String,String> environment;
       
   126     private boolean redirectErrorStream;
       
   127 
       
   128     /**
       
   129      * Constructs a process builder with the specified operating
       
   130      * system program and arguments.  This constructor does <i>not</i>
       
   131      * make a copy of the <code>command</code> list.  Subsequent
       
   132      * updates to the list will be reflected in the state of the
       
   133      * process builder.  It is not checked whether
       
   134      * <code>command</code> corresponds to a valid operating system
       
   135      * command.</p>
       
   136      *
       
   137      * @param   command  The list containing the program and its arguments
       
   138      *
       
   139      * @throws  NullPointerException
       
   140      *          If the argument is <code>null</code>
       
   141      */
       
   142     public ProcessBuilder(List<String> command) {
       
   143         if (command == null)
       
   144             throw new NullPointerException();
       
   145         this.command = command;
       
   146     }
       
   147 
       
   148     /**
       
   149      * Constructs a process builder with the specified operating
       
   150      * system program and arguments.  This is a convenience
       
   151      * constructor that sets the process builder's command to a string
       
   152      * list containing the same strings as the <code>command</code>
       
   153      * array, in the same order.  It is not checked whether
       
   154      * <code>command</code> corresponds to a valid operating system
       
   155      * command.</p>
       
   156      *
       
   157      * @param   command  A string array containing the program and its arguments
       
   158      */
       
   159     public ProcessBuilder(String... command) {
       
   160         this.command = new ArrayList<String>(command.length);
       
   161         for (String arg : command)
       
   162             this.command.add(arg);
       
   163     }
       
   164 
       
   165     /**
       
   166      * Sets this process builder's operating system program and
       
   167      * arguments.  This method does <i>not</i> make a copy of the
       
   168      * <code>command</code> list.  Subsequent updates to the list will
       
   169      * be reflected in the state of the process builder.  It is not
       
   170      * checked whether <code>command</code> corresponds to a valid
       
   171      * operating system command.</p>
       
   172      *
       
   173      * @param   command  The list containing the program and its arguments
       
   174      * @return  This process builder
       
   175      *
       
   176      * @throws  NullPointerException
       
   177      *          If the argument is <code>null</code>
       
   178      */
       
   179     public ProcessBuilder command(List<String> command) {
       
   180         if (command == null)
       
   181             throw new NullPointerException();
       
   182         this.command = command;
       
   183         return this;
       
   184     }
       
   185 
       
   186     /**
       
   187      * Sets this process builder's operating system program and
       
   188      * arguments.  This is a convenience method that sets the command
       
   189      * to a string list containing the same strings as the
       
   190      * <code>command</code> array, in the same order.  It is not
       
   191      * checked whether <code>command</code> corresponds to a valid
       
   192      * operating system command.</p>
       
   193      *
       
   194      * @param   command  A string array containing the program and its arguments
       
   195      * @return  This process builder
       
   196      */
       
   197     public ProcessBuilder command(String... command) {
       
   198         this.command = new ArrayList<String>(command.length);
       
   199         for (String arg : command)
       
   200             this.command.add(arg);
       
   201         return this;
       
   202     }
       
   203 
       
   204     /**
       
   205      * Returns this process builder's operating system program and
       
   206      * arguments.  The returned list is <i>not</i> a copy.  Subsequent
       
   207      * updates to the list will be reflected in the state of this
       
   208      * process builder.</p>
       
   209      *
       
   210      * @return  This process builder's program and its arguments
       
   211      */
       
   212     public List<String> command() {
       
   213         return command;
       
   214     }
       
   215 
       
   216     /**
       
   217      * Returns a string map view of this process builder's environment.
       
   218      *
       
   219      * Whenever a process builder is created, the environment is
       
   220      * initialized to a copy of the current process environment (see
       
   221      * {@link System#getenv()}).  Subprocesses subsequently started by
       
   222      * this object's {@link #start()} method will use this map as
       
   223      * their environment.
       
   224      *
       
   225      * <p>The returned object may be modified using ordinary {@link
       
   226      * java.util.Map Map} operations.  These modifications will be
       
   227      * visible to subprocesses started via the {@link #start()}
       
   228      * method.  Two <code>ProcessBuilder</code> instances always
       
   229      * contain independent process environments, so changes to the
       
   230      * returned map will never be reflected in any other
       
   231      * <code>ProcessBuilder</code> instance or the values returned by
       
   232      * {@link System#getenv System.getenv}.
       
   233      *
       
   234      * <p>If the system does not support environment variables, an
       
   235      * empty map is returned.
       
   236      *
       
   237      * <p>The returned map does not permit null keys or values.
       
   238      * Attempting to insert or query the presence of a null key or
       
   239      * value will throw a {@link NullPointerException}.
       
   240      * Attempting to query the presence of a key or value which is not
       
   241      * of type {@link String} will throw a {@link ClassCastException}.
       
   242      *
       
   243      * <p>The behavior of the returned map is system-dependent.  A
       
   244      * system may not allow modifications to environment variables or
       
   245      * may forbid certain variable names or values.  For this reason,
       
   246      * attempts to modify the map may fail with
       
   247      * {@link UnsupportedOperationException} or
       
   248      * {@link IllegalArgumentException}
       
   249      * if the modification is not permitted by the operating system.
       
   250      *
       
   251      * <p>Since the external format of environment variable names and
       
   252      * values is system-dependent, there may not be a one-to-one
       
   253      * mapping between them and Java's Unicode strings.  Nevertheless,
       
   254      * the map is implemented in such a way that environment variables
       
   255      * which are not modified by Java code will have an unmodified
       
   256      * native representation in the subprocess.
       
   257      *
       
   258      * <p>The returned map and its collection views may not obey the
       
   259      * general contract of the {@link Object#equals} and
       
   260      * {@link Object#hashCode} methods.
       
   261      *
       
   262      * <p>The returned map is typically case-sensitive on all platforms.
       
   263      *
       
   264      * <p>If a security manager exists, its
       
   265      * {@link SecurityManager#checkPermission checkPermission}
       
   266      * method is called with a
       
   267      * <code>{@link RuntimePermission}("getenv.*")</code>
       
   268      * permission.  This may result in a {@link SecurityException} being
       
   269      * thrown.
       
   270      *
       
   271      * <p>When passing information to a Java subprocess,
       
   272      * <a href=System.html#EnvironmentVSSystemProperties>system properties</a>
       
   273      * are generally preferred over environment variables.</p>
       
   274      *
       
   275      * @return  This process builder's environment
       
   276      *
       
   277      * @throws  SecurityException
       
   278      *          If a security manager exists and its
       
   279      *          {@link SecurityManager#checkPermission checkPermission}
       
   280      *          method doesn't allow access to the process environment
       
   281      *
       
   282      * @see     Runtime#exec(String[],String[],java.io.File)
       
   283      * @see     System#getenv()
       
   284      */
       
   285     public Map<String,String> environment() {
       
   286         SecurityManager security = System.getSecurityManager();
       
   287         if (security != null)
       
   288             security.checkPermission(new RuntimePermission("getenv.*"));
       
   289 
       
   290         if (environment == null)
       
   291             environment = ProcessEnvironment.environment();
       
   292 
       
   293         assert environment != null;
       
   294 
       
   295         return environment;
       
   296     }
       
   297 
       
   298     // Only for use by Runtime.exec(...envp...)
       
   299     ProcessBuilder environment(String[] envp) {
       
   300         assert environment == null;
       
   301         if (envp != null) {
       
   302             environment = ProcessEnvironment.emptyEnvironment(envp.length);
       
   303             assert environment != null;
       
   304 
       
   305             for (String envstring : envp) {
       
   306                 // Before 1.5, we blindly passed invalid envstrings
       
   307                 // to the child process.
       
   308                 // We would like to throw an exception, but do not,
       
   309                 // for compatibility with old broken code.
       
   310 
       
   311                 // Silently discard any trailing junk.
       
   312                 if (envstring.indexOf((int) '\u0000') != -1)
       
   313                     envstring = envstring.replaceFirst("\u0000.*", "");
       
   314 
       
   315                 int eqlsign =
       
   316                     envstring.indexOf('=', ProcessEnvironment.MIN_NAME_LENGTH);
       
   317                 // Silently ignore envstrings lacking the required `='.
       
   318                 if (eqlsign != -1)
       
   319                     environment.put(envstring.substring(0,eqlsign),
       
   320                                     envstring.substring(eqlsign+1));
       
   321             }
       
   322         }
       
   323         return this;
       
   324     }
       
   325 
       
   326     /**
       
   327      * Returns this process builder's working directory.
       
   328      *
       
   329      * Subprocesses subsequently started by this object's {@link
       
   330      * #start()} method will use this as their working directory.
       
   331      * The returned value may be <code>null</code> -- this means to use
       
   332      * the working directory of the current Java process, usually the
       
   333      * directory named by the system property <code>user.dir</code>,
       
   334      * as the working directory of the child process.</p>
       
   335      *
       
   336      * @return  This process builder's working directory
       
   337      */
       
   338     public File directory() {
       
   339         return directory;
       
   340     }
       
   341 
       
   342     /**
       
   343      * Sets this process builder's working directory.
       
   344      *
       
   345      * Subprocesses subsequently started by this object's {@link
       
   346      * #start()} method will use this as their working directory.
       
   347      * The argument may be <code>null</code> -- this means to use the
       
   348      * working directory of the current Java process, usually the
       
   349      * directory named by the system property <code>user.dir</code>,
       
   350      * as the working directory of the child process.</p>
       
   351      *
       
   352      * @param   directory  The new working directory
       
   353      * @return  This process builder
       
   354      */
       
   355     public ProcessBuilder directory(File directory) {
       
   356         this.directory = directory;
       
   357         return this;
       
   358     }
       
   359 
       
   360     /**
       
   361      * Tells whether this process builder merges standard error and
       
   362      * standard output.
       
   363      *
       
   364      * <p>If this property is <code>true</code>, then any error output
       
   365      * generated by subprocesses subsequently started by this object's
       
   366      * {@link #start()} method will be merged with the standard
       
   367      * output, so that both can be read using the
       
   368      * {@link Process#getInputStream()} method.  This makes it easier
       
   369      * to correlate error messages with the corresponding output.
       
   370      * The initial value is <code>false</code>.</p>
       
   371      *
       
   372      * @return  This process builder's <code>redirectErrorStream</code> property
       
   373      */
       
   374     public boolean redirectErrorStream() {
       
   375         return redirectErrorStream;
       
   376     }
       
   377 
       
   378     /**
       
   379      * Sets this process builder's <code>redirectErrorStream</code> property.
       
   380      *
       
   381      * <p>If this property is <code>true</code>, then any error output
       
   382      * generated by subprocesses subsequently started by this object's
       
   383      * {@link #start()} method will be merged with the standard
       
   384      * output, so that both can be read using the
       
   385      * {@link Process#getInputStream()} method.  This makes it easier
       
   386      * to correlate error messages with the corresponding output.
       
   387      * The initial value is <code>false</code>.</p>
       
   388      *
       
   389      * @param   redirectErrorStream  The new property value
       
   390      * @return  This process builder
       
   391      */
       
   392     public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) {
       
   393         this.redirectErrorStream = redirectErrorStream;
       
   394         return this;
       
   395     }
       
   396 
       
   397     /**
       
   398      * Starts a new process using the attributes of this process builder.
       
   399      *
       
   400      * <p>The new process will
       
   401      * invoke the command and arguments given by {@link #command()},
       
   402      * in a working directory as given by {@link #directory()},
       
   403      * with a process environment as given by {@link #environment()}.
       
   404      *
       
   405      * <p>This method checks that the command is a valid operating
       
   406      * system command.  Which commands are valid is system-dependent,
       
   407      * but at the very least the command must be a non-empty list of
       
   408      * non-null strings.
       
   409      *
       
   410      * <p>If there is a security manager, its
       
   411      * {@link SecurityManager#checkExec checkExec}
       
   412      * method is called with the first component of this object's
       
   413      * <code>command</code> array as its argument. This may result in
       
   414      * a {@link SecurityException} being thrown.
       
   415      *
       
   416      * <p>Starting an operating system process is highly system-dependent.
       
   417      * Among the many things that can go wrong are:
       
   418      * <ul>
       
   419      * <li>The operating system program file was not found.
       
   420      * <li>Access to the program file was denied.
       
   421      * <li>The working directory does not exist.
       
   422      * </ul>
       
   423      *
       
   424      * <p>In such cases an exception will be thrown.  The exact nature
       
   425      * of the exception is system-dependent, but it will always be a
       
   426      * subclass of {@link IOException}.
       
   427      *
       
   428      * <p>Subsequent modifications to this process builder will not
       
   429      * affect the returned {@link Process}.</p>
       
   430      *
       
   431      * @return  A new {@link Process} object for managing the subprocess
       
   432      *
       
   433      * @throws  NullPointerException
       
   434      *          If an element of the command list is null
       
   435      *
       
   436      * @throws  IndexOutOfBoundsException
       
   437      *          If the command is an empty list (has size <code>0</code>)
       
   438      *
       
   439      * @throws  SecurityException
       
   440      *          If a security manager exists and its
       
   441      *          {@link SecurityManager#checkExec checkExec}
       
   442      *          method doesn't allow creation of the subprocess
       
   443      *
       
   444      * @throws  IOException
       
   445      *          If an I/O error occurs
       
   446      *
       
   447      * @see     Runtime#exec(String[], String[], java.io.File)
       
   448      * @see     SecurityManager#checkExec(String)
       
   449      */
       
   450     public Process start() throws IOException {
       
   451         // Must convert to array first -- a malicious user-supplied
       
   452         // list might try to circumvent the security check.
       
   453         String[] cmdarray = command.toArray(new String[command.size()]);
       
   454         for (String arg : cmdarray)
       
   455             if (arg == null)
       
   456                 throw new NullPointerException();
       
   457         // Throws IndexOutOfBoundsException if command is empty
       
   458         String prog = cmdarray[0];
       
   459 
       
   460         SecurityManager security = System.getSecurityManager();
       
   461         if (security != null)
       
   462             security.checkExec(prog);
       
   463 
       
   464         String dir = directory == null ? null : directory.toString();
       
   465 
       
   466         try {
       
   467             return ProcessImpl.start(cmdarray,
       
   468                                      environment,
       
   469                                      dir,
       
   470                                      redirectErrorStream);
       
   471         } catch (IOException e) {
       
   472             // It's much easier for us to create a high-quality error
       
   473             // message than the low-level C code which found the problem.
       
   474             throw new IOException(
       
   475                 "Cannot run program \"" + prog + "\""
       
   476                 + (dir == null ? "" : " (in directory \"" + dir + "\")")
       
   477                 + ": " + e.getMessage(),
       
   478                 e);
       
   479         }
       
   480     }
       
   481 }