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