]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java
@update:81; Use commons-exec
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.simple / src / main / java / org / argeo / slc / core / execution / tasks / SystemCall.java
1 package org.argeo.slc.core.execution.tasks;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.InputStreamReader;
8 import java.io.OutputStream;
9 import java.io.OutputStreamWriter;
10 import java.io.Writer;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14
15 import org.apache.commons.exec.CommandLine;
16 import org.apache.commons.exec.DefaultExecutor;
17 import org.apache.commons.exec.ExecuteException;
18 import org.apache.commons.exec.ExecuteResultHandler;
19 import org.apache.commons.exec.ExecuteWatchdog;
20 import org.apache.commons.exec.Executor;
21 import org.apache.commons.exec.LogOutputStream;
22 import org.apache.commons.exec.PumpStreamHandler;
23 import org.apache.commons.exec.ShutdownHookProcessDestroyer;
24 import org.apache.commons.exec.launcher.CommandLauncher;
25 import org.apache.commons.exec.launcher.CommandLauncherFactory;
26 import org.apache.commons.io.IOUtils;
27 import org.apache.commons.lang.NotImplementedException;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.argeo.slc.SlcException;
31
32 public class SystemCall implements Runnable {
33 // TODO: specify environment variables
34
35 private final Log log = LogFactory.getLog(getClass());
36
37 private String execDir;
38
39 private String cmd = null;
40 private List<String> command = null;
41
42 private Boolean synchronous = true;
43 // private Boolean captureStdIn = false;
44
45 private String stdErrLogLevel = "ERROR";
46 private String stdOutLogLevel = "INFO";
47
48 private Map<String, List<String>> osCommands = new HashMap<String, List<String>>();
49 private Map<String, String> osCmds = new HashMap<String, String>();
50 private Map<String, String> environmentVariables = new HashMap<String, String>();
51
52 private Long watchdogTimeout = 24 * 60 * 60 * 1000l;
53
54 public void run() {
55 try {
56 if (log.isTraceEnabled()) {
57 log.debug("os.name=" + System.getProperty("os.name"));
58 log.debug("os.arch=" + System.getProperty("os.arch"));
59 log.debug("os.version=" + System.getProperty("os.version"));
60 }
61
62 // Execution directory
63 File dir = null;
64 if (execDir != null) {
65 // Replace '/' by local file separator, for portability
66 execDir.replace('/', File.separatorChar);
67 dir = new File(execDir).getCanonicalFile();
68 }
69
70 // Process process = null;
71
72 // Check if an OS specific command overrides
73 String osName = System.getProperty("os.name");
74 List<String> commandToUse = null;
75 if (osCommands.containsKey(osName))
76 commandToUse = osCommands.get(osName);
77 else
78 commandToUse = command;
79 String cmdToUse = null;
80 if (osCmds.containsKey(osName))
81 cmdToUse = osCmds.get(osName);
82 else
83 cmdToUse = cmd;
84
85 // Prepare executor
86 if (dir == null)
87 dir = new File(getUsedDir(dir));
88 if (!dir.exists())
89 dir.mkdirs();
90
91 Executor executor = new DefaultExecutor();
92 executor.setWatchdog(new ExecuteWatchdog(watchdogTimeout));
93 PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(
94 new LogOutputStream() {
95 protected void processLine(String line, int level) {
96 log(stdOutLogLevel, line);
97 }
98 }, new LogOutputStream() {
99 protected void processLine(String line, int level) {
100 log(stdErrLogLevel, line);
101 }
102 }, null);
103 executor.setStreamHandler(pumpStreamHandler);
104 executor.setProcessDestroyer(new ShutdownHookProcessDestroyer());
105 executor.setWorkingDirectory(dir);
106 final CommandLine commandLine;
107
108 // Which command definition to use
109 if (commandToUse == null && cmdToUse == null)
110 throw new SlcException("Please specify a command.");
111 else if (commandToUse != null && cmdToUse != null)
112 throw new SlcException(
113 "Specify the command either as a line or as a list.");
114 else if (cmdToUse != null) {
115 if (log.isTraceEnabled())
116 log.trace("Execute '" + cmdToUse + "' in "
117 + getUsedDir(dir));
118
119 commandLine = CommandLine.parse(cmdToUse);
120 // process = Runtime.getRuntime().exec(cmdToUse, null, dir);
121 } else if (commandToUse != null) {
122 if (log.isTraceEnabled())
123 log.trace("Execute '" + commandToUse + "' in "
124 + getUsedDir(dir));
125 if (commandToUse.size() == 0)
126 throw new SlcException("Command line is empty.");
127
128 commandLine = new CommandLine(commandToUse.get(0));
129 for (int i = 1; i < commandToUse.size(); i++)
130 commandLine.addArgument(commandToUse.get(i));
131 // ProcessBuilder processBuilder = new
132 // ProcessBuilder(commandToUse);
133 // processBuilder.directory(dir);
134 // process = processBuilder.start();
135 } else {
136 // all cases covered previously
137 throw new NotImplementedException();
138 }
139
140 // Env variables
141 Map<String, String> environmentVariablesToUse = environmentVariables
142 .size() > 0 ? environmentVariables : null;
143
144 // Execute
145 ExecuteResultHandler executeResultHandler = new ExecuteResultHandler() {
146
147 public void onProcessComplete(int exitValue) {
148 log.info("Process " + commandLine + " properly completed.");
149 }
150
151 public void onProcessFailed(ExecuteException e) {
152 throw new SlcException("Process " + commandLine
153 + " failed.", e);
154 }
155 };
156
157 if (synchronous)
158 try {
159 int exitValue = executor.execute(commandLine,
160 environmentVariablesToUse);
161 executeResultHandler.onProcessComplete(exitValue);
162 } catch (ExecuteException e1) {
163 executeResultHandler.onProcessFailed(e1);
164 }
165 else
166 executor.execute(commandLine, environmentVariablesToUse,
167 executeResultHandler);
168
169 // Manage standard streams
170 // StreamReaderThread stdOutThread = new StreamReaderThread(process
171 // .getInputStream()) {
172 // protected void callback(String line) {
173 // stdOutCallback(line);
174 // }
175 // };
176 // stdOutThread.start();
177 // StreamReaderThread stdErrThread = new StreamReaderThread(process
178 // .getErrorStream()) {
179 // protected void callback(String line) {
180 // stdErrCallback(line);
181 // }
182 // };
183 // stdErrThread.start();
184 // if (captureStdIn)
185 // new StdInThread(process.getOutputStream()).start();
186 //
187 // // Wait for the end of the process
188 // if (synchronous) {
189 // Integer exitCode = process.waitFor();
190 // if (exitCode != 0) {
191 // Thread.sleep(5000);// leave the process a chance to log
192 // log.warn("Process return exit code " + exitCode);
193 // }
194 // } else {
195 // // asynchronous: return
196 // }
197 } catch (Exception e) {
198 throw new SlcException("Could not execute command " + cmd, e);
199 }
200
201 }
202
203 /**
204 * Shortcut method returning the current exec dir if the specified one is
205 * null.
206 */
207 private String getUsedDir(File dir) {
208 if (dir == null)
209 return System.getProperty("user.dir");
210 else
211 return dir.getPath();
212 }
213
214 // protected void stdOutCallback(String line) {
215 // log(stdOutLogLevel, line);
216 // }
217 //
218 // protected void stdErrCallback(String line) {
219 // log(stdErrLogLevel, line);
220 // }
221 //
222 protected void log(String logLevel, String line) {
223 if ("ERROR".equals(logLevel))
224 log.error(line);
225 else if ("WARN".equals(logLevel))
226 log.warn(line);
227 else if ("INFO".equals(logLevel))
228 log.info(line);
229 else if ("DEBUG".equals(logLevel))
230 log.debug(line);
231 else if ("TRACE".equals(logLevel))
232 log.trace(line);
233 else
234 throw new SlcException("Unknown log level " + logLevel);
235 }
236
237 public void setCmd(String command) {
238 this.cmd = command;
239 }
240
241 public void setExecDir(String execdir) {
242 this.execDir = execdir;
243 }
244
245 public void setStdErrLogLevel(String stdErrLogLevel) {
246 this.stdErrLogLevel = stdErrLogLevel;
247 }
248
249 public void setStdOutLogLevel(String stdOutLogLevel) {
250 this.stdOutLogLevel = stdOutLogLevel;
251 }
252
253 public void setSynchronous(Boolean synchronous) {
254 this.synchronous = synchronous;
255 }
256
257 // public void setCaptureStdIn(Boolean captureStdIn) {
258 // this.captureStdIn = captureStdIn;
259 // }
260
261 public void setCommand(List<String> command) {
262 this.command = command;
263 }
264
265 public void setOsCommands(Map<String, List<String>> osCommands) {
266 this.osCommands = osCommands;
267 }
268
269 public void setOsCmds(Map<String, String> osCmds) {
270 this.osCmds = osCmds;
271 }
272
273 // protected abstract class StreamReaderThread extends Thread {
274 // private final InputStream stream;
275 //
276 // public StreamReaderThread(InputStream stream) {
277 // this.stream = stream;
278 // }
279 //
280 // @Override
281 // public void run() {
282 // BufferedReader in = null;
283 // try {
284 // in = new BufferedReader(new InputStreamReader(stream));
285 // String line = null;
286 // while ((line = in.readLine()) != null) {
287 // stdOutCallback(line);
288 // }
289 // } catch (IOException e) {
290 // if (log.isTraceEnabled()) {
291 // log.trace("Could not read stream", e);
292 // // catch silently
293 // // because the other methods
294 // // to check whether the stream
295 // // is closed would probably
296 // // be to costly
297 // }
298 // } finally {
299 // if (synchronous)
300 // IOUtils.closeQuietly(in);
301 // }
302 // }
303 //
304 // protected abstract void callback(String line);
305 // }
306 //
307 // protected class StdInThread extends Thread {
308 // private final OutputStream stream;
309 //
310 // public StdInThread(OutputStream stream) {
311 // this.stream = stream;
312 // }
313 //
314 // @Override
315 // public void run() {
316 // BufferedReader in = null;
317 // Writer out = null;
318 // try {
319 // out = new OutputStreamWriter(stream);
320 // in = new BufferedReader(new InputStreamReader(System.in));
321 // String line = null;
322 // while ((line = in.readLine()) != null) {
323 // out.write(line);
324 // out.write("\n");
325 // out.flush();
326 // }
327 // } catch (IOException e) {
328 // throw new SlcException("Could not write to stdin stream", e);
329 // } finally {
330 // if (synchronous) {
331 // IOUtils.closeQuietly(in);
332 // IOUtils.closeQuietly(out);
333 // }
334 // }
335 // }
336 //
337 // }
338 }