Save This Page
Home » openjdk-7 » java » lang » [javadoc | source]
    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   }

Save This Page
Home » openjdk-7 » java » lang » [javadoc | source]