1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package org.objectledge.external;
30
31 import java.io.BufferedInputStream;
32 import java.io.BufferedOutputStream;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.OutputStream;
38
39 import org.jcontainer.dna.Configuration;
40 import org.jcontainer.dna.Logger;
41 import org.objectledge.utils.StringUtils;
42
43 /***
44 * @author <a href="rafal@caltha.pl">RafaĆ Krzewski</a>
45 * @version $Id: ProcessExecutor.java,v 1.2 2006/03/28 18:02:38 zwierzem Exp $
46 */
47 public class ProcessExecutor
48 {
49 /***
50 * Default shell invocation format.
51 */
52 public static final String DEFAULT_SHELL = "sh -c";
53
54 /***
55 * Shell invocation format.
56 */
57 private final String[] shellTokens;
58
59 /*** The logger. */
60 private final Logger log;
61
62 /***
63 * Creates a new ProcessExecutor instance.
64 *
65 * @param logger the logger to use.
66 * @param shell the shell invocation format.
67 */
68 public ProcessExecutor(Logger logger, String shell)
69 {
70 this.log = logger;
71 this.shellTokens = shell.split(" ");
72 }
73
74 /***
75 * Creates a new ProcessExecutor instance.
76 *
77 * @param logger the logger to use.
78 * @param configuration component configuration.
79 */
80 public ProcessExecutor(Logger logger, Configuration configuration)
81 {
82 this(logger, configuration.getChild("shell").getValue(DEFAULT_SHELL));
83 }
84
85 /***
86 * Execute an external process.
87 * <p>
88 * No data is sent to the process input stream, output and error streams are not captured.
89 * </p>
90 *
91 * @param args the script name and arguments.
92 * @return execution result.
93 * @throws IOException If the execution fails.
94 */
95 public ExecutionResult exec(String... args)
96 throws IOException
97 {
98 String cmd = concat(args);
99 log.debug("executing " + cmd);
100 try
101 {
102 Process process = Runtime.getRuntime().exec(args);
103 process.waitFor();
104 return new ExecutionResult(process.exitValue());
105 }
106 catch(InterruptedException e)
107 {
108 throw new IOException("execution interrupted");
109 }
110 }
111
112 /***
113 * Executes an external process.
114 *
115 * @param input data to be passed to the process inpupt stream.
116 * @param captureOutput should process output stream be captured.
117 * @param captureError should process error stream be captured.
118 * @param args process executable name and arguments.
119 * @return execution result.
120 * @throws IOException If the execution fails.
121 */
122 public ExecutionResult exec(byte[] input, boolean captureOutput, boolean captureError,
123 String... args)
124 throws IOException
125 {
126 String cmd = concat(args);
127 File in = null;
128 File out = null;
129 File err = null;
130 try
131 {
132 boolean redirect = false;
133 if(input != null)
134 {
135 in = File.createTempFile("ledge-in-", ".tmp");
136 write(in, input);
137 args = StringUtils.push(args, "<" + in.getPath());
138 redirect = true;
139 }
140 if(captureOutput)
141 {
142 out = File.createTempFile("ledge-out-", ".tmp");
143 args = StringUtils.push(args, ">" + out.getPath());
144 redirect = true;
145 }
146 if(captureError)
147 {
148 err = File.createTempFile("ledge-err-", ".tmp");
149 args = StringUtils.push(args, "2>" + err.getPath());
150 redirect = true;
151 }
152
153 Process process;
154 if(redirect)
155 {
156 args = StringUtils.push(shellTokens, concat(args));
157 cmd = concat(args);
158 }
159 log.debug("executing " + cmd);
160 process = Runtime.getRuntime().exec(args);
161 process.waitFor();
162 return new ExecutionResult(process.exitValue(), read(out), read(err));
163 }
164 catch(InterruptedException e)
165 {
166 throw new IOException("execution interrupted");
167 }
168 finally
169 {
170 release(in);
171 release(out);
172 release(err);
173 }
174 }
175
176 /***
177 * Executes an external process.
178 *
179 * @param input data to be passed to the process inpupt stream.
180 * @param captureOutput should process output stream be captured.
181 * @param captureError should process error stream be captured.
182 * @param args process executable name and arguments.
183 * @return execution result.
184 * @throws IOException
185 * @throws IOException If the execution fails.
186 */
187 public ExecutionResult exec(String input, boolean captureOutput, boolean captureError,
188 String... args)
189 throws IOException
190 {
191 return exec(StringUtils.toUTF8(input), captureOutput, captureError, args);
192 }
193
194 /***
195 * Executes an external process.
196 *
197 * @param captureOutput should process output stream be captured.
198 * @param captureError should process error stream be captured.
199 * @param args process executable name and arguments.
200 * @return execution result.
201 * @throws IOException
202 * @throws IOException If the execution fails.
203 */
204 public ExecutionResult exec(boolean captureOutput, boolean captureError, String... args)
205 throws IOException
206 {
207 return exec((byte[])null, captureOutput, captureError, args);
208 }
209
210 private byte[] read(File file)
211 throws IOException
212 {
213 if(file == null)
214 {
215 return null;
216 }
217 BufferedInputStream is = new BufferedInputStream(new FileInputStream(file));
218 byte[] result = new byte[(int)file.length()];
219 is.read(result);
220 return result;
221 }
222
223 private void write(File file, byte[] bytes)
224 throws IOException
225 {
226 OutputStream fos = new BufferedOutputStream(new FileOutputStream(file));
227 fos.write(bytes);
228 fos.close();
229 }
230
231 private void release(File file)
232 {
233 if(file != null && file.exists() && !log.isDebugEnabled())
234 {
235 file.delete();
236 }
237 }
238
239 private String concat(String[] args)
240 {
241 StringBuffer buff = new StringBuffer();
242 for(int i = 0; i < args.length; i++)
243 {
244 buff.append(args[i]);
245 if(i < args.length - 1)
246 {
247 buff.append(' ');
248 }
249 }
250 return buff.toString();
251 }
252 }