KickJava   Java API By Example, From Geeks To Geeks.

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


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.InputStream JavaDoc;
13 import java.io.OutputStream JavaDoc;
14
15 import org.mmbase.util.logging.Logger;
16 import org.mmbase.util.logging.Logging;
17
18 /**
19  * ProcessClosure handles the reading of the stdout and stderr of a external
20  * process. A reader can block the calling thread until it is finished reading
21  * (readBlocking). Or the reader can immidiately return when reading of the
22  * stdout and stderr begins (readNonBlocking).
23  *
24  * ProcessClosure handles the writing of the stdin of a external process. A
25  * writer can block the calling thread until it is finished writing to the stdin
26  * and reading the stdout and stderr (writeBlocking). Or the writer can
27  * imidiately return when writing to stdin and reading of the stdout and sterr
28  * begins (writeNonBlocking)
29  *
30  * @author Nico Klasens (Finalist IT Group)
31  * @version $Id: ProcessClosure.java,v 1.4 2006/04/18 13:11:06 michiel Exp $
32  * @since MMBase-1.6
33  */

34 public class ProcessClosure {
35
36     private static final Logger log = Logging.getLoggerInstance(ProcessClosure.class);
37
38     /**
39      * the name of the process closure
40      */

41     protected String JavaDoc name;
42
43     /**
44      * the process object representing the external process
45      */

46     protected Process JavaDoc process;
47
48     /**
49      * The stream where data is read from to pipe it to stdin
50      */

51     protected InputStream JavaDoc input;
52     /**
53      * The stream where data is written to when piped from stdout
54      */

55     protected OutputStream JavaDoc output;
56     /**
57      * The stream where data is written to when piped from stderr
58      */

59     protected OutputStream JavaDoc error;
60
61     /**
62      * Thread for copying bytes from input to stdin
63      */

64     protected StreamCopyThread inputWriter;
65     /**
66      * Thread for copying bytes from stdout to output
67      */

68     protected StreamCopyThread outputReader;
69     /**
70      * Thread for copying bytes from stderr to error
71      */

72     protected StreamCopyThread errorReader;
73
74     /**
75      * Creates a process reader
76     * .
77     * @param name the name of the reader
78     * @param inputStream process stdin is read from this stream. Can be
79     * <code>null</code>, if not interested in writing the input
80      * @param outputStream process stdout is written to this stream. Can be
81      * <code>null</code>, if not interested in reading the output
82      * @param errorStream porcess stderr is written to this stream. Can be
83      * <code>null</code>, if not interested in reading the output
84      */

85     public ProcessClosure(
86         String JavaDoc name,
87         Process JavaDoc process,
88         InputStream JavaDoc inputStream,
89         OutputStream JavaDoc outputStream,
90         OutputStream JavaDoc errorStream) {
91         this.name = name;
92         this.process = process;
93         this.input = inputStream;
94         this.output = outputStream;
95         this.error = errorStream;
96     }
97
98     /**
99     * read data from the external process without blocking the calling thread
100     */

101     public void readNonBlocking() {
102         log.debug(name + " read Non Blocking");
103
104         ThreadGroup JavaDoc group = new ThreadGroup JavaDoc(name + " ThreadGroup");
105
106         //Reading both stdout and stderr is required to prevent deadlocks from
107
//the external process.
108

109         //External process Streams are seen from the point of view of the java process
110
InputStream JavaDoc stdout = process.getInputStream();
111         InputStream JavaDoc stderr = process.getErrorStream();
112
113         outputReader = new StreamCopyThread(group, name + "OutputReader", stdout, output, false);
114         errorReader = new StreamCopyThread(group, name + "ErrorReader", stderr, error, false);
115
116         outputReader.start();
117         errorReader.start();
118     }
119
120     /**
121      * write data to the external process without blocking the calling thread
122      */

123     public void writeNonBlocking() {
124         log.debug(name + " write Non Blocking");
125         //External process Streams are seen from the point of view of the java process
126
if (input != null) {
127             OutputStream JavaDoc stdin = process.getOutputStream();
128
129             inputWriter = new StreamCopyThread(name + "InputWriter", input, stdin, true);
130
131             inputWriter.start();
132         }
133     }
134
135     /**
136      * read data from the external process and block the calling thread until
137      * reading is finished
138      */

139     public void readBlocking() {
140         log.debug(name + " read Blocking");
141         readNonBlocking();
142
143         log.debug(name + " wait for process");
144         waitForProcess();
145         waitForReaders();
146
147         // it seems that thread termination and stream closing is working without
148
// any help
149
process = null;
150         outputReader = null;
151         errorReader = null;
152         log.debug(name + " read done");
153     }
154
155     /**
156      * write data to the external process and block the calling thread until
157      * writing and reading is finished
158      */

159     public void writeBlocking() {
160         log.debug(name + " write Blocking");
161
162         //Reading both stdout and stderr is required to prevent deadlocks from
163
//the external process.
164
readNonBlocking();
165         writeNonBlocking();
166
167         log.debug(name + " wait for process");
168         waitForWriter();
169         waitForProcess();
170         waitForReaders();
171
172         // it seems that thread termination and stream closing is working without
173
// any help
174
process = null;
175         outputReader = null;
176         errorReader = null;
177         inputWriter = null;
178         log.debug(name + " write done");
179     }
180
181     /**
182      * wait for the external process.to end
183      */

184     protected void waitForProcess() {
185         boolean finished = false;
186         while (!finished) {
187             try {
188                 process.waitFor();
189             } catch (InterruptedException JavaDoc e) {
190                 //System.err.println("exception " +e);
191
}
192             try {
193                 process.exitValue();
194                 finished = true;
195             } catch (IllegalThreadStateException JavaDoc e) {
196                 //System.err.println("exception " +e);
197
}
198         }
199     }
200
201     /**
202      * wait for the reading threads to finish copying
203      */

204     protected void waitForReaders() {
205         // double-check using output threads
206
if (!outputReader.finished()) {
207             outputReader.waitFor();
208         }
209
210         if (!errorReader.finished()) {
211             errorReader.waitFor();
212         }
213     }
214
215     /**
216      * wait for the writing thread to finish copying
217      */

218     protected void waitForWriter() {
219         // double-check using input threads
220
if (!inputWriter.finished()) {
221             inputWriter.waitFor();
222         }
223     }
224
225     /**
226     * Process closure is alive when the external process and writer/reader
227     * threads are still busy
228     * @return <code>true</code> if is alive and <code>false</code> otherwise
229     */

230     public boolean isAlive() {
231         if (process != null) {
232             if (outputReader.isAlive() || errorReader.isAlive()) {
233                 return true;
234             } else {
235                 process = null;
236                 outputReader = null;
237                 errorReader = null;
238             }
239         }
240         return false;
241     }
242
243     /**
244      * Forces the termination of the launched process
245      */

246     public void terminate() {
247         if (process != null) {
248             process.destroy();
249             process = null;
250         }
251     }
252
253 }
254
Popular Tags