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