3e0e7f853eade21fb9fa57b45c7bbfd1c3893f3d
[utils] / support / general / src / main / java / org / wamblee / io / SimpleProcess.java
1 /*
2  * Copyright 2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.wamblee.io;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.OutputStream;
27 import java.io.PrintStream;
28 import java.io.StringWriter;
29 import java.io.Writer;
30
31
32 /**
33  * DOCUMENT ME!
34  *
35  * @author $author$
36  * @version $Revision$
37  */
38 public class SimpleProcess {
39     /**
40      * DOCUMENT ME!
41      */
42     private static final Log LOG = LogFactory.getLog(SimpleProcess.class);
43
44     /**
45      * DOCUMENT ME!
46      */
47     private File directory;
48
49     /**
50      * DOCUMENT ME!
51      */
52     private String[] cmd;
53
54     /**
55      * DOCUMENT ME!
56      */
57     private String stdout;
58
59     /**
60      * DOCUMENT ME!
61      */
62     private String stderr;
63
64 /**
65      * Creates a new SimpleProcess object.
66      *
67      * @param aDirectory DOCUMENT ME!
68      * @param aCmd DOCUMENT ME!
69      */
70     public SimpleProcess(File aDirectory, String[] aCmd) {
71         directory     = aDirectory;
72         cmd           = aCmd;
73     }
74
75     /**
76      * DOCUMENT ME!
77      *
78      * @return the stdout
79      */
80     public String getStdout() {
81         return stdout;
82     }
83
84     /**
85      * DOCUMENT ME!
86      *
87      * @return the stderr
88      */
89     public String getStderr() {
90         return stderr;
91     }
92
93     /**
94      * Runs the process and blocks until it is done.
95      *
96      * @return Exit status of the process.
97      *
98      * @throws IOException In case of problems.
99      */
100     public int run() throws IOException {
101         return runImpl();
102     }
103
104     /**
105      * DOCUMENT ME!
106      *
107      * @return DOCUMENT ME!
108      *
109      * @throws IOException DOCUMENT ME!
110      */
111     private int runImpl() throws IOException {
112         try {
113             String fullcmd = "";
114
115             for (String part : cmd) {
116                 fullcmd += (" " + part);
117             }
118
119             LOG.debug("Executing '" + fullcmd + "' in directory '" + directory
120                 + "'");
121
122             java.lang.Process proc = Runtime.getRuntime()
123                 .exec(cmd, null, directory);
124
125             // Read standard output and error in separate threads to avoid
126             // deadlock.
127             StringWriter myStdout     = new StringWriter();
128             StringWriter myStderr     = new StringWriter();
129             Thread       stdoutReader = readAndLogStream("STDOUT>  ",
130                     proc.getInputStream(), myStdout);
131             Thread       stderrReader = readAndLogStream("STDERR>  ",
132                     proc.getErrorStream(), myStderr);
133
134             try {
135                 proc.waitFor();
136             } catch (InterruptedException e) {
137                 IOException exception = new IOException(
138                         "Process was terminated: " + this);
139                 exception.initCause(e);
140                 throw exception;
141             }
142
143             waitForReader(stdoutReader);
144             waitForReader(stderrReader);
145
146             stdout     = myStdout.toString();
147             stderr     = myStderr.toString();
148
149             if (proc.exitValue() != 0) {
150                 LOG.warn("Exit value was non-zero: " + this);
151             } else {
152                 LOG.debug("Process finished");
153             }
154
155             return proc.exitValue();
156         } catch (IOException e) {
157             IOException exception = new IOException("Error executing process: "
158                     + this);
159             exception.initCause(e);
160             throw exception;
161         }
162     }
163
164     /**
165      * DOCUMENT ME!
166      *
167      * @param aReaderThread DOCUMENT ME!
168      */
169     private void waitForReader(Thread aReaderThread) {
170         try {
171             aReaderThread.join();
172         } catch (InterruptedException e) {
173             LOG.warn(this
174                 + ": error waiting for output stream reader of process to finish");
175         }
176     }
177
178     /**
179      * DOCUMENT ME!
180      *
181      * @param aPrefix DOCUMENT ME!
182      * @param aStream DOCUMENT ME!
183      * @param aOutput DOCUMENT ME!
184      *
185      * @return DOCUMENT ME!
186      */
187     private Thread readAndLogStream(final String aPrefix,
188         final InputStream aStream, final Writer aOutput) {
189         Thread inputReader = new Thread() {
190                 @Override
191                 public void run() {
192                     BufferedReader br = null;
193
194                     try {
195                         br = new BufferedReader(new InputStreamReader(aStream));
196
197                         String str;
198
199                         while ((str = br.readLine()) != null) {
200                             LOG.debug(aPrefix + str);
201                             aOutput.write(str);
202                         }
203                     } catch (IOException e) {
204                         LOG.warn(SimpleProcess.this
205                             + ": error reading input stream", e);
206                     } finally {
207                         if (br != null) {
208                             try {
209                                 br.close();
210                             } catch (IOException e) {
211                                 LOG.warn("Error closing stream " + aPrefix);
212                             }
213                         }
214                     }
215                 }
216             };
217
218         inputReader.start();
219
220         return inputReader;
221     }
222
223     /**
224      * DOCUMENT ME!
225      *
226      * @return DOCUMENT ME!
227      */
228     @Override
229     public String toString() {
230         String fullcmd = "";
231
232         for (String part : cmd) {
233             fullcmd += (part + " ");
234         }
235
236         return "process(dir = '" + directory + "', cmd = '" + fullcmd + "')";
237     }
238 }