KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > antmod > util > ProcessLauncher


1 package org.antmod.util;
2
3 import java.io.*;
4 import java.util.ArrayList JavaDoc;
5 import java.util.Iterator JavaDoc;
6 import java.util.logging.Level JavaDoc;
7 import java.util.logging.Logger JavaDoc;
8
9 /**
10  * Launches a process, redirecting the output of that sub-process
11  * to the output of this (the parent) process.
12  *
13  * @author Klaas Waslander
14  */

15 public final class ProcessLauncher {
16     /** the logger for this class */
17     private final static Logger JavaDoc LOGGER = Logger.getLogger(ProcessLauncher.class.getName());
18
19     private String JavaDoc commandLine;
20     private String JavaDoc[] commandArray;
21     private File baseDir;
22
23     private ArrayList JavaDoc listeners = new ArrayList JavaDoc(1);
24
25     private Process JavaDoc subProcess;
26     private boolean finished = false;
27
28     StringBuffer JavaDoc out = new StringBuffer JavaDoc();
29     StringBuffer JavaDoc err = new StringBuffer JavaDoc();
30
31     /**
32      * Constructs new process launcher with the given command line.
33      */

34     public ProcessLauncher(String JavaDoc commandLine) {
35         this(commandLine, null);
36     }
37     public ProcessLauncher(String JavaDoc commandLine, File baseDir) {
38         this.commandLine = commandLine;
39         this.baseDir = baseDir;
40     }
41
42     /**
43      * Constructs new process launcher with the given command array.
44      */

45     public ProcessLauncher(String JavaDoc[] commandArray) {
46         this(commandArray, null);
47     }
48     public ProcessLauncher(String JavaDoc[] commandArray, File baseDir) {
49         this.commandArray = commandArray;
50         this.baseDir = baseDir;
51     }
52
53     /**
54      * Constructs new process launcher with the given command element list.
55      */

56     public ProcessLauncher(ArrayList JavaDoc commandList) {
57         this(commandList, null);
58     }
59     public ProcessLauncher(ArrayList JavaDoc commandList, File baseDir) {
60         this(toStringArray(commandList), baseDir);
61     }
62
63     private static String JavaDoc[] toStringArray(ArrayList JavaDoc list) {
64         String JavaDoc[] result = new String JavaDoc[list.size()];
65         Iterator JavaDoc iter = list.iterator();
66         int arrayIndex = 0;
67         while (iter.hasNext()) {
68             result[arrayIndex++] = iter.next().toString();
69         }
70         return result;
71     }
72
73     /**
74      * Classes implementing this interface can receive
75      * output generated by processes launched using the ProcessLauncher.
76      */

77     public interface OutputListener {
78         public void standardOutput(char[] output);
79
80         public void errorOutput(char[] output);
81     }
82
83     /**
84      * Add a listener for output from the to-be-launched process.
85      */

86     public void addOutputListener(OutputListener listener) {
87         this.listeners.add(listener);
88     }
89
90     /** fire error output event */
91     private void fireErr(char[] err) {
92         if (this.listeners.isEmpty()) {
93             this.err.append(out);
94         }
95
96         Iterator JavaDoc iter = this.listeners.iterator();
97         while (iter.hasNext()) {
98             ((OutputListener)iter.next()).errorOutput(err);
99         }
100     }
101
102     /** fire standard output event */
103     private void fireOut(char[] out) {
104         if (this.listeners.isEmpty()) {
105             this.out.append(out);
106         }
107
108         Iterator JavaDoc iter = this.listeners.iterator();
109         while (iter.hasNext()) {
110             ((OutputListener)iter.next()).standardOutput(out);
111         }
112     }
113
114     /**
115      * Get standard output, in case no listeners were registered - never returns null.
116      */

117     public String JavaDoc getStandardOutput() {
118         if (!this.listeners.isEmpty()) {
119             throw new IllegalStateException JavaDoc("Cannot get standard output, because outputlisteners have been registered.");
120         }
121         return this.out.toString();
122     }
123
124     /**
125      * Get error output, in case no listeners were registered - never returns null.
126      */

127     public String JavaDoc getErrorOutput() {
128         if (!this.listeners.isEmpty()) {
129             throw new IllegalStateException JavaDoc("Cannot get error output, because outputlisteners have been registered.");
130         }
131         return this.err.toString();
132     }
133
134     /**
135      * Get the commandline that is used to launch the process.
136      */

137     public String JavaDoc getCommandLine() {
138         String JavaDoc usedCommand = this.commandLine;
139         if (this.commandLine == null && this.commandArray != null) {
140             usedCommand = "";
141             for (int i = 0; i < this.commandArray.length; i++) {
142                 if (i > 0) {
143                     usedCommand += " ";
144                 }
145                 usedCommand += this.commandArray[i];
146             }
147         }
148         return usedCommand;
149     }
150     
151     /**
152      * Check whether execution has finished.
153      */

154     public boolean hasFinished() {
155         return finished;
156     }
157
158     /**
159      * Launches the process, and blocks until that process completes execution.
160      * @throws CommandNotExistsException If the command could not be executed because it does not exist
161      */

162     public int launch() throws CommandNotExistsException {
163         this.err.setLength(0);
164         this.out.setLength(0);
165
166         BackgroundPrinter stdout = null;
167         BackgroundPrinter stderr = null;
168         try {
169             if (this.commandArray != null) {
170                 this.subProcess = Runtime.getRuntime().exec(this.commandArray, null, this.baseDir);
171             }
172             else {
173                 this.subProcess = Runtime.getRuntime().exec(this.commandLine, null, this.baseDir);
174             }
175
176             stdout = new BackgroundPrinter(subProcess.getInputStream(), false);
177             stderr = new BackgroundPrinter(subProcess.getErrorStream(), true);
178             stdout.start();
179             stderr.start();
180
181             // kill process and wait max 10 seconds for output to complete
182
int exitValue = this.subProcess.waitFor();
183             stdout.join(10000);
184             stderr.join(10000);
185
186             /*
187             if (exitValue != 0) {
188                 LOGGER.fine("WARNING: exit value " + exitValue + " for command \"" + getCommandLine() + "\"");
189             }
190             */

191
192             return exitValue;
193         }
194         catch (IOException ioe) {
195             // usually caused if the command does not exist at all
196
throw new CommandNotExistsException("Command probably does not exist: " + ioe);
197         }
198         catch (Exception JavaDoc e) {
199             LOGGER.log(Level.SEVERE, "Exception while running/launching \"" + getCommandLine() + "\".", e);
200         }
201         finally {
202             if (this.subProcess != null) {
203                 this.subProcess.destroy();
204                 this.subProcess = null;
205             }
206             if (stdout != null) {
207                 stdout.close();
208             }
209             if (stderr != null) {
210                 stderr.close();
211             }
212             this.finished = true;
213         }
214         return -1;
215     }
216
217     /**
218      * Tries to abort the currently running process.
219      */

220     public void abort() {
221         if (this.subProcess != null) {
222             this.subProcess.destroy();
223             this.subProcess = null;
224         }
225     }
226
227     /**
228      * Catches output from a "java.lang.Process" and writes it
229      * to either System.err or System.out.
230      *
231      * @author Klaas Waslander - Sun Java Center
232      */

233     private class BackgroundPrinter extends Thread JavaDoc {
234         private InputStream in;
235         boolean isErrorOutput;
236
237         public BackgroundPrinter(InputStream in, boolean isErrorOutput) {
238             this.in = in;
239             this.isErrorOutput = isErrorOutput;
240         }
241
242         public void run() {
243             try {
244                 BufferedReader reader = new BufferedReader(new InputStreamReader(this.in));
245
246                 // read buffer
247
char[] buf = new char[1024];
248
249                 // write data to target, until no more data is left to read
250
int numberOfReadBytes;
251                 while ((numberOfReadBytes = reader.read(buf)) != -1) {
252                     char[] clearedbuf = new char[numberOfReadBytes];
253                     System.arraycopy(buf, 0, clearedbuf, 0, numberOfReadBytes);
254
255                     if (this.isErrorOutput) {
256                         fireErr(clearedbuf);
257                     }
258                     else {
259                         fireOut(clearedbuf);
260                     }
261                 }
262                 /* } catch (IOException ioe) {
263                                 // ignore this: process has ended, causing IOException
264                             } catch (NullPointerException ioe) {
265                                 // ignore this: there was no resulting output
266                 */

267             }
268             catch (Exception JavaDoc e) {
269                 LOGGER.log(Level.FINE, "Exception while reading from stream from subprocess.", e);
270             }
271         }
272
273         public void close() {
274             try {
275                 this.in.close();
276             }
277             catch (Exception JavaDoc e) {
278                 LOGGER.log(Level.WARNING, "Closing background stream for launched process caused exception.", e);
279             }
280         }
281     }
282
283     /**
284      * Exception that is thrown when a command could not be executed because it (probably) does not exist at all.
285      *
286      * @author Klaas Waslander
287      */

288     public static class CommandNotExistsException extends RuntimeException JavaDoc {
289         /**
290          * Construct a new exception for a command that does not exist.
291          * @param msg The message for this exception.
292          */

293         public CommandNotExistsException(String JavaDoc msg) {
294             super(msg);
295         }
296     }
297 }
298
Popular Tags