Source code: edu/emory/mathcs/util/natives/ExecUtils.java
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is the Emory Utilities.
15 *
16 * The Initial Developer of the Original Code is
17 * The Distributed Computing Laboratory, Emory University.
18 * Portions created by the Initial Developer are Copyright (C) 2002
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Alternatively, the contents of this file may be used under the terms of
22 * either the GNU General Public License Version 2 or later (the "GPL"), or
23 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
24 * in which case the provisions of the GPL or the LGPL are applicable instead
25 * of those above. If you wish to allow use of your version of this file only
26 * under the terms of either the GPL or the LGPL, and not to allow others to
27 * use your version of this file under the terms of the MPL, indicate your
28 * decision by deleting the provisions above and replace them with the notice
29 * and other provisions required by the GPL or the LGPL. If you do not delete
30 * the provisions above, a recipient may use your version of this file under
31 * the terms of any one of the MPL, the GPL or the LGPL.
32 *
33 * ***** END LICENSE BLOCK ***** */
34
35 package edu.emory.mathcs.util.natives;
36
37 import java.io.*;
38 import edu.emory.mathcs.util.io.*;
39
40 /**
41 * Utility methods to interact with and manage native processes started from
42 * Java.
43 *
44 * @author Dawid Kurzyniec
45 * @version 1.0
46 */
47 public class ExecUtils {
48
49 /**
50 * Execute specified command and return its results. Waits for the command
51 * to complete and returns its completion status and data written to
52 * standard output and error streams. The process' standard input is set
53 * to EOF. Example:
54 *
55 * <pre>
56 * System.out.println(ExecUtils.execCommand("/bin/ls").getOut());
57 * </pre>
58 *
59 * @param cmd the command to execute
60 * @return the results of the command execution
61 * @throws IOException if an I/O error occurs
62 * @throws InterruptedException if thread is interrupted before command
63 * completes
64 */
65 public static CmdResult execCommand(String cmd)
66 throws IOException, InterruptedException
67 {
68 return execCommand(Runtime.getRuntime().exec(cmd));
69 }
70
71 /**
72 * Attach to the specified process and return its results.
73 * Waits for the process to complete and returns its completion status and
74 * data written to standard output and error streams. The process' standard
75 * input is set to EOF. Example:
76 *
77 * <pre>
78 * Process p = runtime.exec("/bin/ls");
79 * System.out.println(ExecUtils.execCommand(p).getOut());
80 * </pre>
81 *
82 * @param process the process to attach to
83 * @return the results of the process
84 * @throws IOException if an I/O error occurs
85 * @throws InterruptedException if thread is interrupted before process
86 * ends
87 */
88 public static CmdResult execCommand(Process process)
89 throws IOException, InterruptedException
90 {
91 return execCommand(process, new NullInputStream());
92 }
93
94 /**
95 * Attach to the specified process, feed specified standard input,
96 * and return process' results.
97 * Waits for the process to complete and returns completion status and data
98 * written to standard output and error streams.
99 *
100 * @see #execCommand(Process)
101 *
102 * @param process the process to attach to
103 * @param stdin the data to redirect to process' standard input
104 * @return the results of the process
105 * @throws IOException if an I/O error occurs
106 * @throws InterruptedException if thread is interrupted before process
107 * ends
108 */
109 public static CmdResult execCommand(final Process process, final InputStream stdin)
110 throws IOException, InterruptedException
111 {
112 // concurrency to avoid stdio deadlocks
113 Redir stdout = new Redir(process.getInputStream());
114 Redir stderr = new Redir(process.getErrorStream());
115 new Thread(stdout).start();
116 new Thread(stderr).start();
117 // redirect input in the current thread
118 OutputStream pout = process.getOutputStream();
119 new RedirectingInputStream(stdin, true, true).redirectAll(pout);
120 process.waitFor();
121 int exitValue = process.exitValue();
122
123 stdout.throwIfHadException();
124 stderr.throwIfHadException();
125 String out = new String(stdout.getResult());
126 String err = new String(stderr.getResult());
127
128 return new CmdResult(exitValue, out, err);
129 }
130
131 private static class Redir implements Runnable {
132 private IOException ex;
133 final InputStream is;
134 final ByteArrayOutputStream bos;
135 Redir(InputStream is) {
136 this.is = is;
137 this.bos = new ByteArrayOutputStream();
138 }
139 public void run() {
140 try {
141 new RedirectingInputStream(is, true, true).redirectAll(bos);
142 }
143 catch (IOException e) {
144 setException(e);
145 }
146 }
147 synchronized void setException(IOException e) {
148 this.ex = e;
149 }
150 synchronized void throwIfHadException() throws IOException {
151 if (ex != null) throw ex;
152 }
153 public byte[] getResult() {
154 return bos.toByteArray();
155 }
156 }
157
158 /**
159 * Represents the result of a native command. Consists of the process
160 * exit value together with stdout and stderr dumped to strings.
161 *
162 * @author Dawid Kurzyniec
163 * @version 1.0
164 */
165 public static class CmdResult {
166 final int exitValue;
167 final String out;
168 final String err;
169 CmdResult(int exitValue, String out, String err) {
170 this.exitValue = exitValue;
171 this.out = out;
172 this.err = err;
173 }
174 public int getExitValue() { return exitValue; }
175 public String getOut() { return out; }
176 public String getErr() { return err; }
177 }
178 }