1 17 package org.alfresco.util.exec; 18 19 import java.io.BufferedInputStream ; 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.util.Collections ; 23 import java.util.HashMap ; 24 import java.util.HashSet ; 25 import java.util.Map ; 26 import java.util.Set ; 27 import java.util.StringTokenizer ; 28 29 import org.alfresco.error.AlfrescoRuntimeException; 30 import org.apache.commons.logging.Log; 31 import org.apache.commons.logging.LogFactory; 32 33 54 public class RuntimeExec 55 { 56 57 public static final String KEY_OS_DEFAULT = "*"; 58 59 private static final String KEY_OS_NAME = "os.name"; 60 private static final int BUFFER_SIZE = 1024; 61 private static final String VAR_OPEN = "${"; 62 private static final String VAR_CLOSE = "}"; 63 64 private static Log logger = LogFactory.getLog(RuntimeExec.class); 65 66 private String command; 67 private Map <String , String > defaultProperties; 68 private Set <Integer > errCodes; 69 70 73 public RuntimeExec() 74 { 75 defaultProperties = Collections.emptyMap(); 76 this.errCodes = new HashSet <Integer >(2); 78 errCodes.add(1); 79 errCodes.add(2); 80 } 81 82 87 public void setCommand(String command) 88 { 89 this.command = command; 90 } 91 92 99 public void setCommandMap(Map <String , String > commandsByOS) 100 { 101 String serverOs = System.getProperty(KEY_OS_NAME); 103 String command = commandsByOS.get(serverOs); 105 if (command == null) 106 { 107 for (String osName : commandsByOS.keySet()) 109 { 110 if (osName.equals(KEY_OS_DEFAULT)) 112 { 113 continue; 114 } 115 if (serverOs.matches(osName)) 117 { 118 command = commandsByOS.get(osName); 119 break; 120 } 121 } 122 } 123 if (command == null) 125 { 126 throw new AlfrescoRuntimeException( 127 "No command found for OS " + serverOs + " or '" + KEY_OS_DEFAULT + "': \n" + 128 " commands: " + commandsByOS); 129 } 130 this.command = command; 131 } 132 133 142 public void setDefaultProperties(Map <String , String > defaultProperties) 143 { 144 this.defaultProperties = defaultProperties; 145 } 146 147 153 public void setErrorCodes(String errCodesStr) 154 { 155 errCodes.clear(); 156 StringTokenizer tokenizer = new StringTokenizer (errCodesStr, " ,"); 157 while(tokenizer.hasMoreElements()) 158 { 159 String errCodeStr = tokenizer.nextToken(); 160 try 162 { 163 int errCode = Integer.parseInt(errCodeStr); 164 this.errCodes.add(errCode); 165 } 166 catch (NumberFormatException e) 167 { 168 throw new AlfrescoRuntimeException( 169 "Property 'errorCodes' must be comma-separated list of integers: " + errCodesStr); 170 } 171 } 172 } 173 174 179 public ExecutionResult execute() 180 { 181 return execute(defaultProperties); 182 } 183 184 192 public ExecutionResult execute(Map <String , String > properties) 193 { 194 if (command == null) 196 { 197 throw new AlfrescoRuntimeException("Runtime command has not been set: \n" + this); 198 } 199 200 Runtime runtime = Runtime.getRuntime(); 202 Process process = null; 203 String commandToExecute = null; 204 try 205 { 206 commandToExecute = getCommand(properties); 208 process = runtime.exec(commandToExecute); 209 } 210 catch (IOException e) 211 { 212 throw new AlfrescoRuntimeException("Failed to execute command: " + commandToExecute, e); 213 } 214 215 InputStreamReaderThread stdOutGobbler = new InputStreamReaderThread(process.getInputStream()); 217 InputStreamReaderThread stdErrGobbler = new InputStreamReaderThread(process.getErrorStream()); 218 219 stdOutGobbler.start(); 221 stdErrGobbler.start(); 222 223 int exitValue = 0; 225 try 226 { 227 exitValue = process.waitFor(); 228 } 229 catch (InterruptedException e) 230 { 231 stdErrGobbler.addToBuffer(e.toString()); 233 exitValue = 1; 234 } 235 236 stdOutGobbler.waitForCompletion(); 238 stdErrGobbler.waitForCompletion(); 239 240 String execOut = stdOutGobbler.getBuffer(); 242 String execErr = stdErrGobbler.getBuffer(); 243 244 ExecutionResult result = new ExecutionResult(commandToExecute, errCodes, exitValue, execOut, execErr); 246 247 if (logger.isDebugEnabled()) 249 { 250 logger.debug(result); 251 } 252 return result; 253 } 254 255 259 public String getCommand() 260 { 261 return getCommand(defaultProperties); 262 } 263 264 274 public String getCommand(Map <String , String > properties) 275 { 276 Map <String , String > execProperties = null; 277 if (properties == defaultProperties) 278 { 279 execProperties = defaultProperties; 281 } 282 else 283 { 284 execProperties = new HashMap <String , String >(defaultProperties); 285 execProperties.putAll(properties); 287 } 288 StringBuilder sb = new StringBuilder (command); 290 for (Map.Entry <String , String > entry : execProperties.entrySet()) 291 { 292 String key = entry.getKey(); 293 String value = entry.getValue(); 294 if (value == null) 296 { 297 value = ""; 298 } 299 key = (VAR_OPEN + key + VAR_CLOSE); 301 int index = sb.indexOf(key); 302 while (index > -1) 303 { 304 sb.replace(index, index + key.length(), value); 306 index = sb.indexOf(key, index + 1); 308 } 309 } 310 return sb.toString(); 312 } 313 314 public String toString() 315 { 316 StringBuffer sb = new StringBuffer (256); 317 sb.append("RuntimeExec:\n") 318 .append(" command: ").append(command).append("\n") 319 .append(" os: ").append(System.getProperty(KEY_OS_NAME)).append("\n"); 320 return sb.toString(); 321 } 322 323 328 public static class ExecutionResult 329 { 330 private final String command; 331 private final Set <Integer > errCodes; 332 private final int exitValue; 333 private final String stdOut; 334 private final String stdErr; 335 336 private ExecutionResult( 337 final String command, 338 final Set <Integer > errCodes, 339 final int exitValue, 340 final String stdOut, 341 final String stdErr) 342 { 343 this.command = command; 344 this.errCodes = errCodes; 345 this.exitValue = exitValue; 346 this.stdOut = stdOut; 347 this.stdErr = stdErr; 348 } 349 350 @Override 351 public String toString() 352 { 353 String out = stdOut.length() > 250 ? stdOut.substring(0, 250) : stdOut; 354 String err = stdErr.length() > 250 ? stdErr.substring(0, 250) : stdErr; 355 356 StringBuilder sb = new StringBuilder (128); 357 sb.append("Execution result: \n") 358 .append(" os: ").append(System.getProperty(KEY_OS_NAME)).append("\n") 359 .append(" command: ").append(command).append("\n") 360 .append(" succeeded: ").append(getSuccess()).append("\n") 361 .append(" exit code: ").append(exitValue).append("\n") 362 .append(" out: ").append(out).append("\n") 363 .append(" err: ").append(err); 364 return sb.toString(); 365 } 366 367 373 private boolean isFailureCode(int exitValue) 374 { 375 return errCodes.contains((Integer )exitValue); 376 } 377 378 382 public boolean getSuccess() 383 { 384 return !isFailureCode(exitValue); 385 } 386 387 public int getExitValue() 388 { 389 return exitValue; 390 } 391 392 public String getStdOut() 393 { 394 return stdOut; 395 } 396 397 public String getStdErr() 398 { 399 return stdErr; 400 } 401 } 402 403 409 public static class InputStreamReaderThread extends Thread 410 { 411 private InputStream is; 412 private StringBuffer buffer; private boolean isRunning; 414 private boolean completed; 415 416 420 public InputStreamReaderThread(InputStream is) 421 { 422 super(); 423 setDaemon(true); this.is = is; 425 this.buffer = new StringBuffer (BUFFER_SIZE); 426 this.isRunning = false; 427 this.completed = false; 428 } 429 430 public synchronized void run() 431 { 432 isRunning = true; 434 completed = false; 435 436 byte[] bytes = new byte[BUFFER_SIZE]; 437 InputStream tempIs = null; 438 try 439 { 440 tempIs = new BufferedInputStream (is, BUFFER_SIZE); 441 int count = -2; 442 while (count != -1) 443 { 444 if (count > 0) 446 { 447 String toWrite = new String (bytes, 0, count); 448 buffer.append(toWrite); 449 } 450 count = tempIs.read(bytes); 452 } 453 isRunning = false; 455 completed = true; 456 } 457 catch (IOException e) 458 { 459 throw new AlfrescoRuntimeException("Unable to read stream", e); 460 } 461 finally 462 { 463 if (tempIs != null) 465 { 466 try 467 { 468 tempIs.close(); 469 } 470 catch (Exception e) 471 { 472 } 473 } 474 } 475 } 476 477 482 public synchronized void waitForCompletion() 483 { 484 while (!completed && !isRunning) 485 { 486 try 487 { 488 this.wait(200L); } 491 catch (InterruptedException e) 492 { 493 } 494 } 495 } 496 497 500 public void addToBuffer(String msg) 501 { 502 buffer.append(msg); 503 } 504 505 public boolean isComplete() 506 { 507 return completed; 508 } 509 510 513 public String getBuffer() 514 { 515 return buffer.toString(); 516 } 517 } 518 } 519 | Popular Tags |