Source for java.lang.ProcessBuilder

   1: /* ProcessBuilder.java - Represent spawned system process
   2:    Copyright (C) 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.lang;
  40: 
  41: import java.io.File;
  42: import java.io.IOException;
  43: 
  44: import java.util.Arrays;
  45: import java.util.List;
  46: import java.util.Map;
  47: 
  48: /**
  49:  * <p>
  50:  * This class is used to construct new operating system processes.
  51:  * A <code>ProcessBuilder</code> instance basically represent a
  52:  * template for a new process.  Actual processes are generated from
  53:  * this template via use of the <code>start()</code> method, which
  54:  * may be invoked multiple times, with each invocation spawning a
  55:  * new process with the current attributes of the
  56:  * <code>ProcessBuilder</code> object.  Each spawned process is
  57:  * independent of the <code>ProcessBuilder</code> object, and is
  58:  * unaffected by changes in its attributes.
  59:  * </p>
  60:  * <p>
  61:  * The following attributes define a process:
  62:  * </p>
  63:  * <ul>
  64:  * <li>The <emphasis>working directory</emphasis>; the activities of a
  65:  * process begin with the current directory set to this.  By default,
  66:  * this is the working directory of the current process, as defined
  67:  * by the <code>user.dir</code> property.</li>
  68:  * <li>The <emphasis>command</emphasis> which invokes the process.  This
  69:  * usually consists of the name of the program binary followed by an
  70:  * arbitrary number of arguments.  For example, <code>find -type f</code>
  71:  * invokes the <code>find</code> binary with the arguments "-type" and "f".
  72:  * The command is provided a list, the elements of which are defined in a
  73:  * system dependent manner; the layout is affected by expected operating
  74:  * system conventions.  A common method is to split the command on each
  75:  * space within the string.  Thus, <code>find -type f</code> forms a
  76:  * three element list.  However, in some cases, the expectation is that
  77:  * this split is performed by the program itself; thus, the list consists
  78:  * of only two elements (the program name and its arguments).</li>
  79:  * <li>The <emphasis>environment map</emphasis>, which links environment
  80:  * variables to their corresponding values.  The initial contents of the map
  81:  * are the current environment values i.e. it contains the contents of the
  82:  * map returned by <code>System.getenv()</code>.</li>
  83:  * <li>The <emphasis>redirection flag</emphasis>, which specifies whether
  84:  * or not the contents of the error stream should be redirected to standard
  85:  * output.  By default, this is false, and there are two output streams, one
  86:  * for normal data ({@link Process#getOutputStream()}) and one for error data
  87:  * ({@link Process#getErrorStream()}).  When set to true, the two are merged,
  88:  * which simplifies the interleaving of the two streams.  Data is read using
  89:  * the stream returned by {@link Process#getOutputStream()}, and the
  90:  * stream returned by {@link Process#getErrorStream()} throws an immediate
  91:  * end-of-file exception.</li>
  92:  * </ul>
  93:  * <p>
  94:  * All checks on attribute validity are delayed until <code>start()</code>
  95:  * is called. <code>ProcessBuilder</code> objects are <strong>not
  96:  * synchronized</strong>; the user must provide external synchronization
  97:  * where multiple threads may interact with the same
  98:  * <code>ProcessBuilder</code> object.
  99:  * </p>
 100:  *
 101:  * @author Tom Tromey (tromey@redhat.com)
 102:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 103:  * @see Process
 104:  * @see System#getenv()
 105:  * @since 1.5
 106:  */
 107: public final class ProcessBuilder
 108: {
 109: 
 110:   /**
 111:    * The working directory of the process.
 112:    */
 113:   private File directory = new File(System.getProperty("user.dir"));
 114: 
 115:   /**
 116:    * The command line syntax for invoking the process.
 117:    */
 118:   private List<String> command;
 119: 
 120:   /**
 121:    * The mapping of environment variables to values.
 122:    */
 123:   private Map<String, String> environment =
 124:     new System.EnvironmentMap(System.getenv());
 125: 
 126:   /**
 127:    * A flag indicating whether to redirect the error stream to standard
 128:    * output.
 129:    */
 130:   private boolean redirect = false;
 131: 
 132:   /**
 133:    * Constructs a new <code>ProcessBuilder</code> with the specified
 134:    * command being used to invoke the process.  The list is used directly;
 135:    * external changes are reflected in the <code>ProcessBuilder</code>.
 136:    *
 137:    * @param command the name of the program followed by its arguments.
 138:    */
 139:   public ProcessBuilder(List<String> command)
 140:   {
 141:     this.command = command;
 142:   }
 143: 
 144:   /**
 145:    * Constructs a new <code>ProcessBuilder</code> with the specified
 146:    * command being used to invoke the process.  This constructor
 147:    * simplifies creating a new <code>ProcessBuilder</code> by
 148:    * converting the provided series of constructor arguments into a
 149:    * list of command-line arguments.
 150:    *
 151:    * @param command the name of the program followed by its arguments.
 152:    */
 153:   public ProcessBuilder(String... command)
 154:   {
 155:     this.command = Arrays.asList(command);
 156:   }
 157: 
 158:   /**
 159:    * Returns the current command line, used to invoke the process.
 160:    * The return value is simply a reference to the list of command
 161:    * line arguments used by the <code>ProcessBuilder</code> object;
 162:    * any changes made to it will be reflected in the operation of
 163:    * the <code>ProcessBuilder</code>.
 164:    *
 165:    * @return the list of command-line arguments.
 166:    */
 167:   public List<String> command()
 168:   {
 169:     return command;
 170:   }
 171: 
 172:   /**
 173:    * Sets the command-line arguments to those specified.  The list is
 174:    * used directly; external changes are reflected in the
 175:    * <code>ProcessBuilder</code>.
 176:    *
 177:    * @param command the name of the program followed by its arguments.
 178:    * @return a reference to this process builder.
 179:    */
 180:   public ProcessBuilder command(List<String> command)
 181:   {
 182:     this.command = command;
 183:     return this;
 184:   }
 185: 
 186:   /**
 187:    * Sets the command-line arguments to those specified.
 188:    * This simplifies modifying the arguments by converting
 189:    * the provided series of constructor arguments into a
 190:    * list of command-line arguments.
 191:    *
 192:    * @param command the name of the program followed by its arguments.
 193:    * @return a reference to this process builder.
 194:    */
 195:   public ProcessBuilder command(String... command)
 196:   {
 197:     this.command = Arrays.asList(command);
 198:     return this;
 199:   }
 200: 
 201:   /**
 202:    * Returns the working directory of the process.  The
 203:    * returned value may be <code>null</code>; this
 204:    * indicates that the default behaviour of using the
 205:    * working directory of the current process should
 206:    * be adopted.
 207:    *
 208:    * @return the working directory.
 209:    */
 210:   public File directory()
 211:   {
 212:     return directory;
 213:   }
 214: 
 215:   /**
 216:    * Sets the working directory to that specified.
 217:    * The supplied argument may be <code>null</code>,
 218:    * which indicates the default value should be used.
 219:    * The default is the working directory of the current
 220:    * process.
 221:    *
 222:    * @param directory the new working directory.
 223:    * @return a reference to this process builder.
 224:    */
 225:   public ProcessBuilder directory(File directory)
 226:   {
 227:     this.directory = directory;
 228:     return this;
 229:   }
 230: 
 231:   /**
 232:    * <p>
 233:    * Returns the system environment variables of the process.
 234:    * If the underlying system does not support environment variables,
 235:    * an empty map is returned.
 236:    * </p>
 237:    * <p>
 238:    * The returned map does not accept queries using
 239:    * null keys or values, or those of a type other than
 240:    * <code>String</code>.  Attempts to pass in a null value will
 241:    * throw a <code>NullPointerException</code>.  Types other than
 242:    * <code>String</code> throw a <code>ClassCastException</code>.
 243:    * </p>
 244:    * <p>
 245:    * As the returned map is generated using data from the underlying
 246:    * platform, it may not comply with the <code>equals()</code>
 247:    * and <code>hashCode()</code> contracts.  It is also likely that
 248:    * the keys of this map will be case-sensitive.
 249:    * </p>
 250:    * <p>
 251:    * Modification of the map is reliant on the underlying platform;
 252:    * some may not allow any changes to the environment variables or
 253:    * may prevent certain values being used.  Attempts to do so will
 254:    * throw an <code>UnsupportedOperationException</code> or
 255:    * <code>IllegalArgumentException</code>, respectively.
 256:    * </p>
 257:    * <p>
 258:    * Use of this method may require a security check for the
 259:    * RuntimePermission "getenv.*".
 260:    * </p>
 261:    *
 262:    * @return a map of the system environment variables for the process.
 263:    * @throws SecurityException if the checkPermission method of
 264:    *         an installed security manager prevents access to
 265:    *         the system environment variables.
 266:    * @since 1.5
 267:    */
 268:   public Map<String, String> environment()
 269:   {
 270:     return environment;
 271:   }
 272: 
 273:   /**
 274:    * Returns true if the output stream and error stream of the
 275:    * process will be merged to form one composite stream.  The
 276:    * default return value is <code>false</code>.
 277:    *
 278:    * @return true if the output stream and error stream are to
 279:    *         be merged.
 280:    */
 281:   public boolean redirectErrorStream()
 282:   {
 283:     return redirect;
 284:   }
 285: 
 286:   /**
 287:    * Sets the error stream redirection flag.  If set, the output
 288:    * and error streams are merged to form one composite stream.
 289:    *
 290:    * @param redirect the new value of the redirection flag.
 291:    * @return a reference to this process builder.
 292:    */
 293:   public ProcessBuilder redirectErrorStream(boolean redirect)
 294:   {
 295:     this.redirect = redirect;
 296:     return this;
 297:   }
 298: 
 299:   /**
 300:    * <p>
 301:    * Starts execution of a new process, based on the attributes of
 302:    * this <code>ProcessBuilder</code> object.  This is the point
 303:    * at which the command-line arguments are checked.  The list
 304:    * must be non-empty and contain only non-null string objects.
 305:    * The other attributes have default values which are used in
 306:    * cases where their values are not explicitly specified.
 307:    * </p>
 308:    * <p>
 309:    * If a security manager is in place, then the
 310:    * {@link SecurityManager#checkExec()} method is called to
 311:    * ensure that permission is given to execute the process.
 312:    * </p>
 313:    * <p>
 314:    * The execution of the process is system-dependent.  Various
 315:    * exceptions may result, due to problems at the operating system
 316:    * level.  These are all returned as a form of {@link IOException}.
 317:    * </p>
 318:    *
 319:    * @return a <code>Process</code> object, representing the spawned
 320:    *         subprocess.
 321:    * @throws IOException if a problem occurs with executing the process
 322:    *                     at the operating system level.
 323:    * @throws IndexOutOfBoundsException if the command to execute is
 324:    *                                   actually an empty list.
 325:    * @throws NullPointerException if the command to execute is null
 326:    *                              or the list contains null elements.
 327:    * @throws SecurityException if a security manager exists and prevents
 328:    *                           execution of the subprocess.
 329:    */
 330:   public Process start() throws IOException
 331:   {
 332:     SecurityManager sm = SecurityManager.current; // Be thread-safe!
 333:     if (sm != null)
 334:       sm.checkExec(command.get(0));
 335:     return VMProcess.exec(command, environment, directory, redirect);
 336:   }
 337: }