KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > externalprocess > CommandLauncher


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util.externalprocess;
11
12 import java.io.IOException JavaDoc;
13 import java.io.InputStream JavaDoc;
14 import java.io.OutputStream JavaDoc;
15 import java.io.PipedInputStream JavaDoc;
16 import java.io.PipedOutputStream JavaDoc;
17
18 import org.mmbase.util.logging.Logger;
19 import org.mmbase.util.logging.Logging;
20
21 /**
22  * The command launcher provides a way to comunicate with a external process
23  *
24  * @author Nico Klasens (Finalist IT Group)
25  * @version $Id:
26  * @since MMBase-1.6
27  */

28 public class CommandLauncher {
29
30     /** MMBase logging system */
31     private static final Logger log = Logging.getLoggerInstance(CommandLauncher.class);
32
33     /**
34      * Default buffer size.
35      */

36     private static final int BUFFER_SIZE = 1024;
37
38     /**
39      * The number of milliseconds to pause between polling.
40      */

41     protected static final long DELAY = 50L;
42
43     /**
44      * Counts how many comands are launched
45      * Also used for () identification
46      */

47     protected static int counter = 0;
48
49     /**
50      * The process object representing the external process
51      */

52     protected Process JavaDoc process;
53
54     /**
55      * Command and arguments
56      */

57     protected String JavaDoc[] commandArgs;
58
59     /**
60      * The internal name of the external process
61      */

62     protected String JavaDoc name = "";
63
64     /**
65      * System line separator
66      */

67     private String JavaDoc lineSeparator;
68
69     /**
70      * Creates a new launcher
71      * Fills in stderr and stdout output to the given streams.
72      * Streams can be set to <code>null</code>, if output not required
73      *
74      * @param name internal name of the external process
75      */

76     public CommandLauncher(String JavaDoc name) {
77         process = null;
78         this.name = counter++ +" " + name;
79         lineSeparator = System.getProperty("line.separator", "\n");
80     }
81
82     /**
83      * get CommandArgs.
84      * @return String[]
85      */

86     public String JavaDoc[] getCommandArgs() {
87         return commandArgs;
88     }
89
90     /**
91      * Constructs a command array that will be passed to the process
92      *
93      * @param command path of comand
94      * @param commandArgs arguments after the command
95      */

96     protected String JavaDoc[] constructCommandArray(String JavaDoc command, String JavaDoc[] commandArgs) {
97
98         String JavaDoc[] args = new String JavaDoc[1 + commandArgs.length];
99         args[0] = command;
100         System.arraycopy(commandArgs, 0, args, 1, commandArgs.length);
101         return args;
102     }
103
104     /**
105      * Execute a command
106      *
107      * @param command command
108      * @throws IOException if an I/O error occurs
109      */

110     public void execute(String JavaDoc command) throws ProcessException {
111
112         if (log.isDebugEnabled()) {
113             printCommandLine(new String JavaDoc[] { command });
114         }
115         try {
116             process = ProcessFactory.getFactory().exec(command);
117         } catch (IOException JavaDoc e) {
118             throw new ProcessException("An I/O error occured: " + e.getMessage());
119         } catch (SecurityException JavaDoc e) {
120             throw new ProcessException(
121                 "A security manager exists and its checkExec method " + "doesn't allow creation of a subprocess.");
122         } catch (NullPointerException JavaDoc e) {
123             throw new ProcessException("Command is null.");
124         } catch (IllegalArgumentException JavaDoc e) {
125             throw new ProcessException("Command is empty.");
126         }
127     }
128
129     /**
130      * Execute a command
131      *
132      * @param commandArgs command and arguments
133     * @throws IOException if an I/O error occurs
134      */

135     public void execute(String JavaDoc[] commandArgs) throws ProcessException {
136         if (log.isDebugEnabled()) {
137             printCommandLine(commandArgs);
138         }
139         try {
140             process = ProcessFactory.getFactory().exec(commandArgs);
141         } catch (IOException JavaDoc e) {
142             throw new ProcessException("An I/O error occured: " + e.getMessage());
143         } catch (SecurityException JavaDoc e) {
144             throw new ProcessException(
145                 "A security manager exists and its checkExec method " + "doesn't allow creation of a subprocess.");
146         } catch (NullPointerException JavaDoc e) {
147             throw new ProcessException("Command is null.");
148         } catch (IllegalArgumentException JavaDoc e) {
149             throw new ProcessException("Command is empty.");
150         }
151     }
152
153     /**
154      * Execute a command
155      *
156      * @param commandPath path of comand
157      * @param args arguments after the command
158      * @throws IOException if an I/O error occurs
159      */

160     public void execute(String JavaDoc commandPath, String JavaDoc[] args) throws ProcessException {
161         commandArgs = constructCommandArray(commandPath, args);
162         execute(commandArgs);
163     }
164
165     /**
166      * Execute a command
167      *
168      * @param commandArgs command and arguments
169      * @param env environment name value pairs
170      * @throws IOException if an I/O error occurs
171      */

172     public void execute(String JavaDoc[] commandArgs, String JavaDoc[] env) throws ProcessException {
173
174         if (log.isDebugEnabled()) {
175             printCommandLine(commandArgs);
176         }
177         try {
178             process = ProcessFactory.getFactory().exec(commandArgs, env);
179         } catch (IOException JavaDoc e) {
180             throw new ProcessException("An I/O error occured: " + e.getMessage());
181         } catch (SecurityException JavaDoc e) {
182             throw new ProcessException(
183                 "A security manager exists and its checkExec method " + "doesn't allow creation of a subprocess.");
184         } catch (NullPointerException JavaDoc e) {
185             throw new ProcessException("Command is null.");
186         } catch (IllegalArgumentException JavaDoc e) {
187             throw new ProcessException("Command is empty.");
188         }
189     }
190
191     /**
192      * Execute a command
193      *
194      * @param commandPath path of comand
195      * @param args arguments after the comand
196      * @param env environment name value pairs
197      * @throws IOException if an I/O error occurs
198      */

199     public void execute(String JavaDoc commandPath, String JavaDoc[] args, String JavaDoc[] env) throws ProcessException {
200
201         commandArgs = constructCommandArray(commandPath, args);
202         execute(commandArgs, env);
203     }
204
205     /**
206      * Execute a command
207      *
208      * @param commandArgs command and arguments
209      * @param env environment name value pairs
210      * @param changeToDirectory working directory
211      * @throws IOException if an I/O error occurs
212      */

213     public void execute(String JavaDoc[] commandArgs, String JavaDoc[] env, String JavaDoc changeToDirectory) throws ProcessException {
214
215         if (log.isDebugEnabled()) {
216             printCommandLine(commandArgs);
217         }
218         try {
219             process = ProcessFactory.getFactory().exec(commandArgs, env, changeToDirectory);
220         } catch (IOException JavaDoc e) {
221             throw new ProcessException("An I/O error occured: " + e.getMessage());
222         } catch (SecurityException JavaDoc e) {
223             throw new ProcessException(
224                 "A security manager exists and its checkExec method " + "doesn't allow creation of a subprocess.");
225         } catch (NullPointerException JavaDoc e) {
226             throw new ProcessException("Command is null.");
227         } catch (IllegalArgumentException JavaDoc e) {
228             throw new ProcessException("Command is empty.");
229         }
230     }
231
232     /**
233      * Execute a command
234      *
235      * @param commandPath path of comand
236      * @param args arguments after the comand
237      * @param env environment name value pairs
238      * @param changeToDirectory working directory
239      * @throws IOException if an I/O error occurs
240      */

241     public void execute(String JavaDoc commandPath, String JavaDoc[] args, String JavaDoc[] env, String JavaDoc changeToDirectory)
242         throws ProcessException {
243
244         commandArgs = constructCommandArray(commandPath, args);
245         execute(commandArgs, env, changeToDirectory);
246     }
247
248     /**
249      * Reads output from the external process to the streams.
250      *
251      * @param out process stdout is written to this stream
252      * @param err process stderr is written to this stream
253      * @throws ProcessException if process not yet executed
254      */

255     public void waitAndRead(OutputStream JavaDoc out, OutputStream JavaDoc err) throws ProcessException {
256         if (process == null) {
257             throw new ProcessException("Process not yet executed");
258         }
259
260         ProcessClosure reader = new ProcessClosure(name, process, null, out, err);
261         reader.readBlocking(); // a blocking call
262
}
263
264     /**
265      * Reads output from the external process to the streams. A progress monitor
266      * is polled to test for cancellation. Destroys the process if the monitor
267      * becomes cancelled
268      *
269      * @param output process stdout is written to this stream
270      * @param err process stderr is written to this stream
271      * @param monitor monitor monitor to receive progress info and to cancel
272      * the external process
273      * @throws ProcessException if process not yet executed or if process
274      * cancelled
275      */

276     public void waitAndRead(OutputStream JavaDoc output, OutputStream JavaDoc err, IProgressMonitor monitor) throws ProcessException {
277         if (process == null) {
278             throw new ProcessException("Process not yet executed");
279         }
280
281         PipedOutputStream JavaDoc errOutPipe = new PipedOutputStream JavaDoc();
282         PipedOutputStream JavaDoc outputPipe = new PipedOutputStream JavaDoc();
283         PipedInputStream JavaDoc errInPipe, inputPipe;
284         try {
285             errInPipe = new PipedInputStream JavaDoc(errOutPipe);
286             inputPipe = new PipedInputStream JavaDoc(outputPipe);
287         } catch (IOException JavaDoc e) {
288             throw new ProcessException("Command canceled");
289         }
290
291         ProcessClosure closure = new ProcessClosure(name, process, null, outputPipe, errOutPipe);
292         closure.readNonBlocking();
293
294         processStreams(closure, output, inputPipe, err, errInPipe, monitor);
295     }
296
297     /**
298      * Writes input to and reads output from the external process to the streams.
299      *
300      * @param in process stdin is read from this stream
301      * @param out process stdout is written to this stream
302      * @param err process stderr is written to this stream
303      * @throws ProcessException if process not yet executed
304      */

305     public void waitAndWrite(InputStream JavaDoc in, OutputStream JavaDoc out, OutputStream JavaDoc err) throws ProcessException {
306         if (process == null) {
307             throw new ProcessException("Process not yet executed");
308         }
309
310         ProcessClosure reader = new ProcessClosure(name, process, in, out, err);
311         reader.writeBlocking(); // a blocking call
312
}
313
314     /**
315      * Writes input to and reads output from the external process to the streams.
316      * A progress monitor is polled to test for cancellation. Destroys the
317      * process if the monitor becomes cancelled
318      *
319      * @param in process stdin is read from this stream
320      * @param output process stdout is written to this stream
321      * @param err process stderr is written to this stream
322      * @param monitor monitor monitor to receive progress info and to cancel
323      * the external process
324      * @throws ProcessException if process not yet executed or if process
325      * cancelled
326      */

327     public void waitAndWrite(InputStream JavaDoc in, OutputStream JavaDoc output, OutputStream JavaDoc err, IProgressMonitor monitor)
328         throws ProcessException {
329         if (process == null) {
330             throw new ProcessException("Process not yet executed");
331         }
332
333         PipedOutputStream JavaDoc errOutPipe = new PipedOutputStream JavaDoc();
334         PipedOutputStream JavaDoc outputPipe = new PipedOutputStream JavaDoc();
335         PipedInputStream JavaDoc errInPipe, inputPipe;
336         try {
337             errInPipe = new PipedInputStream JavaDoc(errOutPipe);
338             inputPipe = new PipedInputStream JavaDoc(outputPipe);
339         } catch (IOException JavaDoc e) {
340             throw new ProcessException("Command canceled");
341         }
342
343         ProcessClosure closure = new ProcessClosure(name, process, in, outputPipe, errOutPipe);
344         closure.readNonBlocking();
345         closure.writeNonBlocking();
346
347         processStreams(closure, output, inputPipe, err, errInPipe, monitor);
348     }
349
350     /**
351      * process the Streams.while the external process returns bytes. Cancellation
352      * is possible by the ProgressMonitor
353      *
354      * @param closure process closure object which handles the interaction with
355      * the external process
356      * @param output process stdout is written to this stream
357      * @param inputPipe piped stream to other thread for the stdout
358      * @param err process stderr is written to this stream
359      * @param errInPipe piped stream to other thread for the stderr
360      * @param monitor monitor to receive progress info and to cancel
361      * the external process
362      * @throws ProcessException if process cancelled
363      */

364     protected void processStreams(
365         ProcessClosure closure,
366         OutputStream JavaDoc output,
367         PipedInputStream JavaDoc inputPipe,
368         OutputStream JavaDoc err,
369         PipedInputStream JavaDoc errInPipe,
370         IProgressMonitor monitor)
371         throws ProcessException {
372
373         monitor.begin();
374
375         byte buffer[] = new byte[BUFFER_SIZE];
376         int nbytes;
377         while (!monitor.isCanceled() && closure.isAlive()) {
378             nbytes = 0;
379             try {
380                 if (errInPipe.available() > 0) {
381                     nbytes = errInPipe.read(buffer);
382                     err.write(buffer, 0, nbytes);
383                     err.flush();
384                 }
385                 if (inputPipe.available() > 0) {
386                     nbytes = inputPipe.read(buffer);
387                     output.write(buffer, 0, nbytes);
388                     output.flush();
389                 }
390             } catch (IOException JavaDoc e) {}
391             if (nbytes == 0) {
392                 try {
393                     Thread.sleep(DELAY);
394                 } catch (InterruptedException JavaDoc ie) {}
395             } else {
396                 monitor.worked();
397             }
398         }
399
400         // Operation canceled by the user, terminate abnormally.
401
if (monitor.isCanceled()) {
402             closure.terminate();
403             throw new ProcessException("Command canceled");
404         }
405
406         try {
407             process.waitFor();
408         } catch (InterruptedException JavaDoc e) {
409             //System.err.println("reader exception " +e);
410
//e.printStackTrace();
411
}
412
413         // Drain the pipes.
414
try {
415             while (errInPipe.available() > 0 || inputPipe.available() > 0) {
416                 nbytes = 0;
417                 if (errInPipe.available() > 0) {
418                     nbytes = errInPipe.read(buffer);
419                     err.write(buffer, 0, nbytes);
420                     err.flush();
421                 }
422                 if (inputPipe.available() > 0) {
423                     nbytes = inputPipe.read(buffer);
424                     output.write(buffer, 0, nbytes);
425                     output.flush();
426                 }
427                 if (nbytes != 0) {
428                     monitor.worked();
429                 }
430             }
431         } catch (IOException JavaDoc e) {} finally {
432             try {
433                 errInPipe.close();
434             } catch (IOException JavaDoc e) {}
435             try {
436                 inputPipe.close();
437             } catch (IOException JavaDoc e) {}
438         }
439
440         monitor.done();
441     }
442
443     /**
444      * print Command Line.
445      *
446      * @param commandArgs array of comand and args
447      */

448     public void printCommandLine(String JavaDoc[] commandArgs) {
449         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
450         for (int i = 0; i < commandArgs.length; i++) {
451             buf.append(commandArgs[i]);
452             buf.append(' ');
453         }
454         buf.append(lineSeparator);
455         log.debug(buf.toString());
456     }
457 }
458
Popular Tags