1 package org
.argeo
.slc
.core
.execution
.tasks
;
4 import java
.io
.FileWriter
;
5 import java
.io
.IOException
;
7 import java
.util
.HashMap
;
11 import org
.apache
.commons
.exec
.CommandLine
;
12 import org
.apache
.commons
.exec
.DefaultExecutor
;
13 import org
.apache
.commons
.exec
.ExecuteException
;
14 import org
.apache
.commons
.exec
.ExecuteResultHandler
;
15 import org
.apache
.commons
.exec
.ExecuteWatchdog
;
16 import org
.apache
.commons
.exec
.Executor
;
17 import org
.apache
.commons
.exec
.LogOutputStream
;
18 import org
.apache
.commons
.exec
.PumpStreamHandler
;
19 import org
.apache
.commons
.exec
.ShutdownHookProcessDestroyer
;
20 import org
.apache
.commons
.io
.IOUtils
;
21 import org
.apache
.commons
.lang
.NotImplementedException
;
22 import org
.apache
.commons
.logging
.Log
;
23 import org
.apache
.commons
.logging
.LogFactory
;
24 import org
.argeo
.slc
.SlcException
;
25 import org
.argeo
.slc
.core
.structure
.tree
.TreeSPath
;
26 import org
.argeo
.slc
.core
.structure
.tree
.TreeSRelatedHelper
;
27 import org
.argeo
.slc
.core
.test
.SimpleResultPart
;
28 import org
.argeo
.slc
.structure
.StructureAware
;
29 import org
.argeo
.slc
.test
.TestResult
;
30 import org
.argeo
.slc
.test
.TestStatus
;
31 import org
.springframework
.core
.io
.Resource
;
33 /** Execute and OS system call. */
34 public class SystemCall
extends TreeSRelatedHelper
implements Runnable
,
35 StructureAware
<TreeSPath
> {
36 private final Log log
= LogFactory
.getLog(getClass());
38 private String execDir
;
40 private String cmd
= null;
41 private List
<Object
> command
= null;
43 private Boolean synchronous
= true;
45 private String stdErrLogLevel
= "ERROR";
46 private String stdOutLogLevel
= "INFO";
48 private Resource stdOutFile
= null;
49 private Resource stdErrFile
= null;
51 private Map
<String
, List
<Object
>> osCommands
= new HashMap
<String
, List
<Object
>>();
52 private Map
<String
, String
> osCmds
= new HashMap
<String
, String
>();
53 private Map
<String
, String
> environmentVariables
= new HashMap
<String
, String
>();
55 private Long watchdogTimeout
= 24 * 60 * 60 * 1000l;
57 private TestResult testResult
;
63 public SystemCall(List
<Object
> command
) {
65 this.command
= command
;
70 final Writer stdOutWriter
;
71 final Writer stdErrWriter
;
72 if (stdOutFile
!= null) {
73 stdOutWriter
= createWriter(stdOutFile
);
76 if (stdErrFile
!= null) {
77 stdErrWriter
= createWriter(stdErrFile
);
79 if (stdOutFile
!= null) {
80 stdErrWriter
= createWriter(stdOutFile
);
86 if (log
.isTraceEnabled()) {
87 log
.debug("os.name=" + System
.getProperty("os.name"));
88 log
.debug("os.arch=" + System
.getProperty("os.arch"));
89 log
.debug("os.version=" + System
.getProperty("os.version"));
92 // Execution directory
94 if (execDir
!= null) {
95 // Replace '/' by local file separator, for portability
96 execDir
.replace('/', File
.separatorChar
);
97 dir
= new File(execDir
).getCanonicalFile();
100 // Check if an OS specific command overrides
101 String osName
= System
.getProperty("os.name");
102 List
<Object
> commandToUse
= null;
103 if (osCommands
.containsKey(osName
))
104 commandToUse
= osCommands
.get(osName
);
106 commandToUse
= command
;
107 String cmdToUse
= null;
108 if (osCmds
.containsKey(osName
))
109 cmdToUse
= osCmds
.get(osName
);
115 dir
= new File(getUsedDir(dir
));
119 Executor executor
= new DefaultExecutor();
120 executor
.setWatchdog(new ExecuteWatchdog(watchdogTimeout
));
122 PumpStreamHandler pumpStreamHandler
= new PumpStreamHandler(
123 new LogOutputStream() {
124 protected void processLine(String line
, int level
) {
125 log(stdOutLogLevel
, line
);
126 if (stdOutWriter
!= null)
127 appendLineToFile(stdOutWriter
, line
);
129 }, new LogOutputStream() {
130 protected void processLine(String line
, int level
) {
131 log(stdErrLogLevel
, line
);
132 if (stdErrWriter
!= null)
133 appendLineToFile(stdErrWriter
, line
);
136 executor
.setStreamHandler(pumpStreamHandler
);
137 executor
.setProcessDestroyer(new ShutdownHookProcessDestroyer());
138 executor
.setWorkingDirectory(dir
);
139 final CommandLine commandLine
;
141 // Which command definition to use
142 if (commandToUse
== null && cmdToUse
== null)
143 throw new SlcException("Please specify a command.");
144 else if (commandToUse
!= null && cmdToUse
!= null)
145 throw new SlcException(
146 "Specify the command either as a line or as a list.");
147 else if (cmdToUse
!= null) {
148 if (log
.isTraceEnabled())
149 log
.trace("Execute '" + cmdToUse
+ "' in "
152 commandLine
= CommandLine
.parse(cmdToUse
);
153 } else if (commandToUse
!= null) {
154 if (log
.isTraceEnabled())
155 log
.trace("Execute '" + commandToUse
+ "' in "
157 if (commandToUse
.size() == 0)
158 throw new SlcException("Command line is empty.");
160 commandLine
= new CommandLine(commandToUse
.get(0).toString());
161 for (int i
= 1; i
< commandToUse
.size(); i
++)
162 commandLine
.addArgument(commandToUse
.get(i
).toString());
164 // all cases covered previously
165 throw new NotImplementedException();
169 Map
<String
, String
> environmentVariablesToUse
= environmentVariables
170 .size() > 0 ? environmentVariables
: null;
173 ExecuteResultHandler executeResultHandler
= new ExecuteResultHandler() {
175 public void onProcessComplete(int exitValue
) {
176 if (log
.isDebugEnabled())
177 log
.debug("Process " + commandLine
178 + " properly completed.");
179 if (testResult
!= null) {
180 forwardPath(testResult
, null);
181 testResult
.addResultPart(new SimpleResultPart(
182 TestStatus
.PASSED
, "Process " + commandLine
183 + " properly completed."));
187 public void onProcessFailed(ExecuteException e
) {
188 if (testResult
!= null) {
189 forwardPath(testResult
, null);
190 testResult
.addResultPart(new SimpleResultPart(
191 TestStatus
.ERROR
, "Process " + commandLine
194 throw new SlcException("Process " + commandLine
202 int exitValue
= executor
.execute(commandLine
,
203 environmentVariablesToUse
);
204 executeResultHandler
.onProcessComplete(exitValue
);
205 } catch (ExecuteException e1
) {
206 executeResultHandler
.onProcessFailed(e1
);
209 executor
.execute(commandLine
, environmentVariablesToUse
,
210 executeResultHandler
);
211 } catch (Exception e
) {
212 throw new SlcException("Could not execute command " + cmd
, e
);
214 IOUtils
.closeQuietly(stdOutWriter
);
215 IOUtils
.closeQuietly(stdErrWriter
);
221 * Shortcut method returning the current exec dir if the specified one is
224 private String
getUsedDir(File dir
) {
226 return System
.getProperty("user.dir");
228 return dir
.getPath();
231 protected void log(String logLevel
, String line
) {
232 if ("ERROR".equals(logLevel
))
234 else if ("WARN".equals(logLevel
))
236 else if ("INFO".equals(logLevel
))
238 else if ("DEBUG".equals(logLevel
))
240 else if ("TRACE".equals(logLevel
))
243 throw new SlcException("Unknown log level " + logLevel
);
246 protected void appendLineToFile(Writer writer
, String line
) {
248 writer
.append(line
).append('\n');
249 } catch (IOException e
) {
250 log
.error("Cannot write to log file", e
);
254 protected Writer
createWriter(Resource target
) {
255 FileWriter writer
= null;
257 File file
= target
.getFile();
258 writer
= new FileWriter(file
, true);
259 } catch (IOException e
) {
260 log
.error("Cannot create log file " + target
, e
);
261 IOUtils
.closeQuietly(writer
);
266 public void setCmd(String command
) {
270 public void setExecDir(String execdir
) {
271 this.execDir
= execdir
;
274 public void setStdErrLogLevel(String stdErrLogLevel
) {
275 this.stdErrLogLevel
= stdErrLogLevel
;
278 public void setStdOutLogLevel(String stdOutLogLevel
) {
279 this.stdOutLogLevel
= stdOutLogLevel
;
282 public void setSynchronous(Boolean synchronous
) {
283 this.synchronous
= synchronous
;
286 public void setCommand(List
<Object
> command
) {
287 this.command
= command
;
290 public void setOsCommands(Map
<String
, List
<Object
>> osCommands
) {
291 this.osCommands
= osCommands
;
294 public void setOsCmds(Map
<String
, String
> osCmds
) {
295 this.osCmds
= osCmds
;
298 public void setEnvironmentVariables(Map
<String
, String
> environmentVariables
) {
299 this.environmentVariables
= environmentVariables
;
302 public void setWatchdogTimeout(Long watchdogTimeout
) {
303 this.watchdogTimeout
= watchdogTimeout
;
306 public void setStdOutFile(Resource stdOutFile
) {
307 this.stdOutFile
= stdOutFile
;
310 public void setStdErrFile(Resource stdErrFile
) {
311 this.stdErrFile
= stdErrFile
;
314 public void setTestResult(TestResult testResult
) {
315 this.testResult
= testResult
;