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
.logging
.Log
;
22 import org
.apache
.commons
.logging
.LogFactory
;
23 import org
.argeo
.slc
.SlcException
;
24 import org
.argeo
.slc
.core
.structure
.tree
.TreeSPath
;
25 import org
.argeo
.slc
.core
.structure
.tree
.TreeSRelatedHelper
;
26 import org
.argeo
.slc
.core
.test
.SimpleResultPart
;
27 import org
.argeo
.slc
.structure
.StructureAware
;
28 import org
.argeo
.slc
.test
.TestResult
;
29 import org
.argeo
.slc
.test
.TestStatus
;
30 import org
.springframework
.core
.io
.Resource
;
32 /** Execute and OS system call. */
33 public class SystemCall
extends TreeSRelatedHelper
implements Runnable
,
34 StructureAware
<TreeSPath
> {
35 private final Log log
= LogFactory
.getLog(getClass());
37 private String execDir
;
39 private String cmd
= null;
40 private List
<Object
> command
= null;
42 private Boolean synchronous
= true;
44 private String stdErrLogLevel
= "ERROR";
45 private String stdOutLogLevel
= "INFO";
47 private Resource stdOutFile
= null;
48 private Resource stdErrFile
= null;
50 private Map
<String
, List
<Object
>> osCommands
= new HashMap
<String
, List
<Object
>>();
51 private Map
<String
, String
> osCmds
= new HashMap
<String
, String
>();
52 private Map
<String
, String
> environmentVariables
= new HashMap
<String
, String
>();
54 private Long watchdogTimeout
= 24 * 60 * 60 * 1000l;
56 private TestResult testResult
;
62 public SystemCall(List
<Object
> command
) {
64 this.command
= command
;
69 final Writer stdOutWriter
;
70 final Writer stdErrWriter
;
71 if (stdOutFile
!= null) {
72 stdOutWriter
= createWriter(stdOutFile
);
75 if (stdErrFile
!= null) {
76 stdErrWriter
= createWriter(stdErrFile
);
78 if (stdOutFile
!= null) {
79 stdErrWriter
= createWriter(stdOutFile
);
85 if (log
.isTraceEnabled()) {
86 log
.debug("os.name=" + System
.getProperty("os.name"));
87 log
.debug("os.arch=" + System
.getProperty("os.arch"));
88 log
.debug("os.version=" + System
.getProperty("os.version"));
91 // Execution directory
93 if (execDir
!= null) {
94 // Replace '/' by local file separator, for portability
95 execDir
.replace('/', File
.separatorChar
);
96 dir
= new File(execDir
).getCanonicalFile();
101 dir
= new File(getUsedDir(dir
));
105 // Watchdog to check for lost processes
106 Executor executor
= new DefaultExecutor();
107 executor
.setWatchdog(new ExecuteWatchdog(watchdogTimeout
));
109 // Redirect standard streams
110 PumpStreamHandler pumpStreamHandler
= new PumpStreamHandler(
111 new LogOutputStream() {
112 protected void processLine(String line
, int level
) {
113 log(stdOutLogLevel
, line
);
114 if (stdOutWriter
!= null)
115 appendLineToFile(stdOutWriter
, line
);
117 }, new LogOutputStream() {
118 protected void processLine(String line
, int level
) {
119 log(stdErrLogLevel
, line
);
120 if (stdErrWriter
!= null)
121 appendLineToFile(stdErrWriter
, line
);
124 executor
.setStreamHandler(pumpStreamHandler
);
125 executor
.setProcessDestroyer(new ShutdownHookProcessDestroyer());
126 executor
.setWorkingDirectory(dir
);
128 // Command line to use
129 final CommandLine commandLine
= createCommandLine();
132 Map
<String
, String
> environmentVariablesToUse
= environmentVariables
133 .size() > 0 ? environmentVariables
: null;
136 ExecuteResultHandler executeResultHandler
= new ExecuteResultHandler() {
138 public void onProcessComplete(int exitValue
) {
139 if (log
.isDebugEnabled())
140 log
.debug("Process " + commandLine
141 + " properly completed.");
142 if (testResult
!= null) {
143 forwardPath(testResult
, null);
144 testResult
.addResultPart(new SimpleResultPart(
145 TestStatus
.PASSED
, "Process " + commandLine
146 + " properly completed."));
150 public void onProcessFailed(ExecuteException e
) {
151 if (testResult
!= null) {
152 forwardPath(testResult
, null);
153 testResult
.addResultPart(new SimpleResultPart(
154 TestStatus
.ERROR
, "Process " + commandLine
157 throw new SlcException("Process " + commandLine
165 int exitValue
= executor
.execute(commandLine
,
166 environmentVariablesToUse
);
167 executeResultHandler
.onProcessComplete(exitValue
);
168 } catch (ExecuteException e1
) {
169 executeResultHandler
.onProcessFailed(e1
);
172 executor
.execute(commandLine
, environmentVariablesToUse
,
173 executeResultHandler
);
174 } catch (Exception e
) {
175 throw new SlcException("Could not execute command " + cmd
, e
);
177 IOUtils
.closeQuietly(stdOutWriter
);
178 IOUtils
.closeQuietly(stdErrWriter
);
183 /** Can be overridden by specific command wrapper*/
184 protected CommandLine
createCommandLine() {
185 // Check if an OS specific command overrides
186 String osName
= System
.getProperty("os.name");
187 List
<Object
> commandToUse
= null;
188 if (osCommands
.containsKey(osName
))
189 commandToUse
= osCommands
.get(osName
);
191 commandToUse
= command
;
192 String cmdToUse
= null;
193 if (osCmds
.containsKey(osName
))
194 cmdToUse
= osCmds
.get(osName
);
198 final CommandLine commandLine
;
200 // Which command definition to use
201 if (commandToUse
== null && cmdToUse
== null)
202 throw new SlcException("Please specify a command.");
203 else if (commandToUse
!= null && cmdToUse
!= null)
204 throw new SlcException(
205 "Specify the command either as a line or as a list.");
206 else if (cmdToUse
!= null) {
207 commandLine
= CommandLine
.parse(cmdToUse
);
208 } else if (commandToUse
!= null) {
209 if (commandToUse
.size() == 0)
210 throw new SlcException("Command line is empty.");
212 commandLine
= new CommandLine(commandToUse
.get(0).toString());
213 for (int i
= 1; i
< commandToUse
.size(); i
++)
214 commandLine
.addArgument(commandToUse
.get(i
).toString());
216 // all cases covered previously
217 throw new UnsupportedOperationException();
223 * Shortcut method returning the current exec dir if the specified one is
226 private String
getUsedDir(File dir
) {
228 return System
.getProperty("user.dir");
230 return dir
.getPath();
233 protected void log(String logLevel
, String line
) {
234 if ("ERROR".equals(logLevel
))
236 else if ("WARN".equals(logLevel
))
238 else if ("INFO".equals(logLevel
))
240 else if ("DEBUG".equals(logLevel
))
242 else if ("TRACE".equals(logLevel
))
245 throw new SlcException("Unknown log level " + logLevel
);
248 protected void appendLineToFile(Writer writer
, String line
) {
250 writer
.append(line
).append('\n');
251 } catch (IOException e
) {
252 log
.error("Cannot write to log file", e
);
256 protected Writer
createWriter(Resource target
) {
257 FileWriter writer
= null;
259 File file
= target
.getFile();
260 writer
= new FileWriter(file
, true);
261 } catch (IOException e
) {
262 log
.error("Cannot create log file " + target
, e
);
263 IOUtils
.closeQuietly(writer
);
268 public void setCmd(String command
) {
272 public void setExecDir(String execdir
) {
273 this.execDir
= execdir
;
276 public void setStdErrLogLevel(String stdErrLogLevel
) {
277 this.stdErrLogLevel
= stdErrLogLevel
;
280 public void setStdOutLogLevel(String stdOutLogLevel
) {
281 this.stdOutLogLevel
= stdOutLogLevel
;
284 public void setSynchronous(Boolean synchronous
) {
285 this.synchronous
= synchronous
;
288 public void setCommand(List
<Object
> command
) {
289 this.command
= command
;
292 public void setOsCommands(Map
<String
, List
<Object
>> osCommands
) {
293 this.osCommands
= osCommands
;
296 public void setOsCmds(Map
<String
, String
> osCmds
) {
297 this.osCmds
= osCmds
;
300 public void setEnvironmentVariables(Map
<String
, String
> environmentVariables
) {
301 this.environmentVariables
= environmentVariables
;
304 public void setWatchdogTimeout(Long watchdogTimeout
) {
305 this.watchdogTimeout
= watchdogTimeout
;
308 public void setStdOutFile(Resource stdOutFile
) {
309 this.stdOutFile
= stdOutFile
;
312 public void setStdErrFile(Resource stdErrFile
) {
313 this.stdErrFile
= stdErrFile
;
316 public void setTestResult(TestResult testResult
) {
317 this.testResult
= testResult
;