]> 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
Make tree test results serializable so that it can be used with ObjectList.
[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.io.IOUtils;
16 import org.apache.commons.logging.Log;
17 import org.apache.commons.logging.LogFactory;
18 import org.argeo.slc.SlcException;
19
20 public class SystemCall implements Runnable {
21 // TODO: specify environment variables
22
23 private final Log log = LogFactory.getLog(getClass());
24
25 private String execDir;
26
27 private String cmd = null;
28 private List<String> command = null;
29
30 private Boolean synchronous = true;
31 private Boolean captureStdIn = false;
32
33 private String stdErrLogLevel = "ERROR";
34 private String stdOutLogLevel = "INFO";
35
36 private Map<String, List<String>> osCommands = new HashMap<String, List<String>>();
37 private Map<String, String> osCmds = new HashMap<String, String>();
38
39 public void run() {
40 try {
41 if (log.isTraceEnabled()) {
42 log.debug("os.name=" + System.getProperty("os.name"));
43 log.debug("os.arch=" + System.getProperty("os.arch"));
44 log.debug("os.version=" + System.getProperty("os.version"));
45 }
46
47 // Execution directory
48 File dir = null;
49 if (execDir != null) {
50 // Replace '/' by local file separator, for portability
51 execDir.replace('/', File.separatorChar);
52 dir = new File(execDir).getCanonicalFile();
53 }
54
55 Process process = null;
56
57 // Check if an OS specific command overrides
58 String osName = System.getProperty("os.name");
59 List<String> commandToUse = null;
60 if (osCommands.containsKey(osName))
61 commandToUse = osCommands.get(osName);
62 else
63 commandToUse = command;
64 String cmdToUse = null;
65 if (osCmds.containsKey(osName))
66 cmdToUse = osCmds.get(osName);
67 else
68 cmdToUse = cmd;
69
70 // Which command definition to use
71 if (commandToUse == null && cmdToUse == null)
72 throw new SlcException("Please specify a command.");
73 else if (commandToUse != null && cmdToUse != null)
74 throw new SlcException(
75 "Specify the command either as a line or as a list.");
76 else if (cmdToUse != null) {
77 if (log.isTraceEnabled())
78 log.trace("Execute '" + cmdToUse + "' in "
79 + getUsedDir(dir));
80 process = Runtime.getRuntime().exec(cmdToUse, null, dir);
81 } else if (commandToUse != null) {
82 if (log.isTraceEnabled())
83 log.trace("Execute '" + commandToUse + "' in "
84 + getUsedDir(dir));
85 ProcessBuilder processBuilder = new ProcessBuilder(commandToUse);
86 processBuilder.directory(dir);
87 process = processBuilder.start();
88 } else {
89 // all cases covered previously
90 }
91
92 // Manage standard streams
93 StreamReaderThread stdOutThread = new StreamReaderThread(process
94 .getInputStream()) {
95 protected void callback(String line) {
96 stdOutCallback(line);
97 }
98 };
99 stdOutThread.start();
100 StreamReaderThread stdErrThread = new StreamReaderThread(process
101 .getErrorStream()) {
102 protected void callback(String line) {
103 stdErrCallback(line);
104 }
105 };
106 stdErrThread.start();
107 if (captureStdIn)
108 new StdInThread(process.getOutputStream()).start();
109
110 // Wait for the end of the process
111 if (synchronous) {
112 Integer exitCode = process.waitFor();
113 if (exitCode != 0) {
114 Thread.sleep(5000);// leave the process a chance to log
115 log.warn("Process return exit code " + exitCode);
116 }
117 } else {
118 // asynchronous: return
119 }
120 } catch (Exception e) {
121 throw new SlcException("Could not execute command " + cmd, e);
122 }
123
124 }
125
126 /**
127 * Shortcut method returning the current exec dir if the specified one is
128 * null.
129 */
130 private String getUsedDir(File dir) {
131 if (dir == null)
132 return System.getProperty("user.dir");
133 else
134 return dir.getPath();
135 }
136
137 protected void stdOutCallback(String line) {
138 log(stdOutLogLevel, line);
139 }
140
141 protected void stdErrCallback(String line) {
142 log(stdErrLogLevel, line);
143 }
144
145 protected void log(String logLevel, String line) {
146 if ("ERROR".equals(logLevel))
147 log.error(line);
148 else if ("WARN".equals(logLevel))
149 log.warn(line);
150 else if ("INFO".equals(logLevel))
151 log.info(line);
152 else if ("DEBUG".equals(logLevel))
153 log.debug(line);
154 else if ("TRACE".equals(logLevel))
155 log.trace(line);
156 else
157 throw new SlcException("Unknown log level " + logLevel);
158 }
159
160 public void setCmd(String command) {
161 this.cmd = command;
162 }
163
164 public void setExecDir(String execdir) {
165 this.execDir = execdir;
166 }
167
168 public void setStdErrLogLevel(String stdErrLogLevel) {
169 this.stdErrLogLevel = stdErrLogLevel;
170 }
171
172 public void setStdOutLogLevel(String stdOutLogLevel) {
173 this.stdOutLogLevel = stdOutLogLevel;
174 }
175
176 public void setSynchronous(Boolean synchronous) {
177 this.synchronous = synchronous;
178 }
179
180 public void setCaptureStdIn(Boolean captureStdIn) {
181 this.captureStdIn = captureStdIn;
182 }
183
184 public void setCommand(List<String> command) {
185 this.command = command;
186 }
187
188 public void setOsCommands(Map<String, List<String>> osCommands) {
189 this.osCommands = osCommands;
190 }
191
192 public void setOsCmds(Map<String, String> osCmds) {
193 this.osCmds = osCmds;
194 }
195
196 protected abstract class StreamReaderThread extends Thread {
197 private final InputStream stream;
198
199 public StreamReaderThread(InputStream stream) {
200 this.stream = stream;
201 }
202
203 @Override
204 public void run() {
205 BufferedReader in = null;
206 try {
207 in = new BufferedReader(new InputStreamReader(stream));
208 String line = null;
209 while ((line = in.readLine()) != null) {
210 stdOutCallback(line);
211 }
212 } catch (IOException e) {
213 if (log.isTraceEnabled()) {
214 log.trace("Could not read stream", e);
215 // catch silently
216 // because the other methods
217 // to check whether the stream
218 // is closed would probably
219 // be to costly
220 }
221 } finally {
222 if (synchronous)
223 IOUtils.closeQuietly(in);
224 }
225 }
226
227 protected abstract void callback(String line);
228 }
229
230 protected class StdInThread extends Thread {
231 private final OutputStream stream;
232
233 public StdInThread(OutputStream stream) {
234 this.stream = stream;
235 }
236
237 @Override
238 public void run() {
239 BufferedReader in = null;
240 Writer out = null;
241 try {
242 out = new OutputStreamWriter(stream);
243 in = new BufferedReader(new InputStreamReader(System.in));
244 String line = null;
245 while ((line = in.readLine()) != null) {
246 out.write(line);
247 out.write("\n");
248 out.flush();
249 }
250 } catch (IOException e) {
251 throw new SlcException("Could not write to stdin stream", e);
252 } finally {
253 if (synchronous) {
254 IOUtils.closeQuietly(in);
255 IOUtils.closeQuietly(out);
256 }
257 }
258 }
259
260 }
261 }