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