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