1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.gridsystems.utils;
18
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.util.Enumeration;
25 import java.util.Formatter;
26 import java.util.HashSet;
27 import java.util.Map;
28 import java.util.Properties;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33
34
35
36
37
38
39
40
41 public final class NativeShell {
42
43
44
45
46 private static final Log LOG = LogFactory.getLog(NativeShell.class);
47
48
49
50
51 private static final int BUF_SIZE = 4096;
52
53
54
55
56 private static final FileProperties ALIAS;
57
58 static {
59 Properties defaults = new Properties();
60 InputStream is = null;
61 try {
62 ClassLoader cl = Thread.currentThread().getContextClassLoader();
63 is = cl.getResourceAsStream("native-commands.properties");
64 defaults.load(is);
65 } catch (Exception e) {
66 LOG.error("Could not load native-commands defaults", e);
67 } finally {
68 FileUtils.close(is);
69 }
70
71 File f = new File("native-commands.properties");
72 ALIAS = new FileProperties(f, defaults);
73 }
74
75
76
77
78
79
80 public static void setConfigFile(File f) {
81 ALIAS.setFile(f);
82 }
83
84
85
86
87 private ProcessBuilder builder = new ProcessBuilder();
88
89
90
91
92 private OutputStream stdOut;
93
94
95
96
97 private OutputStream stdErr;
98
99
100
101
102 private boolean closeStdOut;
103
104
105
106
107 private boolean closeStdErr;
108
109
110
111
112 public NativeShell() {
113 }
114
115
116
117
118
119
120
121
122 public static String alias(String cmd, Object... args) {
123 String osName = SystemUtils.getOsName();
124 return doAlias(osName, cmd, args);
125 }
126
127
128
129
130
131
132
133
134
135 protected static String doAlias(String osName, String cmd, Object... args) {
136 String osPrefix = SystemUtils.getSimpleOsName(osName);
137 String osVersion = System.getProperty("os.version");
138
139 String alias = ALIAS.getProperty(cmd + "_" + osPrefix + "_" + osVersion);
140 if (alias == null) {
141 alias = ALIAS.getProperty(cmd + "_" + osPrefix);
142 if (alias == null) {
143 alias = ALIAS.getProperty(cmd, "#null");
144 }
145 }
146
147 if ("#null".equals(alias)) {
148 return null;
149 } else if (args.length == 0) {
150 return alias;
151 } else {
152 Formatter f = new Formatter();
153 return f.format(alias, args).toString();
154 }
155 }
156
157
158
159
160
161
162
163
164
165 public static String[] getAllCommands() {
166 HashSet<String> commands = new HashSet<String>();
167 for (Enumeration< ? > names = ALIAS.propertyNames(); names.hasMoreElements();) {
168 String name = names.nextElement().toString();
169 int pos = name.indexOf('_');
170 String cmd = (pos == -1) ? name : name.substring(0, pos);
171 commands.add(cmd);
172 }
173
174 return commands.toArray(new String[commands.size()]);
175 }
176
177
178
179
180
181
182 public static String[] getAvailableCommands() {
183 String[] all = getAllCommands();
184 HashSet<String> available = new HashSet<String>();
185 for (String cmd : all) {
186 String alias = alias(cmd);
187 if (alias != null) {
188 available.add(cmd);
189 }
190 }
191
192 return available.toArray(new String[available.size()]);
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206 public static String[] shell(String cmd, Object... args) {
207 String osName = SystemUtils.getOsName();
208 return doShell(osName, cmd, args);
209 }
210
211
212
213
214
215
216
217
218
219
220
221
222
223 protected static String[] doShell(String osName, String cmd, Object... args) {
224 String alias = alias(osName, cmd, args);
225 String shell = alias(osName, "shell");
226 String shopts = alias(osName, "shopts");
227
228 if (alias == null || shell == null) {
229 return null;
230 } else if (shopts == null) {
231 return new String[] { shell, alias };
232 } else {
233 return new String[] { shell, shopts, alias };
234 }
235 }
236
237
238
239
240
241
242 public Map<String, String> getEnv() {
243 return this.builder.environment();
244 }
245
246
247
248
249
250
251 public void setDirectory(File dir) {
252 this.builder.directory(dir);
253 }
254
255
256
257
258
259
260 public File getDirectory() {
261 return this.builder.directory();
262 }
263
264
265
266
267
268
269
270 public void setStdOut(File f) throws IOException {
271 if (this.stdOut != null && this.closeStdOut) {
272 FileUtils.close(this.stdOut);
273 }
274
275 if (f == null) {
276 this.stdOut = null;
277 this.closeStdOut = false;
278 } else {
279 File parent = f.getParentFile();
280 if (parent != null) {
281 parent.mkdirs();
282 }
283
284 this.stdOut = new FileOutputStream(f);
285 this.closeStdOut = true;
286 }
287 }
288
289
290
291
292
293
294 public void setStdOut(OutputStream os) {
295 if (this.stdOut != null && this.closeStdOut) {
296 FileUtils.close(this.stdOut);
297 }
298
299 this.stdOut = os;
300 this.closeStdOut = false;
301 }
302
303
304
305
306
307
308
309 public void setStdErr(File f) throws IOException {
310 if (this.stdErr != null && this.closeStdErr) {
311 FileUtils.close(this.stdErr);
312 }
313
314 if (f == null) {
315 this.stdErr = null;
316 this.closeStdErr = false;
317 } else {
318 File parent = f.getParentFile();
319 if (parent != null) {
320 parent.mkdirs();
321 }
322
323 this.stdErr = new FileOutputStream(f);
324 this.closeStdErr = true;
325 }
326 }
327
328
329
330
331
332
333 public void setStdErr(OutputStream os) {
334 if (this.stdErr != null && this.closeStdErr) {
335 FileUtils.close(this.stdErr);
336 }
337
338 this.stdErr = os;
339 this.closeStdErr = false;
340 }
341
342
343
344
345
346
347
348
349
350
351 public Integer exec(String cmd, Object... args)
352 throws IOException, InterruptedException {
353 String osName = SystemUtils.getOsName();
354 return doExec(osName, cmd, args);
355 }
356
357
358
359
360
361
362
363
364
365
366
367 protected Integer doExec(String osName, String cmd, Object... args)
368 throws IOException, InterruptedException {
369 String[] cmdline = doShell(osName, cmd, args);
370 if (cmdline == null) {
371 return null;
372 } else {
373 builder.command(cmdline);
374 Process p = builder.start();
375
376 Pipe out;
377 Pipe err;
378 if (stdOut == null) {
379 out = null;
380 } else {
381 out = new Pipe(p.getInputStream(), stdOut, closeStdOut);
382 out.start();
383 }
384 if (stdErr == null) {
385 err = null;
386 } else {
387 err = new Pipe(p.getErrorStream(), stdErr, closeStdErr);
388 err.start();
389 }
390
391 try {
392 int exitCode = p.waitFor();
393 if (out.getError() != null) {
394 throw out.getError();
395 } else if (err.getError() != null) {
396 throw err.getError();
397 } else {
398 return exitCode;
399 }
400 } catch (InterruptedException e) {
401 p.destroy();
402 throw e;
403 }
404 }
405 }
406
407
408
409
410 private static class Pipe extends Thread {
411
412 private InputStream is;
413
414 private OutputStream os;
415
416 private IOException error;
417
418 private boolean closeOutput;
419
420
421
422
423
424
425
426
427 public Pipe(InputStream is, OutputStream os, boolean closeOutput) {
428 this.is = is;
429 this.os = os;
430 this.closeOutput = closeOutput;
431 }
432
433
434
435
436 @Override public void run() {
437 try {
438 byte[] buf = new byte[BUF_SIZE];
439 int count = is.read(buf);
440 while (count != -1) {
441 os.write(buf, 0, count);
442 count = is.read(buf);
443 }
444 os.flush();
445 } catch (IOException e) {
446 this.error = e;
447 } finally {
448 FileUtils.close(is);
449 if (closeOutput) {
450 FileUtils.close(os);
451 }
452 }
453 }
454
455
456
457
458
459
460 public IOException getError() {
461 return this.error;
462 }
463 }
464 }