1 package org.apache.helix;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.UnsupportedEncodingException;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.concurrent.TimeoutException;
33
34 import org.apache.log4j.Logger;
35
36 public class ExternalCommand
37 {
38 public static final String MODULE = ExternalCommand.class.getName();
39 public static final Logger LOG = Logger.getLogger(MODULE);
40
41 private final ProcessBuilder _processBuilder;
42
43 private Process _process;
44 private InputReader _out;
45 private InputReader _err;
46
47 private static class InputReader extends Thread
48 {
49 private static final int BUFFER_SIZE = 2048;
50
51 private final InputStream _in;
52 private final ByteArrayOutputStream _out;
53 private boolean _running = false;
54
55 InputReader(InputStream in)
56 {
57 _in = in;
58 _out = new ByteArrayOutputStream();
59 }
60
61 @Override
62 public void run()
63 {
64 _running = true;
65
66 byte[] buf = new byte[BUFFER_SIZE];
67 int n = 0;
68 try
69 {
70 while((n = _in.read(buf)) != -1)
71 _out.write(buf, 0, n);
72 }
73 catch(IOException e)
74 {
75 LOG.error("error while reading external command", e);
76 }
77
78 _running = false;
79 }
80
81 public byte[] getOutput()
82 {
83 if(_running)
84 throw new IllegalStateException("wait for process to be completed");
85
86 return _out.toByteArray();
87 }
88 }
89
90
91 public ExternalCommand(ProcessBuilder processBuilder)
92 {
93 _processBuilder = processBuilder;
94 }
95
96
97
98
99
100
101 public void start() throws IOException
102 {
103 _process = _processBuilder.start();
104 _out = new InputReader(new BufferedInputStream(_process.getInputStream()));
105 _err = new InputReader(new BufferedInputStream(_process.getErrorStream()));
106
107 _out.start();
108 _err.start();
109 }
110
111
112
113
114 public Map<String, String> getEnvironment()
115 {
116 return _processBuilder.environment();
117 }
118
119
120
121
122 public File getWorkingDirectory()
123 {
124 return _processBuilder.directory();
125 }
126
127
128
129
130 public void setWorkingDirectory(File directory)
131 {
132 _processBuilder.directory(directory);
133 }
134
135
136
137
138 public boolean getRedirectErrorStream()
139 {
140 return _processBuilder.redirectErrorStream();
141 }
142
143
144
145
146 public void setRedirectErrorStream(boolean redirectErrorStream)
147 {
148 _processBuilder.redirectErrorStream(redirectErrorStream);
149 }
150
151 public byte[] getOutput() throws InterruptedException
152 {
153 waitFor();
154 return _out.getOutput();
155 }
156
157 public byte[] getError() throws InterruptedException
158 {
159 waitFor();
160 return _err.getOutput();
161 }
162
163
164
165
166
167
168
169
170
171 public String getStringOutput(String encoding) throws InterruptedException,
172 UnsupportedEncodingException
173 {
174 return new String(getOutput(), encoding);
175 }
176
177
178
179
180
181
182
183 public String getStringOutput() throws InterruptedException
184 {
185 try
186 {
187 return getStringOutput("UTF-8");
188 }
189 catch(UnsupportedEncodingException e)
190 {
191
192 throw new RuntimeException(e);
193 }
194 }
195
196
197
198
199
200
201
202
203
204 public String getStringError(String encoding) throws InterruptedException,
205 UnsupportedEncodingException
206 {
207 return new String(getError(), encoding);
208 }
209
210
211
212
213
214
215
216 public String getStringError() throws InterruptedException
217 {
218 try
219 {
220 return getStringError("UTF-8");
221 }
222 catch(UnsupportedEncodingException e)
223 {
224
225 throw new RuntimeException(e);
226 }
227 }
228
229
230
231
232
233
234
235
236
237 public int waitFor() throws InterruptedException
238 {
239 if(_process == null)
240 throw new IllegalStateException("you must call start first");
241
242 _out.join();
243 _err.join();
244 return _process.waitFor();
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258 public int waitFor(long timeout) throws InterruptedException, TimeoutException
259 {
260 if(_process == null)
261 throw new IllegalStateException("you must call start first");
262
263
264 _out.join(timeout);
265
266 if (timeout <= 0)
267 throw new TimeoutException("Wait timed out");
268 _err.join(timeout);
269
270 if (timeout <= 0)
271 throw new TimeoutException("Wait timed out");
272
273
274
275 return _process.waitFor();
276 }
277
278 public int exitValue()
279 {
280 if(_process == null)
281 throw new IllegalStateException("you must call start first");
282
283 return _process.exitValue();
284 }
285
286 public void destroy()
287 {
288 if(_process == null)
289 throw new IllegalStateException("you must call start first");
290
291 _process.destroy();
292 }
293
294
295
296
297
298
299
300 public static ExternalCommand create(String... commands)
301 {
302 ExternalCommand ec = new ExternalCommand(new ProcessBuilder(commands));
303 return ec;
304 }
305
306
307
308
309
310
311
312 public static ExternalCommand create(List<String> commands)
313 {
314 ExternalCommand ec = new ExternalCommand(new ProcessBuilder(commands));
315 return ec;
316 }
317
318
319
320
321
322
323
324 public static ExternalCommand start(String... commands) throws IOException
325 {
326 ExternalCommand ec = new ExternalCommand(new ProcessBuilder(commands));
327 ec.start();
328 return ec;
329 }
330
331
332
333
334
335
336
337
338
339 public static ExternalCommand execute(File workingDirectory,
340 String command,
341 String... args)
342 throws IOException, InterruptedException
343 {
344 try
345 {
346 return executeWithTimeout(workingDirectory, command, 0, args);
347 }
348 catch (TimeoutException e)
349 {
350
351 throw new IllegalStateException(MODULE + ".execute: Unexpected timeout occurred!");
352 }
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370 public static ExternalCommand executeWithTimeout(File workingDirectory,
371 String command,
372 long timeout,
373 String... args)
374 throws IOException, InterruptedException, TimeoutException
375 {
376 List<String> arguments = new ArrayList<String>(args.length + 1);
377
378 arguments.add(new File(workingDirectory, command).getAbsolutePath());
379 arguments.addAll(Arrays.asList(args));
380
381 ExternalCommand cmd = ExternalCommand.create(arguments);
382
383 cmd.setWorkingDirectory(workingDirectory);
384
385 cmd.setRedirectErrorStream(true);
386
387 cmd.start();
388
389
390 if (timeout <= 0)
391 cmd.waitFor();
392 else
393 cmd.waitFor(timeout);
394
395 if (LOG.isDebugEnabled())
396 LOG.debug(cmd.getStringOutput());
397
398 return cmd;
399 }
400 }