Home | History | Annotate | Download | only in lang
      1 /* Licensed to the Apache Software Foundation (ASF) under one or more
      2  * contributor license agreements.  See the NOTICE file distributed with
      3  * this work for additional information regarding copyright ownership.
      4  * The ASF licenses this file to You under the Apache License, Version 2.0
      5  * (the "License"); you may not use this file except in compliance with
      6  * the License.  You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package java.lang;
     18 
     19 import java.io.File;
     20 import java.io.IOException;
     21 import java.util.ArrayList;
     22 import java.util.Arrays;
     23 import java.util.Hashtable;
     24 import java.util.List;
     25 import java.util.Map;
     26 
     27 /**
     28  * Creates operating system processes. See {@link Process} for documentation and
     29  * example usage.
     30  */
     31 public final class ProcessBuilder {
     32 
     33     private List<String> command;
     34     private File directory;
     35     private Map<String, String> environment;
     36     private boolean redirectErrorStream;
     37 
     38     /**
     39      * Constructs a new {@code ProcessBuilder} instance with the specified
     40      * operating system program and its arguments.
     41      *
     42      * @param command
     43      *            the requested operating system program and its arguments.
     44      */
     45     public ProcessBuilder(String... command) {
     46         this(new ArrayList<String>(Arrays.asList(command)));
     47     }
     48 
     49     /**
     50      * Constructs a new {@code ProcessBuilder} instance with the specified
     51      * operating system program and its arguments. Note that the list passed to
     52      * this constructor is not copied, so any subsequent updates to it are
     53      * reflected in this instance's state.
     54      *
     55      * @param command
     56      *            the requested operating system program and its arguments.
     57      * @throws NullPointerException
     58      *             if {@code command} is {@code null}.
     59      */
     60     public ProcessBuilder(List<String> command) {
     61         if (command == null) {
     62             throw new NullPointerException();
     63         }
     64         this.command = command;
     65 
     66         // use a hashtable to prevent nulls from sneaking in
     67         this.environment = new Hashtable<String, String>(System.getenv());
     68     }
     69 
     70     /**
     71      * Returns this process builder's current program and arguments. Note that
     72      * the returned list is not a copy and modifications to it will change the
     73      * state of this instance.
     74      *
     75      * @return this process builder's program and arguments.
     76      */
     77     public List<String> command() {
     78         return command;
     79     }
     80 
     81     /**
     82      * Changes the program and arguments of this process builder.
     83      *
     84      * @param command
     85      *            the new operating system program and its arguments.
     86      * @return this process builder instance.
     87      */
     88     public ProcessBuilder command(String... command) {
     89         return command(new ArrayList<String>(Arrays.asList(command)));
     90     }
     91 
     92     /**
     93      * Changes the program and arguments of this process builder. Note that the
     94      * list passed to this method is not copied, so any subsequent updates to it
     95      * are reflected in this instance's state.
     96      *
     97      * @param command
     98      *            the new operating system program and its arguments.
     99      * @return this process builder instance.
    100      * @throws NullPointerException
    101      *             if {@code command} is {@code null}.
    102      */
    103     public ProcessBuilder command(List<String> command) {
    104         if (command == null) {
    105             throw new NullPointerException();
    106         }
    107         this.command = command;
    108         return this;
    109     }
    110 
    111     /**
    112      * Returns the working directory of this process builder. If {@code null} is
    113      * returned, then the working directory of the Java process is used when a
    114      * process is started.
    115      *
    116      * @return the current working directory, may be {@code null}.
    117      */
    118     public File directory() {
    119         return directory;
    120     }
    121 
    122     /**
    123      * Changes the working directory of this process builder. If the specified
    124      * directory is {@code null}, then the working directory of the Java
    125      * process is used when a process is started.
    126      *
    127      * @param directory
    128      *            the new working directory for this process builder.
    129      * @return this process builder instance.
    130      */
    131     public ProcessBuilder directory(File directory) {
    132         this.directory = directory;
    133         return this;
    134     }
    135 
    136     /**
    137      * Returns this process builder's current environment. When a process
    138      * builder instance is created, the environment is populated with a copy of
    139      * the environment, as returned by {@link System#getenv()}. Note that the
    140      * map returned by this method is not a copy and any changes made to it are
    141      * reflected in this instance's state.
    142      *
    143      * @return the map containing this process builder's environment variables.
    144      */
    145     public Map<String, String> environment() {
    146         return environment;
    147     }
    148 
    149     /**
    150      * Indicates whether the standard error should be redirected to standard
    151      * output. If redirected, the {@link Process#getErrorStream()} will always
    152      * return end of stream and standard error is written to
    153      * {@link Process#getInputStream()}.
    154      *
    155      * @return {@code true} if the standard error is redirected; {@code false}
    156      *         otherwise.
    157      */
    158     public boolean redirectErrorStream() {
    159         return redirectErrorStream;
    160     }
    161 
    162     /**
    163      * Changes the state of whether or not standard error is redirected to
    164      * standard output.
    165      *
    166      * @param redirectErrorStream
    167      *            {@code true} to redirect standard error, {@code false}
    168      *            otherwise.
    169      * @return this process builder instance.
    170      */
    171     public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) {
    172         this.redirectErrorStream = redirectErrorStream;
    173         return this;
    174     }
    175 
    176     /**
    177      * Starts a new process based on the current state of this process builder.
    178      *
    179      * @return the new {@code Process} instance.
    180      * @throws NullPointerException
    181      *             if any of the elements of {@link #command()} is {@code null}.
    182      * @throws IndexOutOfBoundsException
    183      *             if {@link #command()} is empty.
    184      * @throws IOException
    185      *             if an I/O error happens.
    186      */
    187     public Process start() throws IOException {
    188         // We push responsibility for argument checking into ProcessManager.
    189         String[] cmdArray = command.toArray(new String[command.size()]);
    190         String[] envArray = new String[environment.size()];
    191         int i = 0;
    192         for (Map.Entry<String, String> entry : environment.entrySet()) {
    193             envArray[i++] = entry.getKey() + "=" + entry.getValue();
    194         }
    195         return ProcessManager.getInstance().exec(cmdArray, envArray, directory, redirectErrorStream);
    196     }
    197 }
    198