(no commit message)
[utils] / support / general / src / main / java / org / wamblee / io / SimpleProcess.java
1 package org.wamblee.io;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.InputStreamReader;
8 import java.io.OutputStream;
9 import java.io.PrintStream;
10 import java.io.StringWriter;
11 import java.io.Writer;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15
16 public class SimpleProcess {
17
18         private static final Log LOG = LogFactory.getLog(SimpleProcess.class);
19
20         private File _directory;
21
22         private String[] _cmd;
23         
24         private String _stdout; 
25         private String _stderr; 
26
27         public SimpleProcess(File aDirectory, String[] aCmd) {
28                 _directory = aDirectory;
29                 _cmd = aCmd;
30         }
31
32     /**
33      * @return the stdout
34      */
35     public String getStdout() {
36         return _stdout;
37     }
38     
39     /**
40      * @return the stderr
41      */
42     public String getStderr() {
43         return _stderr;
44     }
45     
46         /**
47          * Runs the process and blocks until it is done.
48          * 
49          * @return Exit status of the process.
50          * @throws IOException
51          *             In case of problems.
52          */
53         public int run() throws IOException {
54                 return runImpl();
55         }
56
57         private int runImpl() throws IOException {
58                 try {
59                     String fullcmd = ""; 
60                     for (String part: _cmd) {
61                         fullcmd += " " + part; 
62                     }
63                         LOG.debug("Executing '" + fullcmd + "' in directory '" + _directory
64                                         + "'");
65                         java.lang.Process proc = Runtime.getRuntime().exec(_cmd, null, _directory);
66
67                         // Read standard output and error in separate threads to avoid
68                         // deadlock.
69
70             StringWriter stdout = new StringWriter();
71             StringWriter stderr = new StringWriter();
72                         Thread stdoutReader = readAndLogStream("STDOUT>  ", proc
73                                         .getInputStream(), stdout);
74                         Thread stderrReader = readAndLogStream("STDERR>  ", proc
75                                         .getErrorStream(), stderr);
76
77                         try {
78                                 proc.waitFor();
79                         } catch (InterruptedException e) {
80                                 IOException exception = new IOException(
81                                                 "Process was terminated: " + this);
82                                 exception.initCause(e);
83                                 throw exception;
84                         }
85                         waitForReader(stdoutReader);
86                         waitForReader(stderrReader);
87             
88             _stdout = stdout.toString();
89             _stderr = stderr.toString();
90
91                         if (proc.exitValue() != 0) {
92                                 LOG.warn("Exit value was non-zero: " + this);
93                         } else { 
94                                 LOG.debug("Process finished");
95                         }
96                         return proc.exitValue();
97                 } catch (IOException e) {
98                         IOException exception = new IOException("Error executing process: "
99                                         + this);
100                         exception.initCause(e);
101                         throw exception;
102                 }
103         }
104
105         private void waitForReader(Thread aReaderThread) {
106                 try {
107                         aReaderThread.join();
108                 } catch (InterruptedException e) {
109                         LOG
110                                         .warn(this
111                                                         + ": error waiting for output stream reader of process to finish");
112                 }
113         }
114
115         private Thread readAndLogStream(final String aPrefix,
116                         final InputStream aStream, final Writer aOutput) {
117                 Thread inputReader = new Thread() {
118                         @Override
119                         public void run() {
120                                 BufferedReader br = null;
121                                 try {
122                                         br = new BufferedReader(new InputStreamReader(aStream));
123                                         String str;
124                                         while ((str = br.readLine()) != null) {
125                                                 LOG.debug(aPrefix + str);
126                         aOutput.write(str);
127                                         }
128                                 } catch (IOException e) {
129                                         LOG.warn(SimpleProcess.this + ": error reading input stream", e);
130                                 } finally {
131                                         if (br != null) {
132                                                 try {
133                                                         br.close();
134                                                 } catch (IOException e) {
135                                                         LOG.warn("Error closing stream " + aPrefix);
136                                                 }
137                                         }
138                                 }
139                         }
140                 };
141                 inputReader.start();
142                 return inputReader;
143         }
144
145         @Override
146         public String toString() {
147         String fullcmd = "";
148         for (String part: _cmd) { 
149             fullcmd += part + " ";
150         }
151                 return "process(dir = '" + _directory + "', cmd = '" + fullcmd + "')";
152         }
153 }