1 21 22 package org.continuent.sequoia.controller.backup.backupers; 23 24 import java.io.BufferedWriter ; 25 import java.io.File ; 26 import java.io.IOException ; 27 import java.io.OutputStream ; 28 import java.io.StringWriter ; 29 import java.util.ArrayList ; 30 import java.util.Timer ; 31 import java.util.TimerTask ; 32 33 import org.continuent.sequoia.common.log.Trace; 34 35 44 public class NativeCommandExec 45 { 46 47 private static final int THREAD_WAIT_MAX = 30 * 1000; 48 49 private static Trace logger = Trace 51 .getLogger(NativeCommandExec.class 52 .getName()); 53 54 ArrayList stdout; 56 ArrayList stderr; 57 58 class NativeCommand 60 { 61 String command; 62 String [] commands; 63 64 NativeCommand(String cmd) 66 { 67 this.command = cmd; 68 } 69 70 NativeCommand(String [] cmds) 72 { 73 this.commands = cmds; 74 } 75 76 boolean isString() 78 { 79 return (command != null); 80 } 81 82 String commandText() 84 { 85 if (isString()) 86 return command; 87 else 88 { 89 StringBuffer buf = new StringBuffer (); 91 for (int i = 0; i < commands.length; i++) 92 { 93 buf.append(commands[i] + " "); 94 } 95 return buf.toString(); 96 } 97 } 98 99 String getCommand() 101 { 102 return command; 103 } 104 105 String [] getCommands() 107 { 108 return commands; 109 } 110 } 111 112 115 public NativeCommandExec() 116 { 117 } 118 119 124 public ArrayList getStdout() 125 { 126 return stdout; 127 } 128 129 134 public ArrayList getStderr() 135 { 136 return stderr; 137 } 138 139 142 public void initOutput() 143 { 144 stdout = new ArrayList (); 145 stderr = new ArrayList (); 146 } 147 148 163 public boolean safelyExecNativeCommand(String cmd, 164 NativeCommandInputSource input, OutputStream output, int timeout, 165 File workingDirectory, boolean ignoreStdErrOutput) 166 { 167 NativeCommand nc = new NativeCommand(cmd); 168 return safelyExecNativeCommand0(nc, input, output, timeout, 169 workingDirectory, ignoreStdErrOutput); 170 } 171 172 176 public boolean safelyExecNativeCommand(String cmd, 177 NativeCommandInputSource input, OutputStream output, int timeout, 178 boolean ignoreStdErrOutput) 179 { 180 return safelyExecNativeCommand(cmd, input, output, timeout, null, 181 ignoreStdErrOutput); 182 } 183 184 199 public boolean safelyExecNativeCommand(String [] cmds, 200 NativeCommandInputSource input, OutputStream output, int timeout, 201 File workingDirectory, boolean ignoreStdErrOutput) 202 { 203 NativeCommand nc = new NativeCommand(cmds); 204 return safelyExecNativeCommand0(nc, input, output, timeout, 205 workingDirectory, ignoreStdErrOutput); 206 } 207 208 212 public boolean safelyExecNativeCommand(String [] cmds, 213 NativeCommandInputSource input, OutputStream output, int timeout, 214 boolean ignoreStdErrOutput) 215 { 216 return safelyExecNativeCommand(cmds, input, output, timeout, null, 217 ignoreStdErrOutput); 218 } 219 220 236 protected boolean safelyExecNativeCommand0(NativeCommand nc, 237 NativeCommandInputSource input, OutputStream output, int timeout, 238 File workingDirectory, boolean ignoreStdErrOutput) 239 { 240 boolean status; 241 try 242 { 243 int errorCount; 244 if (nc.isString()) 245 errorCount = executeNativeCommand(nc.getCommand(), input, output, 246 timeout, workingDirectory, ignoreStdErrOutput); 247 else 248 errorCount = executeNativeCommand(nc.getCommands(), input, output, 249 timeout, workingDirectory, ignoreStdErrOutput); 250 status = (errorCount == 0); 251 if (!status) 252 logger.warn("Native command failed with error count=" + errorCount); 253 } 254 catch (InterruptedException e) 255 { 256 logger.warn("Native command timed out: command=" + nc.commandText() 257 + " timeout=" + timeout); 258 status = false; 259 } 260 catch (IOException e) 261 { 262 logger.warn("Native command I/O failed: command=" + nc.commandText(), e); 263 status = false; 264 } 265 266 if (status == false) 268 { 269 logOutput(); 270 logErrors(); 271 } 272 273 return status; 274 } 275 276 289 protected int manageCommandExecution(String commandText, Process process, 290 NativeCommandInputSource inputSource, OutputStream output, int timeout, 291 boolean ignoreStdErrOutput) throws InterruptedException 292 { 293 if (logger.isInfoEnabled()) 294 { 295 logger.info("Starting execution of \"" + commandText + "\""); 296 } 297 298 NativeCommandOutputThread inStreamThread = new NativeCommandOutputThread( 300 process.getInputStream(), output); 301 NativeCommandOutputThread errStreamThread = new NativeCommandOutputThread( 302 process.getErrorStream(), null); 303 inStreamThread.start(); 304 errStreamThread.start(); 305 306 TimerTask task = null; 308 try 309 { 310 if (timeout > 0) 312 { 313 final Thread t = Thread.currentThread(); 314 task = new TimerTask () 315 { 316 public void run() 317 { 318 t.interrupt(); 319 } 320 }; 321 Timer timer = new Timer (); 322 timer.schedule(task, timeout * 1000); 323 } 324 325 if (inputSource != null) 327 { 328 OutputStream processOutput = process.getOutputStream(); 329 try 330 { 331 inputSource.write(processOutput); 332 } 333 catch (IOException e) 334 { 335 logger.warn("Writing of data to stdin halted by exception", e); 336 } 337 finally 338 { 339 try 340 { 341 inputSource.close(); 342 } 343 catch (IOException e) 344 { 345 logger.warn("Input source close operation generated exception", e); 346 } 347 try 348 { 349 processOutput.close(); 350 } 351 catch (IOException e) 352 { 353 logger.warn("Process stdin close operation generated exception", e); 354 } 355 } 356 } 357 358 process.waitFor(); 360 361 inStreamThread.join(THREAD_WAIT_MAX); 364 errStreamThread.join(THREAD_WAIT_MAX); 365 } 366 catch (InterruptedException e) 367 { 368 logger.warn("Command exceeded timeout: " + commandText); 369 process.destroy(); 370 throw e; 371 } 372 finally 373 { 374 if (task != null) 376 task.cancel(); 377 378 stderr = errStreamThread.getOutput(); 380 stdout = inStreamThread.getOutput(); 381 } 382 383 if (logger.isInfoEnabled()) 384 { 385 logger.info("Command \"" + commandText + "\" logged " + stderr.size() 386 + " errors and terminated with exitcode " + process.exitValue()); 387 } 388 389 if (ignoreStdErrOutput) 390 return process.exitValue(); 391 else 392 { 393 if (stderr.size() > 0) return -1; 395 else 396 return process.exitValue(); 397 } 398 } 399 400 415 public int executeNativeCommand(String command, 416 NativeCommandInputSource input, OutputStream output, int timeout, 417 File workingDirectory, boolean ignoreStdErrOutput) throws IOException , 418 InterruptedException 419 { 420 initOutput(); 421 Process process = Runtime.getRuntime() 422 .exec(command, null, workingDirectory); 423 return manageCommandExecution(command, process, input, output, timeout, 424 ignoreStdErrOutput); 425 } 426 427 431 public int executeNativeCommand(String command, 432 NativeCommandInputSource input, OutputStream output, int timeout, 433 boolean ignoreStdErrOutput) throws IOException , InterruptedException 434 { 435 return executeNativeCommand(command, input, output, timeout, null, 436 ignoreStdErrOutput); 437 } 438 439 454 public int executeNativeCommand(String [] commands, 455 NativeCommandInputSource input, OutputStream output, int timeout, 456 File workingDirectory, boolean ignoreStdErrOutput) throws IOException , 457 InterruptedException 458 { 459 initOutput(); 460 Process process = Runtime.getRuntime().exec(commands, null, 461 workingDirectory); 462 return manageCommandExecution(new NativeCommand(commands).commandText(), 463 process, input, output, timeout, ignoreStdErrOutput); 464 } 465 466 470 public int executeNativeCommand(String [] commands, 471 NativeCommandInputSource input, OutputStream output, int timeout, 472 boolean ignoreStdErrOutput) throws IOException , InterruptedException 473 { 474 return executeNativeCommand(commands, input, output, timeout, null, 475 ignoreStdErrOutput); 476 } 477 478 481 public void logOutput() 482 { 483 log("stdout", stdout); 484 } 485 486 489 public void logErrors() 490 { 491 log("stderr", stderr); 492 } 493 494 500 protected void log(String name, ArrayList outArray) 501 { 502 StringWriter sw = new StringWriter (); 503 BufferedWriter writer = new BufferedWriter (sw); 504 if (outArray != null) 505 { 506 int arraySize = outArray.size(); 507 for (int i = 0; i < arraySize; i++) 508 { 509 String line = (String ) outArray.get(i); 510 try 511 { 512 writer.newLine(); 513 writer.write(line); 514 } 515 catch (IOException e) 516 { 517 logger.error( 519 "Unexpected exception while trying to log process output", e); 520 } 521 } 522 } 523 524 try 526 { 527 writer.flush(); 528 writer.close(); 529 } 530 catch (IOException e) 531 { 532 } 533 534 String outText = sw.toString(); 535 logger.info("Process output (" + name + "):" + outText); 536 } 537 } | Popular Tags |