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