1 package org
.argeo
.slc
.core
.execution
.tasks
;
4 import java
.io
.FileWriter
;
5 import java
.io
.IOException
;
6 import java
.io
.InputStream
;
7 import java
.io
.OutputStream
;
9 import java
.util
.HashMap
;
10 import java
.util
.List
;
13 import org
.apache
.commons
.exec
.CommandLine
;
14 import org
.apache
.commons
.exec
.DefaultExecutor
;
15 import org
.apache
.commons
.exec
.ExecuteException
;
16 import org
.apache
.commons
.exec
.ExecuteResultHandler
;
17 import org
.apache
.commons
.exec
.ExecuteStreamHandler
;
18 import org
.apache
.commons
.exec
.ExecuteWatchdog
;
19 import org
.apache
.commons
.exec
.Executor
;
20 import org
.apache
.commons
.exec
.LogOutputStream
;
21 import org
.apache
.commons
.exec
.PumpStreamHandler
;
22 import org
.apache
.commons
.exec
.ShutdownHookProcessDestroyer
;
23 import org
.apache
.commons
.io
.FileUtils
;
24 import org
.apache
.commons
.io
.IOUtils
;
25 import org
.apache
.commons
.logging
.Log
;
26 import org
.apache
.commons
.logging
.LogFactory
;
27 import org
.argeo
.slc
.SlcException
;
28 import org
.argeo
.slc
.UnsupportedException
;
29 import org
.argeo
.slc
.core
.structure
.tree
.TreeSPath
;
30 import org
.argeo
.slc
.core
.structure
.tree
.TreeSRelatedHelper
;
31 import org
.argeo
.slc
.core
.test
.SimpleResultPart
;
32 import org
.argeo
.slc
.structure
.StructureAware
;
33 import org
.argeo
.slc
.test
.TestResult
;
34 import org
.argeo
.slc
.test
.TestStatus
;
35 import org
.springframework
.core
.io
.Resource
;
37 /** Execute and OS system call. */
38 public class SystemCall
extends TreeSRelatedHelper
implements Runnable
,
39 StructureAware
<TreeSPath
> {
40 private final Log log
= LogFactory
.getLog(getClass());
42 private String execDir
;
44 private String cmd
= null;
45 private List
<Object
> command
= null;
47 private Boolean synchronous
= true;
49 private String stdErrLogLevel
= "ERROR";
50 private String stdOutLogLevel
= "INFO";
52 private Resource stdOutFile
= null;
53 private Resource stdErrFile
= null;
55 private Map
<String
, List
<Object
>> osCommands
= new HashMap
<String
, List
<Object
>>();
56 private Map
<String
, String
> osCmds
= new HashMap
<String
, String
>();
57 private Map
<String
, String
> environmentVariables
= new HashMap
<String
, String
>();
59 private Boolean logCommand
= false;
60 private Boolean redirectStreams
= true;
61 private String osConsole
= null;
62 private String generateScript
= null;
64 private Long watchdogTimeout
= 24 * 60 * 60 * 1000l;
66 private TestResult testResult
;
74 public SystemCall(List
<Object
> command
) {
76 this.command
= command
;
80 final Writer stdOutWriter
;
81 final Writer stdErrWriter
;
82 if (stdOutFile
!= null) {
83 stdOutWriter
= createWriter(stdOutFile
);
86 if (stdErrFile
!= null) {
87 stdErrWriter
= createWriter(stdErrFile
);
89 if (stdOutFile
!= null) {
90 stdErrWriter
= createWriter(stdOutFile
);
96 if (log
.isTraceEnabled()) {
97 log
.debug("os.name=" + System
.getProperty("os.name"));
98 log
.debug("os.arch=" + System
.getProperty("os.arch"));
99 log
.debug("os.version=" + System
.getProperty("os.version"));
102 // Execution directory
103 File dir
= new File(getExecDirToUse());
107 // Watchdog to check for lost processes
108 Executor executor
= new DefaultExecutor();
109 executor
.setWatchdog(new ExecuteWatchdog(watchdogTimeout
));
111 if (redirectStreams
) {
112 // Redirect standard streams
113 executor
.setStreamHandler(createExecuteStreamHandler(
114 stdOutWriter
, stdErrWriter
));
116 // Dummy stream handler (otherwise pump is used)
117 executor
.setStreamHandler(new DummyexecuteStreamHandler());
120 executor
.setProcessDestroyer(new ShutdownHookProcessDestroyer());
121 executor
.setWorkingDirectory(dir
);
123 // Command line to use
124 final CommandLine commandLine
= createCommandLine();
126 log
.info("Execute command:\n" + commandLine
+ "\n");
129 Map
<String
, String
> environmentVariablesToUse
= environmentVariables
130 .size() > 0 ? environmentVariables
: null;
133 ExecuteResultHandler executeResultHandler
= createExecuteResultHandler(commandLine
);
137 int exitValue
= executor
.execute(commandLine
,
138 environmentVariablesToUse
);
139 executeResultHandler
.onProcessComplete(exitValue
);
140 } catch (ExecuteException e1
) {
141 executeResultHandler
.onProcessFailed(e1
);
144 executor
.execute(commandLine
, environmentVariablesToUse
,
145 executeResultHandler
);
146 } catch (Exception e
) {
147 throw new SlcException("Could not execute command " + cmd
, e
);
149 IOUtils
.closeQuietly(stdOutWriter
);
150 IOUtils
.closeQuietly(stdErrWriter
);
155 /** Can be overridden by specific command wrapper */
156 protected CommandLine
createCommandLine() {
157 // Check if an OS specific command overrides
158 String osName
= System
.getProperty("os.name");
159 List
<Object
> commandToUse
= null;
160 if (osCommands
.containsKey(osName
))
161 commandToUse
= osCommands
.get(osName
);
163 commandToUse
= command
;
164 String cmdToUse
= null;
165 if (osCmds
.containsKey(osName
))
166 cmdToUse
= osCmds
.get(osName
);
170 CommandLine commandLine
= null;
172 // Which command definition to use
173 if (commandToUse
== null && cmdToUse
== null)
174 throw new SlcException("Please specify a command.");
175 else if (commandToUse
!= null && cmdToUse
!= null)
176 throw new SlcException(
177 "Specify the command either as a line or as a list.");
178 else if (cmdToUse
!= null) {
179 commandLine
= CommandLine
.parse(cmdToUse
);
180 } else if (commandToUse
!= null) {
181 if (commandToUse
.size() == 0)
182 throw new SlcException("Command line is empty.");
184 commandLine
= new CommandLine(commandToUse
.get(0).toString());
186 for (int i
= 1; i
< commandToUse
.size(); i
++) {
187 if (log
.isTraceEnabled())
188 log
.debug(commandToUse
.get(i
));
189 commandLine
.addArgument(commandToUse
.get(i
).toString());
192 // all cases covered previously
193 throw new UnsupportedException();
196 if (generateScript
!= null) {
197 File scriptFile
= new File(getExecDirToUse() + File
.separator
200 FileUtils
.writeStringToFile(scriptFile
,
201 (osConsole
!= null ? osConsole
+ " " : "")
202 + commandLine
.toString());
203 } catch (IOException e
) {
204 throw new SlcException("Could not generate script "
207 commandLine
= new CommandLine(scriptFile
);
209 if (osConsole
!= null)
210 commandLine
= CommandLine
.parse(osConsole
+ " "
211 + commandLine
.toString());
217 protected ExecuteStreamHandler
createExecuteStreamHandler(
218 final Writer stdOutWriter
, final Writer stdErrWriter
) {
221 PumpStreamHandler pumpStreamHandler
= new PumpStreamHandler(
222 new LogOutputStream() {
223 protected void processLine(String line
, int level
) {
224 log(stdOutLogLevel
, line
);
225 if (stdOutWriter
!= null)
226 appendLineToFile(stdOutWriter
, line
);
228 }, new LogOutputStream() {
229 protected void processLine(String line
, int level
) {
230 log(stdErrLogLevel
, line
);
231 if (stdErrWriter
!= null)
232 appendLineToFile(stdErrWriter
, line
);
235 return pumpStreamHandler
;
238 protected ExecuteResultHandler
createExecuteResultHandler(
239 final CommandLine commandLine
) {
240 return new ExecuteResultHandler() {
242 public void onProcessComplete(int exitValue
) {
243 if (log
.isDebugEnabled())
245 .debug("Process " + commandLine
246 + " properly completed.");
247 if (testResult
!= null) {
248 forwardPath(testResult
, null);
249 testResult
.addResultPart(new SimpleResultPart(
250 TestStatus
.PASSED
, "Process " + commandLine
251 + " properly completed."));
255 public void onProcessFailed(ExecuteException e
) {
256 if (testResult
!= null) {
257 forwardPath(testResult
, null);
258 testResult
.addResultPart(new SimpleResultPart(
259 TestStatus
.ERROR
, "Process " + commandLine
262 throw new SlcException("Process " + commandLine
270 * Shortcut method getting the execDir to use
272 protected String
getExecDirToUse() {
275 if (execDir
!= null) {
276 // Replace '/' by local file separator, for portability
277 execDir
.replace('/', File
.separatorChar
);
278 dir
= new File(execDir
).getCanonicalFile();
282 return System
.getProperty("user.dir");
284 return dir
.getPath();
285 } catch (Exception e
) {
286 throw new SlcException("Cannot find exec dir", e
);
290 protected void log(String logLevel
, String line
) {
291 if ("ERROR".equals(logLevel
))
293 else if ("WARN".equals(logLevel
))
295 else if ("INFO".equals(logLevel
))
297 else if ("DEBUG".equals(logLevel
))
299 else if ("TRACE".equals(logLevel
))
302 throw new SlcException("Unknown log level " + logLevel
);
305 protected void appendLineToFile(Writer writer
, String line
) {
307 writer
.append(line
).append('\n');
308 } catch (IOException e
) {
309 log
.error("Cannot write to log file", e
);
313 protected Writer
createWriter(Resource target
) {
314 FileWriter writer
= null;
316 File file
= target
.getFile();
317 writer
= new FileWriter(file
, true);
318 } catch (IOException e
) {
319 log
.error("Cannot create log file " + target
, e
);
320 IOUtils
.closeQuietly(writer
);
325 public void setCmd(String command
) {
329 public void setExecDir(String execdir
) {
330 this.execDir
= execdir
;
333 public void setStdErrLogLevel(String stdErrLogLevel
) {
334 this.stdErrLogLevel
= stdErrLogLevel
;
337 public void setStdOutLogLevel(String stdOutLogLevel
) {
338 this.stdOutLogLevel
= stdOutLogLevel
;
341 public void setSynchronous(Boolean synchronous
) {
342 this.synchronous
= synchronous
;
345 public void setCommand(List
<Object
> command
) {
346 this.command
= command
;
349 public void setOsCommands(Map
<String
, List
<Object
>> osCommands
) {
350 this.osCommands
= osCommands
;
353 public void setOsCmds(Map
<String
, String
> osCmds
) {
354 this.osCmds
= osCmds
;
357 public void setEnvironmentVariables(Map
<String
, String
> environmentVariables
) {
358 this.environmentVariables
= environmentVariables
;
361 public void setWatchdogTimeout(Long watchdogTimeout
) {
362 this.watchdogTimeout
= watchdogTimeout
;
365 public void setStdOutFile(Resource stdOutFile
) {
366 this.stdOutFile
= stdOutFile
;
369 public void setStdErrFile(Resource stdErrFile
) {
370 this.stdErrFile
= stdErrFile
;
373 public void setTestResult(TestResult testResult
) {
374 this.testResult
= testResult
;
377 public void setLogCommand(Boolean logCommand
) {
378 this.logCommand
= logCommand
;
381 public void setRedirectStreams(Boolean redirectStreams
) {
382 this.redirectStreams
= redirectStreams
;
385 public void setOsConsole(String osConsole
) {
386 this.osConsole
= osConsole
;
389 public void setGenerateScript(String generateScript
) {
390 this.generateScript
= generateScript
;
393 private class DummyexecuteStreamHandler
implements ExecuteStreamHandler
{
395 public void setProcessErrorStream(InputStream is
) throws IOException
{
398 public void setProcessInputStream(OutputStream os
) throws IOException
{
401 public void setProcessOutputStream(InputStream is
) throws IOException
{
404 public void start() throws IOException
{