View Javadoc
1   /*
2    * Copyright (c) 2003, 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.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package java.lang;
27  
28  import java.io.File;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.OutputStream;
32  import java.util.Arrays;
33  import java.util.ArrayList;
34  import java.util.List;
35  import java.util.Map;
36  
37  /**
38   * This class is used to create operating system processes.
39   *
40   * <p>Each {@code ProcessBuilder} instance manages a collection
41   * of process attributes.  The {@link #start()} method creates a new
42   * {@link Process} instance with those attributes.  The {@link
43   * #start()} method can be invoked repeatedly from the same instance
44   * to create new subprocesses with identical or related attributes.
45   *
46   * <p>Each process builder manages these process attributes:
47   *
48   * <ul>
49   *
50   * <li>a <i>command</i>, a list of strings which signifies the
51   * external program file to be invoked and its arguments, if any.
52   * Which string lists represent a valid operating system command is
53   * system-dependent.  For example, it is common for each conceptual
54   * argument to be an element in this list, but there are operating
55   * systems where programs are expected to tokenize command line
56   * strings themselves - on such a system a Java implementation might
57   * require commands to contain exactly two elements.
58   *
59   * <li>an <i>environment</i>, which is a system-dependent mapping from
60   * <i>variables</i> to <i>values</i>.  The initial value is a copy of
61   * the environment of the current process (see {@link System#getenv()}).
62   *
63   * <li>a <i>working directory</i>.  The default value is the current
64   * working directory of the current process, usually the directory
65   * named by the system property {@code user.dir}.
66   *
67   * <li><a name="redirect-input">a source of <i>standard input</i></a>.
68   * By default, the subprocess reads input from a pipe.  Java code
69   * can access this pipe via the output stream returned by
70   * {@link Process#getOutputStream()}.  However, standard input may
71   * be redirected to another source using
72   * {@link #redirectInput(Redirect) redirectInput}.
73   * In this case, {@link Process#getOutputStream()} will return a
74   * <i>null output stream</i>, for which:
75   *
76   * <ul>
77   * <li>the {@link OutputStream#write(int) write} methods always
78   * throw {@code IOException}
79   * <li>the {@link OutputStream#close() close} method does nothing
80   * </ul>
81   *
82   * <li><a name="redirect-output">a destination for <i>standard output</i>
83   * and <i>standard error</i></a>.  By default, the subprocess writes standard
84   * output and standard error to pipes.  Java code can access these pipes
85   * via the input streams returned by {@link Process#getInputStream()} and
86   * {@link Process#getErrorStream()}.  However, standard output and
87   * standard error may be redirected to other destinations using
88   * {@link #redirectOutput(Redirect) redirectOutput} and
89   * {@link #redirectError(Redirect) redirectError}.
90   * In this case, {@link Process#getInputStream()} and/or
91   * {@link Process#getErrorStream()} will return a <i>null input
92   * stream</i>, for which:
93   *
94   * <ul>
95   * <li>the {@link InputStream#read() read} methods always return
96   * {@code -1}
97   * <li>the {@link InputStream#available() available} method always returns
98   * {@code 0}
99   * <li>the {@link InputStream#close() close} method does nothing
100  * </ul>
101  *
102  * <li>a <i>redirectErrorStream</i> property.  Initially, this property
103  * is {@code false}, meaning that the standard output and error
104  * output of a subprocess are sent to two separate streams, which can
105  * be accessed using the {@link Process#getInputStream()} and {@link
106  * Process#getErrorStream()} methods.
107  *
108  * <p>If the value is set to {@code true}, then:
109  *
110  * <ul>
111  * <li>standard error is merged with the standard output and always sent
112  * to the same destination (this makes it easier to correlate error
113  * messages with the corresponding output)
114  * <li>the common destination of standard error and standard output can be
115  * redirected using
116  * {@link #redirectOutput(Redirect) redirectOutput}
117  * <li>any redirection set by the
118  * {@link #redirectError(Redirect) redirectError}
119  * method is ignored when creating a subprocess
120  * <li>the stream returned from {@link Process#getErrorStream()} will
121  * always be a <a href="#redirect-output">null input stream</a>
122  * </ul>
123  *
124  * </ul>
125  *
126  * <p>Modifying a process builder's attributes will affect processes
127  * subsequently started by that object's {@link #start()} method, but
128  * will never affect previously started processes or the Java process
129  * itself.
130  *
131  * <p>Most error checking is performed by the {@link #start()} method.
132  * It is possible to modify the state of an object so that {@link
133  * #start()} will fail.  For example, setting the command attribute to
134  * an empty list will not throw an exception unless {@link #start()}
135  * is invoked.
136  *
137  * <p><strong>Note that this class is not synchronized.</strong>
138  * If multiple threads access a {@code ProcessBuilder} instance
139  * concurrently, and at least one of the threads modifies one of the
140  * attributes structurally, it <i>must</i> be synchronized externally.
141  *
142  * <p>Starting a new process which uses the default working directory
143  * and environment is easy:
144  *
145  * <pre> {@code
146  * Process p = new ProcessBuilder("myCommand", "myArg").start();
147  * }</pre>
148  *
149  * <p>Here is an example that starts a process with a modified working
150  * directory and environment, and redirects standard output and error
151  * to be appended to a log file:
152  *
153  * <pre> {@code
154  * ProcessBuilder pb =
155  *   new ProcessBuilder("myCommand", "myArg1", "myArg2");
156  * Map<String, String> env = pb.environment();
157  * env.put("VAR1", "myValue");
158  * env.remove("OTHERVAR");
159  * env.put("VAR2", env.get("VAR1") + "suffix");
160  * pb.directory(new File("myDir"));
161  * File log = new File("log");
162  * pb.redirectErrorStream(true);
163  * pb.redirectOutput(Redirect.appendTo(log));
164  * Process p = pb.start();
165  * assert pb.redirectInput() == Redirect.PIPE;
166  * assert pb.redirectOutput().file() == log;
167  * assert p.getInputStream().read() == -1;
168  * }</pre>
169  *
170  * <p>To start a process with an explicit set of environment
171  * variables, first call {@link java.util.Map#clear() Map.clear()}
172  * before adding environment variables.
173  *
174  * @author Martin Buchholz
175  * @since 1.5
176  */
177 
178 public final class ProcessBuilder
179 {
180     private List<String> command;
181     private File directory;
182     private Map<String,String> environment;
183     private boolean redirectErrorStream;
184     private Redirect[] redirects;
185 
186     /**
187      * Constructs a process builder with the specified operating
188      * system program and arguments.  This constructor does <i>not</i>
189      * make a copy of the {@code command} list.  Subsequent
190      * updates to the list will be reflected in the state of the
191      * process builder.  It is not checked whether
192      * {@code command} corresponds to a valid operating system
193      * command.
194      *
195      * @param  command the list containing the program and its arguments
196      * @throws NullPointerException if the argument is null
197      */
198     public ProcessBuilder(List<String> command) {
199         if (command == null)
200             throw new NullPointerException();
201         this.command = command;
202     }
203 
204     /**
205      * Constructs a process builder with the specified operating
206      * system program and arguments.  This is a convenience
207      * constructor that sets the process builder's command to a string
208      * list containing the same strings as the {@code command}
209      * array, in the same order.  It is not checked whether
210      * {@code command} corresponds to a valid operating system
211      * command.
212      *
213      * @param command a string array containing the program and its arguments
214      */
215     public ProcessBuilder(String... command) {
216         this.command = new ArrayList<>(command.length);
217         for (String arg : command)
218             this.command.add(arg);
219     }
220 
221     /**
222      * Sets this process builder's operating system program and
223      * arguments.  This method does <i>not</i> make a copy of the
224      * {@code command} list.  Subsequent updates to the list will
225      * be reflected in the state of the process builder.  It is not
226      * checked whether {@code command} corresponds to a valid
227      * operating system command.
228      *
229      * @param  command the list containing the program and its arguments
230      * @return this process builder
231      *
232      * @throws NullPointerException if the argument is null
233      */
234     public ProcessBuilder command(List<String> command) {
235         if (command == null)
236             throw new NullPointerException();
237         this.command = command;
238         return this;
239     }
240 
241     /**
242      * Sets this process builder's operating system program and
243      * arguments.  This is a convenience method that sets the command
244      * to a string list containing the same strings as the
245      * {@code command} array, in the same order.  It is not
246      * checked whether {@code command} corresponds to a valid
247      * operating system command.
248      *
249      * @param  command a string array containing the program and its arguments
250      * @return this process builder
251      */
252     public ProcessBuilder command(String... command) {
253         this.command = new ArrayList<>(command.length);
254         for (String arg : command)
255             this.command.add(arg);
256         return this;
257     }
258 
259     /**
260      * Returns this process builder's operating system program and
261      * arguments.  The returned list is <i>not</i> a copy.  Subsequent
262      * updates to the list will be reflected in the state of this
263      * process builder.
264      *
265      * @return this process builder's program and its arguments
266      */
267     public List<String> command() {
268         return command;
269     }
270 
271     /**
272      * Returns a string map view of this process builder's environment.
273      *
274      * Whenever a process builder is created, the environment is
275      * initialized to a copy of the current process environment (see
276      * {@link System#getenv()}).  Subprocesses subsequently started by
277      * this object's {@link #start()} method will use this map as
278      * their environment.
279      *
280      * <p>The returned object may be modified using ordinary {@link
281      * java.util.Map Map} operations.  These modifications will be
282      * visible to subprocesses started via the {@link #start()}
283      * method.  Two {@code ProcessBuilder} instances always
284      * contain independent process environments, so changes to the
285      * returned map will never be reflected in any other
286      * {@code ProcessBuilder} instance or the values returned by
287      * {@link System#getenv System.getenv}.
288      *
289      * <p>If the system does not support environment variables, an
290      * empty map is returned.
291      *
292      * <p>The returned map does not permit null keys or values.
293      * Attempting to insert or query the presence of a null key or
294      * value will throw a {@link NullPointerException}.
295      * Attempting to query the presence of a key or value which is not
296      * of type {@link String} will throw a {@link ClassCastException}.
297      *
298      * <p>The behavior of the returned map is system-dependent.  A
299      * system may not allow modifications to environment variables or
300      * may forbid certain variable names or values.  For this reason,
301      * attempts to modify the map may fail with
302      * {@link UnsupportedOperationException} or
303      * {@link IllegalArgumentException}
304      * if the modification is not permitted by the operating system.
305      *
306      * <p>Since the external format of environment variable names and
307      * values is system-dependent, there may not be a one-to-one
308      * mapping between them and Java's Unicode strings.  Nevertheless,
309      * the map is implemented in such a way that environment variables
310      * which are not modified by Java code will have an unmodified
311      * native representation in the subprocess.
312      *
313      * <p>The returned map and its collection views may not obey the
314      * general contract of the {@link Object#equals} and
315      * {@link Object#hashCode} methods.
316      *
317      * <p>The returned map is typically case-sensitive on all platforms.
318      *
319      * <p>If a security manager exists, its
320      * {@link SecurityManager#checkPermission checkPermission} method
321      * is called with a
322      * {@link RuntimePermission}{@code ("getenv.*")} permission.
323      * This may result in a {@link SecurityException} being thrown.
324      *
325      * <p>When passing information to a Java subprocess,
326      * <a href=System.html#EnvironmentVSSystemProperties>system properties</a>
327      * are generally preferred over environment variables.
328      *
329      * @return this process builder's environment
330      *
331      * @throws SecurityException
332      *         if a security manager exists and its
333      *         {@link SecurityManager#checkPermission checkPermission}
334      *         method doesn't allow access to the process environment
335      *
336      * @see    Runtime#exec(String[],String[],java.io.File)
337      * @see    System#getenv()
338      */
339     public Map<String,String> environment() {
340         SecurityManager security = System.getSecurityManager();
341         if (security != null)
342             security.checkPermission(new RuntimePermission("getenv.*"));
343 
344         if (environment == null)
345             environment = ProcessEnvironment.environment();
346 
347         assert environment != null;
348 
349         return environment;
350     }
351 
352     // Only for use by Runtime.exec(...envp...)
353     ProcessBuilder environment(String[] envp) {
354         assert environment == null;
355         if (envp != null) {
356             environment = ProcessEnvironment.emptyEnvironment(envp.length);
357             assert environment != null;
358 
359             for (String envstring : envp) {
360                 // Before 1.5, we blindly passed invalid envstrings
361                 // to the child process.
362                 // We would like to throw an exception, but do not,
363                 // for compatibility with old broken code.
364 
365                 // Silently discard any trailing junk.
366                 if (envstring.indexOf((int) '\u0000') != -1)
367                     envstring = envstring.replaceFirst("\u0000.*", "");
368 
369                 int eqlsign =
370                     envstring.indexOf('=', ProcessEnvironment.MIN_NAME_LENGTH);
371                 // Silently ignore envstrings lacking the required `='.
372                 if (eqlsign != -1)
373                     environment.put(envstring.substring(0,eqlsign),
374                                     envstring.substring(eqlsign+1));
375             }
376         }
377         return this;
378     }
379 
380     /**
381      * Returns this process builder's working directory.
382      *
383      * Subprocesses subsequently started by this object's {@link
384      * #start()} method will use this as their working directory.
385      * The returned value may be {@code null} -- this means to use
386      * the working directory of the current Java process, usually the
387      * directory named by the system property {@code user.dir},
388      * as the working directory of the child process.
389      *
390      * @return this process builder's working directory
391      */
392     public File directory() {
393         return directory;
394     }
395 
396     /**
397      * Sets this process builder's working directory.
398      *
399      * Subprocesses subsequently started by this object's {@link
400      * #start()} method will use this as their working directory.
401      * The argument may be {@code null} -- this means to use the
402      * working directory of the current Java process, usually the
403      * directory named by the system property {@code user.dir},
404      * as the working directory of the child process.
405      *
406      * @param  directory the new working directory
407      * @return this process builder
408      */
409     public ProcessBuilder directory(File directory) {
410         this.directory = directory;
411         return this;
412     }
413 
414     // ---------------- I/O Redirection ----------------
415 
416     /**
417      * Implements a <a href="#redirect-output">null input stream</a>.
418      */
419     static class NullInputStream extends InputStream {
420         static final NullInputStream INSTANCE = new NullInputStream();
421         private NullInputStream() {}
422         public int read()      { return -1; }
423         public int available() { return 0; }
424     }
425 
426     /**
427      * Implements a <a href="#redirect-input">null output stream</a>.
428      */
429     static class NullOutputStream extends OutputStream {
430         static final NullOutputStream INSTANCE = new NullOutputStream();
431         private NullOutputStream() {}
432         public void write(int b) throws IOException {
433             throw new IOException("Stream closed");
434         }
435     }
436 
437     /**
438      * Represents a source of subprocess input or a destination of
439      * subprocess output.
440      *
441      * Each {@code Redirect} instance is one of the following:
442      *
443      * <ul>
444      * <li>the special value {@link #PIPE Redirect.PIPE}
445      * <li>the special value {@link #INHERIT Redirect.INHERIT}
446      * <li>a redirection to read from a file, created by an invocation of
447      *     {@link Redirect#from Redirect.from(File)}
448      * <li>a redirection to write to a file,  created by an invocation of
449      *     {@link Redirect#to Redirect.to(File)}
450      * <li>a redirection to append to a file, created by an invocation of
451      *     {@link Redirect#appendTo Redirect.appendTo(File)}
452      * </ul>
453      *
454      * <p>Each of the above categories has an associated unique
455      * {@link Type Type}.
456      *
457      * @since 1.7
458      */
459     public static abstract class Redirect {
460         /**
461          * The type of a {@link Redirect}.
462          */
463         public enum Type {
464             /**
465              * The type of {@link Redirect#PIPE Redirect.PIPE}.
466              */
467             PIPE,
468 
469             /**
470              * The type of {@link Redirect#INHERIT Redirect.INHERIT}.
471              */
472             INHERIT,
473 
474             /**
475              * The type of redirects returned from
476              * {@link Redirect#from Redirect.from(File)}.
477              */
478             READ,
479 
480             /**
481              * The type of redirects returned from
482              * {@link Redirect#to Redirect.to(File)}.
483              */
484             WRITE,
485 
486             /**
487              * The type of redirects returned from
488              * {@link Redirect#appendTo Redirect.appendTo(File)}.
489              */
490             APPEND
491         };
492 
493         /**
494          * Returns the type of this {@code Redirect}.
495          * @return the type of this {@code Redirect}
496          */
497         public abstract Type type();
498 
499         /**
500          * Indicates that subprocess I/O will be connected to the
501          * current Java process over a pipe.
502          *
503          * This is the default handling of subprocess standard I/O.
504          *
505          * <p>It will always be true that
506          *  <pre> {@code
507          * Redirect.PIPE.file() == null &&
508          * Redirect.PIPE.type() == Redirect.Type.PIPE
509          * }</pre>
510          */
511         public static final Redirect PIPE = new Redirect() {
512                 public Type type() { return Type.PIPE; }
513                 public String toString() { return type().toString(); }};
514 
515         /**
516          * Indicates that subprocess I/O source or destination will be the
517          * same as those of the current process.  This is the normal
518          * behavior of most operating system command interpreters (shells).
519          *
520          * <p>It will always be true that
521          *  <pre> {@code
522          * Redirect.INHERIT.file() == null &&
523          * Redirect.INHERIT.type() == Redirect.Type.INHERIT
524          * }</pre>
525          */
526         public static final Redirect INHERIT = new Redirect() {
527                 public Type type() { return Type.INHERIT; }
528                 public String toString() { return type().toString(); }};
529 
530         /**
531          * Returns the {@link File} source or destination associated
532          * with this redirect, or {@code null} if there is no such file.
533          *
534          * @return the file associated with this redirect,
535          *         or {@code null} if there is no such file
536          */
537         public File file() { return null; }
538 
539         /**
540          * When redirected to a destination file, indicates if the output
541          * is to be written to the end of the file.
542          */
543         boolean append() {
544             throw new UnsupportedOperationException();
545         }
546 
547         /**
548          * Returns a redirect to read from the specified file.
549          *
550          * <p>It will always be true that
551          *  <pre> {@code
552          * Redirect.from(file).file() == file &&
553          * Redirect.from(file).type() == Redirect.Type.READ
554          * }</pre>
555          *
556          * @param file The {@code File} for the {@code Redirect}.
557          * @throws NullPointerException if the specified file is null
558          * @return a redirect to read from the specified file
559          */
560         public static Redirect from(final File file) {
561             if (file == null)
562                 throw new NullPointerException();
563             return new Redirect() {
564                     public Type type() { return Type.READ; }
565                     public File file() { return file; }
566                     public String toString() {
567                         return "redirect to read from file \"" + file + "\"";
568                     }
569                 };
570         }
571 
572         /**
573          * Returns a redirect to write to the specified file.
574          * If the specified file exists when the subprocess is started,
575          * its previous contents will be discarded.
576          *
577          * <p>It will always be true that
578          *  <pre> {@code
579          * Redirect.to(file).file() == file &&
580          * Redirect.to(file).type() == Redirect.Type.WRITE
581          * }</pre>
582          *
583          * @param file The {@code File} for the {@code Redirect}.
584          * @throws NullPointerException if the specified file is null
585          * @return a redirect to write to the specified file
586          */
587         public static Redirect to(final File file) {
588             if (file == null)
589                 throw new NullPointerException();
590             return new Redirect() {
591                     public Type type() { return Type.WRITE; }
592                     public File file() { return file; }
593                     public String toString() {
594                         return "redirect to write to file \"" + file + "\"";
595                     }
596                     boolean append() { return false; }
597                 };
598         }
599 
600         /**
601          * Returns a redirect to append to the specified file.
602          * Each write operation first advances the position to the
603          * end of the file and then writes the requested data.
604          * Whether the advancement of the position and the writing
605          * of the data are done in a single atomic operation is
606          * system-dependent and therefore unspecified.
607          *
608          * <p>It will always be true that
609          *  <pre> {@code
610          * Redirect.appendTo(file).file() == file &&
611          * Redirect.appendTo(file).type() == Redirect.Type.APPEND
612          * }</pre>
613          *
614          * @param file The {@code File} for the {@code Redirect}.
615          * @throws NullPointerException if the specified file is null
616          * @return a redirect to append to the specified file
617          */
618         public static Redirect appendTo(final File file) {
619             if (file == null)
620                 throw new NullPointerException();
621             return new Redirect() {
622                     public Type type() { return Type.APPEND; }
623                     public File file() { return file; }
624                     public String toString() {
625                         return "redirect to append to file \"" + file + "\"";
626                     }
627                     boolean append() { return true; }
628                 };
629         }
630 
631         /**
632          * Compares the specified object with this {@code Redirect} for
633          * equality.  Returns {@code true} if and only if the two
634          * objects are identical or both objects are {@code Redirect}
635          * instances of the same type associated with non-null equal
636          * {@code File} instances.
637          */
638         public boolean equals(Object obj) {
639             if (obj == this)
640                 return true;
641             if (! (obj instanceof Redirect))
642                 return false;
643             Redirect r = (Redirect) obj;
644             if (r.type() != this.type())
645                 return false;
646             assert this.file() != null;
647             return this.file().equals(r.file());
648         }
649 
650         /**
651          * Returns a hash code value for this {@code Redirect}.
652          * @return a hash code value for this {@code Redirect}
653          */
654         public int hashCode() {
655             File file = file();
656             if (file == null)
657                 return super.hashCode();
658             else
659                 return file.hashCode();
660         }
661 
662         /**
663          * No public constructors.  Clients must use predefined
664          * static {@code Redirect} instances or factory methods.
665          */
666         private Redirect() {}
667     }
668 
669     private Redirect[] redirects() {
670         if (redirects == null)
671             redirects = new Redirect[] {
672                 Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
673             };
674         return redirects;
675     }
676 
677     /**
678      * Sets this process builder's standard input source.
679      *
680      * Subprocesses subsequently started by this object's {@link #start()}
681      * method obtain their standard input from this source.
682      *
683      * <p>If the source is {@link Redirect#PIPE Redirect.PIPE}
684      * (the initial value), then the standard input of a
685      * subprocess can be written to using the output stream
686      * returned by {@link Process#getOutputStream()}.
687      * If the source is set to any other value, then
688      * {@link Process#getOutputStream()} will return a
689      * <a href="#redirect-input">null output stream</a>.
690      *
691      * @param  source the new standard input source
692      * @return this process builder
693      * @throws IllegalArgumentException
694      *         if the redirect does not correspond to a valid source
695      *         of data, that is, has type
696      *         {@link Redirect.Type#WRITE WRITE} or
697      *         {@link Redirect.Type#APPEND APPEND}
698      * @since  1.7
699      */
700     public ProcessBuilder redirectInput(Redirect source) {
701         if (source.type() == Redirect.Type.WRITE ||
702             source.type() == Redirect.Type.APPEND)
703             throw new IllegalArgumentException(
704                 "Redirect invalid for reading: " + source);
705         redirects()[0] = source;
706         return this;
707     }
708 
709     /**
710      * Sets this process builder's standard output destination.
711      *
712      * Subprocesses subsequently started by this object's {@link #start()}
713      * method send their standard output to this destination.
714      *
715      * <p>If the destination is {@link Redirect#PIPE Redirect.PIPE}
716      * (the initial value), then the standard output of a subprocess
717      * can be read using the input stream returned by {@link
718      * Process#getInputStream()}.
719      * If the destination is set to any other value, then
720      * {@link Process#getInputStream()} will return a
721      * <a href="#redirect-output">null input stream</a>.
722      *
723      * @param  destination the new standard output destination
724      * @return this process builder
725      * @throws IllegalArgumentException
726      *         if the redirect does not correspond to a valid
727      *         destination of data, that is, has type
728      *         {@link Redirect.Type#READ READ}
729      * @since  1.7
730      */
731     public ProcessBuilder redirectOutput(Redirect destination) {
732         if (destination.type() == Redirect.Type.READ)
733             throw new IllegalArgumentException(
734                 "Redirect invalid for writing: " + destination);
735         redirects()[1] = destination;
736         return this;
737     }
738 
739     /**
740      * Sets this process builder's standard error destination.
741      *
742      * Subprocesses subsequently started by this object's {@link #start()}
743      * method send their standard error to this destination.
744      *
745      * <p>If the destination is {@link Redirect#PIPE Redirect.PIPE}
746      * (the initial value), then the error output of a subprocess
747      * can be read using the input stream returned by {@link
748      * Process#getErrorStream()}.
749      * If the destination is set to any other value, then
750      * {@link Process#getErrorStream()} will return a
751      * <a href="#redirect-output">null input stream</a>.
752      *
753      * <p>If the {@link #redirectErrorStream redirectErrorStream}
754      * attribute has been set {@code true}, then the redirection set
755      * by this method has no effect.
756      *
757      * @param  destination the new standard error destination
758      * @return this process builder
759      * @throws IllegalArgumentException
760      *         if the redirect does not correspond to a valid
761      *         destination of data, that is, has type
762      *         {@link Redirect.Type#READ READ}
763      * @since  1.7
764      */
765     public ProcessBuilder redirectError(Redirect destination) {
766         if (destination.type() == Redirect.Type.READ)
767             throw new IllegalArgumentException(
768                 "Redirect invalid for writing: " + destination);
769         redirects()[2] = destination;
770         return this;
771     }
772 
773     /**
774      * Sets this process builder's standard input source to a file.
775      *
776      * <p>This is a convenience method.  An invocation of the form
777      * {@code redirectInput(file)}
778      * behaves in exactly the same way as the invocation
779      * {@link #redirectInput(Redirect) redirectInput}
780      * {@code (Redirect.from(file))}.
781      *
782      * @param  file the new standard input source
783      * @return this process builder
784      * @since  1.7
785      */
786     public ProcessBuilder redirectInput(File file) {
787         return redirectInput(Redirect.from(file));
788     }
789 
790     /**
791      * Sets this process builder's standard output destination to a file.
792      *
793      * <p>This is a convenience method.  An invocation of the form
794      * {@code redirectOutput(file)}
795      * behaves in exactly the same way as the invocation
796      * {@link #redirectOutput(Redirect) redirectOutput}
797      * {@code (Redirect.to(file))}.
798      *
799      * @param  file the new standard output destination
800      * @return this process builder
801      * @since  1.7
802      */
803     public ProcessBuilder redirectOutput(File file) {
804         return redirectOutput(Redirect.to(file));
805     }
806 
807     /**
808      * Sets this process builder's standard error destination to a file.
809      *
810      * <p>This is a convenience method.  An invocation of the form
811      * {@code redirectError(file)}
812      * behaves in exactly the same way as the invocation
813      * {@link #redirectError(Redirect) redirectError}
814      * {@code (Redirect.to(file))}.
815      *
816      * @param  file the new standard error destination
817      * @return this process builder
818      * @since  1.7
819      */
820     public ProcessBuilder redirectError(File file) {
821         return redirectError(Redirect.to(file));
822     }
823 
824     /**
825      * Returns this process builder's standard input source.
826      *
827      * Subprocesses subsequently started by this object's {@link #start()}
828      * method obtain their standard input from this source.
829      * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
830      *
831      * @return this process builder's standard input source
832      * @since  1.7
833      */
834     public Redirect redirectInput() {
835         return (redirects == null) ? Redirect.PIPE : redirects[0];
836     }
837 
838     /**
839      * Returns this process builder's standard output destination.
840      *
841      * Subprocesses subsequently started by this object's {@link #start()}
842      * method redirect their standard output to this destination.
843      * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
844      *
845      * @return this process builder's standard output destination
846      * @since  1.7
847      */
848     public Redirect redirectOutput() {
849         return (redirects == null) ? Redirect.PIPE : redirects[1];
850     }
851 
852     /**
853      * Returns this process builder's standard error destination.
854      *
855      * Subprocesses subsequently started by this object's {@link #start()}
856      * method redirect their standard error to this destination.
857      * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
858      *
859      * @return this process builder's standard error destination
860      * @since  1.7
861      */
862     public Redirect redirectError() {
863         return (redirects == null) ? Redirect.PIPE : redirects[2];
864     }
865 
866     /**
867      * Sets the source and destination for subprocess standard I/O
868      * to be the same as those of the current Java process.
869      *
870      * <p>This is a convenience method.  An invocation of the form
871      *  <pre> {@code
872      * pb.inheritIO()
873      * }</pre>
874      * behaves in exactly the same way as the invocation
875      *  <pre> {@code
876      * pb.redirectInput(Redirect.INHERIT)
877      *   .redirectOutput(Redirect.INHERIT)
878      *   .redirectError(Redirect.INHERIT)
879      * }</pre>
880      *
881      * This gives behavior equivalent to most operating system
882      * command interpreters, or the standard C library function
883      * {@code system()}.
884      *
885      * @return this process builder
886      * @since  1.7
887      */
888     public ProcessBuilder inheritIO() {
889         Arrays.fill(redirects(), Redirect.INHERIT);
890         return this;
891     }
892 
893     /**
894      * Tells whether this process builder merges standard error and
895      * standard output.
896      *
897      * <p>If this property is {@code true}, then any error output
898      * generated by subprocesses subsequently started by this object's
899      * {@link #start()} method will be merged with the standard
900      * output, so that both can be read using the
901      * {@link Process#getInputStream()} method.  This makes it easier
902      * to correlate error messages with the corresponding output.
903      * The initial value is {@code false}.
904      *
905      * @return this process builder's {@code redirectErrorStream} property
906      */
907     public boolean redirectErrorStream() {
908         return redirectErrorStream;
909     }
910 
911     /**
912      * Sets this process builder's {@code redirectErrorStream} property.
913      *
914      * <p>If this property is {@code true}, then any error output
915      * generated by subprocesses subsequently started by this object's
916      * {@link #start()} method will be merged with the standard
917      * output, so that both can be read using the
918      * {@link Process#getInputStream()} method.  This makes it easier
919      * to correlate error messages with the corresponding output.
920      * The initial value is {@code false}.
921      *
922      * @param  redirectErrorStream the new property value
923      * @return this process builder
924      */
925     public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) {
926         this.redirectErrorStream = redirectErrorStream;
927         return this;
928     }
929 
930     /**
931      * Starts a new process using the attributes of this process builder.
932      *
933      * <p>The new process will
934      * invoke the command and arguments given by {@link #command()},
935      * in a working directory as given by {@link #directory()},
936      * with a process environment as given by {@link #environment()}.
937      *
938      * <p>This method checks that the command is a valid operating
939      * system command.  Which commands are valid is system-dependent,
940      * but at the very least the command must be a non-empty list of
941      * non-null strings.
942      *
943      * <p>A minimal set of system dependent environment variables may
944      * be required to start a process on some operating systems.
945      * As a result, the subprocess may inherit additional environment variable
946      * settings beyond those in the process builder's {@link #environment()}.
947      *
948      * <p>If there is a security manager, its
949      * {@link SecurityManager#checkExec checkExec}
950      * method is called with the first component of this object's
951      * {@code command} array as its argument. This may result in
952      * a {@link SecurityException} being thrown.
953      *
954      * <p>Starting an operating system process is highly system-dependent.
955      * Among the many things that can go wrong are:
956      * <ul>
957      * <li>The operating system program file was not found.
958      * <li>Access to the program file was denied.
959      * <li>The working directory does not exist.
960      * </ul>
961      *
962      * <p>In such cases an exception will be thrown.  The exact nature
963      * of the exception is system-dependent, but it will always be a
964      * subclass of {@link IOException}.
965      *
966      * <p>Subsequent modifications to this process builder will not
967      * affect the returned {@link Process}.
968      *
969      * @return a new {@link Process} object for managing the subprocess
970      *
971      * @throws NullPointerException
972      *         if an element of the command list is null
973      *
974      * @throws IndexOutOfBoundsException
975      *         if the command is an empty list (has size {@code 0})
976      *
977      * @throws SecurityException
978      *         if a security manager exists and
979      *         <ul>
980      *
981      *         <li>its
982      *         {@link SecurityManager#checkExec checkExec}
983      *         method doesn't allow creation of the subprocess, or
984      *
985      *         <li>the standard input to the subprocess was
986      *         {@linkplain #redirectInput redirected from a file}
987      *         and the security manager's
988      *         {@link SecurityManager#checkRead checkRead} method
989      *         denies read access to the file, or
990      *
991      *         <li>the standard output or standard error of the
992      *         subprocess was
993      *         {@linkplain #redirectOutput redirected to a file}
994      *         and the security manager's
995      *         {@link SecurityManager#checkWrite checkWrite} method
996      *         denies write access to the file
997      *
998      *         </ul>
999      *
1000      * @throws IOException if an I/O error occurs
1001      *
1002      * @see Runtime#exec(String[], String[], java.io.File)
1003      */
1004     public Process start() throws IOException {
1005         // Must convert to array first -- a malicious user-supplied
1006         // list might try to circumvent the security check.
1007         String[] cmdarray = command.toArray(new String[command.size()]);
1008         cmdarray = cmdarray.clone();
1009 
1010         for (String arg : cmdarray)
1011             if (arg == null)
1012                 throw new NullPointerException();
1013         // Throws IndexOutOfBoundsException if command is empty
1014         String prog = cmdarray[0];
1015 
1016         SecurityManager security = System.getSecurityManager();
1017         if (security != null)
1018             security.checkExec(prog);
1019 
1020         String dir = directory == null ? null : directory.toString();
1021 
1022         try {
1023             return ProcessImpl.start(cmdarray,
1024                                      environment,
1025                                      dir,
1026                                      redirects,
1027                                      redirectErrorStream);
1028         } catch (IOException | IllegalArgumentException e) {
1029             String exceptionInfo = ": " + e.getMessage();
1030             Throwable cause = e;
1031             if ((e instanceof IOException) && security != null) {
1032                 // Can not disclose the fail reason for read-protected files.
1033                 try {
1034                     security.checkRead(prog);
1035                 } catch (SecurityException se) {
1036                     exceptionInfo = "";
1037                     cause = se;
1038                 }
1039             }
1040             // It's much easier for us to create a high-quality error
1041             // message than the low-level C code which found the problem.
1042             throw new IOException(
1043                 "Cannot run program \"" + prog + "\""
1044                 + (dir == null ? "" : " (in directory \"" + dir + "\")")
1045                 + exceptionInfo,
1046                 cause);
1047         }
1048     }
1049 }