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