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.List;
23 import java.util.Map;
24
25 /**
26 * Creates operating system processes.
27 *
28 * @since 1.5
29 */
30 public final class ProcessBuilder {
31
32 private List<String> command;
33
34 private File directory;
35
36 private Map<String, String> environment;
37
38 private boolean redirectErrorStream;
39
40 /**
41 * Constructs a new {@code ProcessBuilder} instance with the specified
42 * operating system program and its arguments.
43 *
44 * @param command
45 * the requested operating system program and its arguments.
46 */
47 public ProcessBuilder(String... command) {
48 this(toList(command));
49 }
50
51 /**
52 * Constructs a new {@code ProcessBuilder} instance with the specified
53 * operating system program and its arguments. Note that the list passed to
54 * this constructor is not copied, so any subsequent updates to it are
55 * reflected in this instance's state.
56 *
57 * @param command
58 * the requested operating system program and its arguments.
59 * @throws NullPointerException
60 * if {@code command} is {@code null}.
61 */
62 public ProcessBuilder(List<String> command) {
63 super();
64 if (command == null) {
65 throw new NullPointerException();
66 }
67 this.command = command;
68 this.environment = new org.apache.harmony.luni.platform.Environment.EnvironmentMap(
69 System.getenv());
70 }
71
72 /**
73 * Returns this process builder's current program and arguments. Note that
74 * the returned list is not a copy and modifications to it will change the
75 * state of this instance.
76 *
77 * @return this process builder's program and arguments.
78 */
79 public List<String> command() {
80 return command;
81 }
82
83 /**
84 * Changes the program and arguments of this process builder.
85 *
86 * @param command
87 * the new operating system program and its arguments.
88 * @return this process builder instance.
89 */
90 public ProcessBuilder command(String... command) {
91 return command(toList(command));
92 }
93
94 /**
95 * Changes the program and arguments of this process builder. Note that the
96 * list passed to this method is not copied, so any subsequent updates to it
97 * are reflected in this instance's state.
98 *
99 * @param command
100 * the new operating system program and its arguments.
101 * @return this process builder instance.
102 * @throws NullPointerException
103 * if {@code command} is {@code null}.
104 */
105 public ProcessBuilder command(List<String> command) {
106 if (command == null) {
107 throw new NullPointerException();
108 }
109 this.command = command;
110 return this;
111 }
112
113 /**
114 * Returns the working directory of this process builder. If {@code null} is
115 * returned, then the working directory of the Java process is used when a
116 * process is started.
117 *
118 * @return the current working directory, may be {@code null}.
119 */
120 public File directory() {
121 return directory;
122 }
123
124 /**
125 * Changes the working directory of this process builder. If the specified
126 * directory is {@code null}, then the working directory of the Java
127 * process is used when a process is started.
128 *
129 * @param directory
130 * the new working directory for this process builder.
131 * @return this process builder instance.
132 */
133 public ProcessBuilder directory(File directory) {
134 this.directory = directory;
135 return this;
136 }
137
138 /**
139 * Returns this process builder's current environment. When a process
140 * builder instance is created, the environment is populated with a copy of
141 * the environment, as returned by {@link System#getenv()}. Note that the
142 * map returned by this method is not a copy and any changes made to it are
143 * reflected in this instance's state.
144 *
145 * @return the map containing this process builder's environment variables.
146 */
147 public Map<String, String> environment() {
148 return environment;
149 }
150
151 /**
152 * Indicates whether the standard error should be redirected to standard
153 * output. If redirected, the {@link Process#getErrorStream()} will always
154 * return end of stream and standard error is written to
155 * {@link Process#getInputStream()}.
156 *
157 * @return {@code true} if the standard error is redirected; {@code false}
158 * otherwise.
159 */
160 public boolean redirectErrorStream() {
161 return redirectErrorStream;
162 }
163
164 /**
165 * Changes the state of whether or not standard error is redirected to
166 * standard output.
167 *
168 * @param redirectErrorStream
169 * {@code true} to redirect standard error, {@code false}
170 * otherwise.
171 * @return this process builder instance.
172 */
173 public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) {
174 this.redirectErrorStream = redirectErrorStream;
175 return this;
176 }
177
178 /**
179 * Starts a new process based on the current state of this process builder.
180 *
181 * @return the new {@code Process} instance.
182 * @throws NullPointerException
183 * if any of the elements of {@link #command()} is {@code null}.
184 * @throws IndexOutOfBoundsException
185 * if {@link #command()} is empty.
186 * @throws SecurityException
187 * if {@link SecurityManager#checkExec(String)} doesn't allow
188 * process creation.
189 * @throws IOException
190 * if an I/O error happens.
191 */
192 public Process start() throws IOException {
193 if (command.isEmpty()) {
194 throw new IndexOutOfBoundsException();
195 }
196 String[] cmdArray = new String[command.size()];
197 for (int i = 0; i < cmdArray.length; i++) {
198 if ((cmdArray[i] = command.get(i)) == null) {
199 throw new NullPointerException();
200 }
201 }
202 String[] envArray = new String[environment.size()];
203 int i = 0;
204 for (Map.Entry<String, String> entry : environment.entrySet()) {
205 envArray[i++] = entry.getKey() + "=" + entry.getValue(); //$NON-NLS-1$
206 }
207 Process process = Runtime.getRuntime().exec(cmdArray, envArray,
208 directory);
209 // TODO implement support for redirectErrorStream
210 return process;
211 }
212
213 private static List<String> toList(String[] strings) {
214 ArrayList<String> arrayList = new ArrayList<String>(strings.length);
215 for (String string : strings) {
216 arrayList.add(string);
217 }
218 return arrayList;
219 }
220 }