• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       */
ProcessBuilder(List<String> command)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       */
ProcessBuilder(String... command)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       */
command(List<String> command)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       */
command(String... command)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       */
command()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       */
environment()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...)
environment(String[] 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       */
directory()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       */
directory(File directory)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();
NullInputStream()421          private NullInputStream() {}
read()422          public int read()      { return -1; }
available()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();
NullOutputStream()431          private NullOutputStream() {}
write(int b)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           */
type()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           */
file()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           */
append()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           */
from(final File file)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           */
to(final File file)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          for (int i = 1; i < cmdarray.length; i++) {
1023              if (cmdarray[i].indexOf('\u0000') >= 0) {
1024                  throw new IOException("invalid null character in command");
1025              }
1026          }
1027  
1028          try {
1029              return ProcessImpl.start(cmdarray,
1030                                       environment,
1031                                       dir,
1032                                       redirects,
1033                                       redirectErrorStream);
1034          } catch (IOException | IllegalArgumentException e) {
1035              String exceptionInfo = ": " + e.getMessage();
1036              Throwable cause = e;
1037              if ((e instanceof IOException) && security != null) {
1038                  // Can not disclose the fail reason for read-protected files.
1039                  try {
1040                      security.checkRead(prog);
1041                  } catch (SecurityException se) {
1042                      exceptionInfo = "";
1043                      cause = se;
1044                  }
1045              }
1046              // It's much easier for us to create a high-quality error
1047              // message than the low-level C code which found the problem.
1048              throw new IOException(
1049                  "Cannot run program \"" + prog + "\""
1050                  + (dir == null ? "" : " (in directory \"" + dir + "\")")
1051                  + exceptionInfo,
1052                  cause);
1053          }
1054      }
1055  }
1056