1 package org.apache.helix.filestore;
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
105 _out = new InputReader(new BufferedInputStream(_process.getInputStream()));
106 _err = new InputReader(new BufferedInputStream(_process.getErrorStream()));
107
108 _out.start();
109 _err.start();
110 }
111
112
113
114
115 public Map<String, String> getEnvironment()
116 {
117 return _processBuilder.environment();
118 }
119
120
121
122
123 public File getWorkingDirectory()
124 {
125 return _processBuilder.directory();
126 }
127
128
129
130
131 public void setWorkingDirectory(File directory)
132 {
133 _processBuilder.directory(directory);
134 }
135
136
137
138
139 public boolean getRedirectErrorStream()
140 {
141 return _processBuilder.redirectErrorStream();
142 }
143
144
145
146
147 public void setRedirectErrorStream(boolean redirectErrorStream)
148 {
149 _processBuilder.redirectErrorStream(redirectErrorStream);
150 }
151
152 public byte[] getOutput() throws InterruptedException
153 {
154 waitFor();
155 return _out.getOutput();
156 }
157
158 public byte[] getError() throws InterruptedException
159 {
160 waitFor();
161 return _err.getOutput();
162 }
163
164
165
166
167
168
169
170
171
172 public String getStringOutput(String encoding) throws InterruptedException,
173 UnsupportedEncodingException
174 {
175 return new String(getOutput(), encoding);
176 }
177
178
179
180
181
182
183
184 public String getStringOutput() throws InterruptedException
185 {
186 try
187 {
188 return getStringOutput("UTF-8");
189 }
190 catch(UnsupportedEncodingException e)
191 {
192
193 throw new RuntimeException(e);
194 }
195 }
196
197
198
199
200
201
202
203
204
205 public String getStringError(String encoding) throws InterruptedException,
206 UnsupportedEncodingException
207 {
208 return new String(getError(), encoding);
209 }
210
211
212
213
214
215
216
217 public String getStringError() throws InterruptedException
218 {
219 try
220 {
221 return getStringError("UTF-8");
222 }
223 catch(UnsupportedEncodingException e)
224 {
225
226 throw new RuntimeException(e);
227 }
228 }
229
230
231
232
233
234
235
236
237
238 public int waitFor() throws InterruptedException
239 {
240 if(_process == null)
241 throw new IllegalStateException("you must call start first");
242
243 _out.join();
244 _err.join();
245 return _process.waitFor();
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259 public int waitFor(long timeout) throws InterruptedException, TimeoutException
260 {
261 if(_process == null)
262 throw new IllegalStateException("you must call start first");
263
264
265 _out.join(timeout);
266
267 if (timeout <= 0)
268 throw new TimeoutException("Wait timed out");
269 _err.join(timeout);
270
271 if (timeout <= 0)
272 throw new TimeoutException("Wait timed out");
273
274
275
276 return _process.waitFor();
277 }
278
279 public int exitValue()
280 {
281 if(_process == null)
282 throw new IllegalStateException("you must call start first");
283
284 return _process.exitValue();
285 }
286
287 public void destroy()
288 {
289 if(_process == null)
290 throw new IllegalStateException("you must call start first");
291
292 _process.destroy();
293 }
294
295
296
297
298
299
300
301 public static ExternalCommand create(String... commands)
302 {
303 ExternalCommand ec = new ExternalCommand(new ProcessBuilder(commands));
304 return ec;
305 }
306
307
308
309
310
311
312
313 public static ExternalCommand create(List<String> commands)
314 {
315 ExternalCommand ec = new ExternalCommand(new ProcessBuilder(commands));
316 return ec;
317 }
318
319
320
321
322
323
324
325 public static ExternalCommand start(String... commands) throws IOException
326 {
327 ExternalCommand ec = new ExternalCommand(new ProcessBuilder(commands));
328 ec.start();
329 return ec;
330 }
331
332
333
334
335
336
337
338
339
340 public static ExternalCommand execute(File workingDirectory,
341 String command,
342 String... args)
343 throws IOException, InterruptedException
344 {
345 try
346 {
347 return executeWithTimeout(workingDirectory, command, 0, args);
348 }
349 catch (TimeoutException e)
350 {
351
352 throw new IllegalStateException(MODULE + ".execute: Unexpected timeout occurred!");
353 }
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371 public static ExternalCommand executeWithTimeout(File workingDirectory,
372 String command,
373 long timeout,
374 String... args)
375 throws IOException, InterruptedException, TimeoutException
376 {
377 List<String> arguments = new ArrayList<String>(args.length + 1);
378
379 arguments.add(new File(workingDirectory, command).getAbsolutePath());
380 arguments.addAll(Arrays.asList(args));
381
382 ExternalCommand cmd = ExternalCommand.create(arguments);
383
384 cmd.setWorkingDirectory(workingDirectory);
385
386 cmd.setRedirectErrorStream(true);
387
388 cmd.start();
389
390
391 if (timeout <= 0)
392 cmd.waitFor();
393 else
394 cmd.waitFor(timeout);
395
396 if (LOG.isDebugEnabled())
397 LOG.debug(cmd.getStringOutput());
398
399 return cmd;
400 }
401 }