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