001    /*--------------------------------------------------------------------------+
002    $Id: ProcessUtils.java 26268 2010-02-18 10:44:30Z juergens $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.commons.io;
019    
020    import java.io.IOException;
021    import java.io.OutputStreamWriter;
022    import java.io.Writer;
023    
024    /**
025     * Executes a system process. Takes care of reading stdout and stderr of the
026     * process in separate threads to avoid blocking.
027     * 
028     * @author juergens
029     * @author $Author: juergens $
030     * @version $Rev: 26268 $
031     * @levd.rating GREEN Hash: 4D8721B16BD1F29DDCC9C144FC6E0BCC
032     */
033    public class ProcessUtils {
034    
035            /**
036             * Executes a process in a thread-safe way.
037             * 
038             * @param completeArguments
039             *            Array of command line arguments to start the process
040             * 
041             * @return result of the execution
042             */
043            public static ExecutionResult execute(String[] completeArguments)
044                            throws IOException {
045                    return execute(completeArguments, null);
046            }
047    
048            /**
049             * Executes a process in a thread-safe way.
050             * 
051             * @param completeArguments
052             *            Array of command line arguments to start the process
053             * @param input
054             *            String that gets written to stdin
055             * 
056             * @return result of the execution
057             */
058            public static ExecutionResult execute(String[] completeArguments,
059                            String input) throws IOException {
060                    ProcessBuilder builder = new ProcessBuilder(completeArguments);
061                    return execute(builder, input);
062            }
063    
064            /**
065             * Executes a process in a thread-safe way.
066             * 
067             * @param builder
068             *            builder that gets executed
069             * @return result of the execution
070             */
071            public static ExecutionResult execute(ProcessBuilder builder)
072                            throws IOException {
073                    return execute(builder, null);
074            }
075    
076            /**
077             * Executes a process in a thread-safe way.
078             * 
079             * @param builder
080             *            builder that gets executed
081             * @param input
082             *            String that gets written to stdin
083             * @return result of the execution
084             */
085            public static ExecutionResult execute(ProcessBuilder builder, String input)
086                            throws IOException {
087                    // start process
088                    Process process = builder.start();
089    
090                    // read error for later use
091                    StreamReaderThread stderrReader = new StreamReaderThread(process
092                                    .getErrorStream());
093                    StreamReaderThread stdoutReader = new StreamReaderThread(process
094                                    .getInputStream());
095    
096                    // write input to process
097                    if (input != null) {
098                            Writer stdIn = new OutputStreamWriter(process.getOutputStream());
099                            stdIn.write(input);
100                            stdIn.close();
101                    }
102    
103                    // wait for process
104                    try {
105                            process.waitFor();
106    
107                            // It is important to wait for the threads, so the output is
108                            // completely stored.
109                            stderrReader.join();
110                            stdoutReader.join();
111    
112                    } catch (InterruptedException e) {
113                            // ignore this one
114                    }
115    
116                    return new ExecutionResult(stdoutReader.getContent(), stderrReader
117                                    .getContent(), process.exitValue());
118            }
119    
120            /**
121             * Parameter object that encapsulates the result of a process execution.
122             * This object is immutable.
123             */
124            public static class ExecutionResult {
125    
126                    /** Output on stdout of the process */
127                    private final String stdout;
128    
129                    /** Output on stderr of the process */
130                    private final String stderr;
131    
132                    /** Return code of the process */
133                    private final int returnCode;
134    
135                    /** Constructor */
136                    private ExecutionResult(String stdout, String stderr, int returnCode) {
137                            this.stdout = stdout;
138                            this.stderr = stderr;
139                            this.returnCode = returnCode;
140                    }
141    
142                    /** Returns stdout. */
143                    public String getStdout() {
144                            return stdout;
145                    }
146    
147                    /** Returns stderr. */
148                    public String getStderr() {
149                            return stderr;
150                    }
151    
152                    /** Returns returnCode. */
153                    public int getReturnCode() {
154                            return returnCode;
155                    }
156            }
157    }