1 23 24 package com.sun.enterprise.util; 25 26 import java.io.File ; 28 import java.io.IOException ; 29 import java.io.InputStream ; 30 import java.io.BufferedInputStream ; 31 import java.io.FileInputStream ; 32 import java.io.OutputStream ; 33 import java.io.BufferedOutputStream ; 34 import java.io.FileOutputStream ; 35 import java.io.PrintWriter ; 36 import java.io.BufferedWriter ; 37 import java.io.OutputStreamWriter ; 38 import java.io.BufferedReader ; 39 import java.io.InputStreamReader ; 40 import java.io.Reader ; 41 import java.io.FileReader ; 42 import java.io.RandomAccessFile ; 43 import java.util.ArrayList ; 44 import java.lang.IllegalArgumentException ; 45 49 50 public class ProcessExecutor 51 { 52 public static final long kDefaultTimeoutMillis = 600000; 53 public static final long kSleepTime = 2000; 54 private static final long DEFAULT_TIMEOUT_SEC = 600; 55 private static final String NEWLINE = System.getProperty("line.separator"); 56 private long mTimeoutMilliseconds = 0; 57 protected String [] mCmdStrings = null; 58 protected File mOutFile = null; 59 protected File mErrFile = null; 60 private OutputStream mOutStream = null; 61 private OutputStream mErrStream = null; 62 63 private File mWorkingDir = null; private String [] mEnv = null; private String [] mInputLines = null; private int mExitValue = -1; 67 private Process mSubProcess=null; private boolean mVerboseMode = false; 69 private boolean retainExecutionLogs = false; 70 private String lastExecutionOutputString = null; 71 private String lastExecutionErrorString = null; 72 private static boolean bDebug=false; 73 74 77 public ProcessExecutor(String [] cmd) 78 { 79 this(cmd, DEFAULT_TIMEOUT_SEC, null); 80 } 81 82 85 public ProcessExecutor(String [] cmd, String [] inputLines) 86 { 87 this(cmd, DEFAULT_TIMEOUT_SEC, inputLines); 88 } 89 90 93 public ProcessExecutor(String [] cmd, long timeoutSeconds) 94 { 95 this(cmd, timeoutSeconds, null); 96 } 97 98 public ProcessExecutor(String [] cmd, long timeoutSeconds, String [] inputLines) 99 { 100 this(cmd, timeoutSeconds, inputLines, null, null); 101 } 102 103 110 111 public ProcessExecutor(String [] cmd, long timeoutSeconds, String [] inputLines, 112 String [] env, File workingDir) 113 { 114 mCmdStrings = cmd; 115 mInputLines = inputLines; 116 mEnv = env; 117 mWorkingDir = workingDir; 118 char fwdSlashChar = '/'; 119 char backSlashChar = '\\'; 120 121 if (System.getProperty("Debug") != null) { 122 bDebug=true; 125 } 126 127 for(int i=0; i<mCmdStrings.length; i++) 128 { 129 if (OS.isUnix()) 130 { 131 mCmdStrings[i] = mCmdStrings[i].replace(backSlashChar, fwdSlashChar); 132 } 133 else 134 { 135 mCmdStrings[i] = mCmdStrings[i].replace(fwdSlashChar, backSlashChar); 136 } 137 } 138 mTimeoutMilliseconds = (long) timeoutSeconds * 1000; 139 } 140 141 147 public void setExecutionRetentionFlag(final boolean s) { 148 this.retainExecutionLogs = s; 149 } 150 public boolean getExecutionRetentionFlag() { 151 return ( this.retainExecutionLogs ); 152 } 153 157 public String getLastExecutionError() { 158 return ( this.lastExecutionErrorString ); 159 } 160 164 public String getLastExecutionOutput() { 165 return ( this.lastExecutionOutputString ); 166 } 167 private void init() throws ExecException 168 { 169 try{ 170 mOutFile = File.createTempFile("stdout", null); 171 mOutFile.deleteOnExit(); 172 mErrFile = File.createTempFile("stderr", null); 173 mErrFile.deleteOnExit(); 174 } 175 catch (IllegalArgumentException iae){ 176 deleteTempFiles(); 177 throw new ExecException("Internal error (util.ProcessExecutor.init()): "+iae.getMessage()); 178 } 179 catch (IOException ioe){ 180 deleteTempFiles(); 181 throw new ExecException(cannotCreateTempFiles()); 182 } 183 } 184 185 private final static String cannotCreateTempFiles(){ 186 return "Could not create temporary files - check " 187 + System.getProperty("java.io.tmpdir") 188 + " to see if its writeable and not-full"; 189 } 190 191 192 private void deleteTempFiles(){ 193 if (mOutStream != null) { 194 try { 195 mOutStream.flush(); 196 mOutStream.close(); 197 } catch (IOException ioe) { 198 } 200 } 201 202 if (mErrStream != null) { 203 try { 204 mErrStream.flush(); 205 mErrStream.close(); 206 } catch (IOException ioe) { 207 } 209 } 210 if (mOutFile != null) mOutFile.delete(); 211 if (mErrFile != null) mErrFile.delete(); 212 } 213 214 public void execute() throws ExecException 215 { 216 execute(false); 217 } 218 219 220 230 231 public String [] execute(boolean bReturnOutputLines) throws ExecException 232 { 233 return execute(bReturnOutputLines, true); 234 } 235 236 237 242 protected String getExceptionMessage() 243 { 244 245 String errorMessage = getFileBuffer(mErrFile); 246 if (errorMessage.length() == 0) { 247 errorMessage = "The Process Output: " + getLatestOutput(mOutFile); 248 } 249 return "abnormal subprocess termination: Detailed Message:" + errorMessage; 250 } 251 252 262 263 public String [] execute(boolean bReturnOutputLines, boolean bStartUpTimeLimit) throws ExecException 264 { 265 init(); 266 InputStream inputStream = null; 267 try 268 { 269 270 if (bDebug) { 271 System.out.println("\n**** Executing command:"); 272 for(int ii=0; ii < mCmdStrings.length; ii++) { 273 System.out.println(mCmdStrings[ii]); 274 } 275 } 276 277 mSubProcess = Runtime.getRuntime().exec(mCmdStrings, mEnv, mWorkingDir); 278 if(mInputLines != null) 279 addInputLinesToProcessInput(mSubProcess); 280 if(!bReturnOutputLines) 281 mOutStream = redirectProcessOutput(mSubProcess); 282 else 283 inputStream = mSubProcess.getInputStream(); mErrStream = redirectProcessError(mSubProcess); 285 286 if (bStartUpTimeLimit) { 289 long timeBefore = System.currentTimeMillis(); 290 boolean timeoutReached = false; 291 boolean isSubProcessFinished = false; 292 boolean shouldBeDone = false; 293 while (! shouldBeDone) 294 { 295 sleep(kSleepTime); 296 long timeAfter = System.currentTimeMillis(); 297 timeoutReached = (timeAfter - timeBefore) >= mTimeoutMilliseconds; 298 try 299 { 300 mExitValue = mSubProcess.exitValue(); 301 isSubProcessFinished = true; 302 } 303 catch(IllegalThreadStateException itse) 304 { 305 isSubProcessFinished = false; 306 } 308 shouldBeDone = timeoutReached || isSubProcessFinished; 309 } 310 if (!isSubProcessFinished) 311 { 312 mSubProcess.destroy(); 313 mExitValue = -255; 314 throw new ExecException("Subprocess timed out after "+mTimeoutMilliseconds +"mS"); 315 } 316 else 317 { 318 mExitValue = mSubProcess.exitValue(); 319 if (debug()) { 320 System.out.println("Subprocess command line = " + a2s(mCmdStrings)); 321 System.out.println("Subprocess exit value = " + mExitValue); 322 } 323 if (mExitValue != 0) 324 { 325 mExitValue = mSubProcess.exitValue(); 326 if (mExitValue != 0) 327 { 328 throw new ExecException(getExceptionMessage()); 329 } 330 } 331 } 332 } 333 } 334 catch(SecurityException se) 335 { 336 throw new ExecException(se.getMessage()); 337 } 338 catch(IOException ioe) 339 { 340 throw new ExecException(ioe.getMessage()); 341 } 342 finally { 343 344 retainBuffers(); 346 347 if (bStartUpTimeLimit) { 350 deleteTempFiles(); 351 } 352 } 353 354 if(bReturnOutputLines) { 355 return getInputStrings(inputStream); 356 } else { 357 return null; 358 } 359 360 } 361 362 368 public int getProcessExitValue() { 369 return mExitValue; 370 } 371 372 private void addInputLinesToProcessInput(Process subProcess) throws ExecException { 373 if(mInputLines==null) 374 return; 375 376 PrintWriter out = null; 377 try 378 { 379 out = new PrintWriter (new BufferedWriter ( 380 new OutputStreamWriter (subProcess.getOutputStream()))); 381 382 for(int i=0; i<mInputLines.length; i++) 383 { 384 if(bDebug) { 385 System.out.println("InputLine ->" + mInputLines[i] + "<-"); 386 } 387 out.println(mInputLines[i]); 388 } 389 out.flush(); 390 } 391 catch (Exception e) 392 { 393 throw new ExecException(e.getMessage()); 394 } 395 finally 396 { 397 try 398 { 399 out.close(); 400 } 401 catch (Throwable t) 402 { 403 } 404 } 405 } 406 407 private String [] getInputStrings(InputStream inputStream) throws ExecException 408 { 409 if(inputStream==null) 410 return null; 411 BufferedReader in = null; 412 ArrayList list = new ArrayList (); 413 String str; 414 try 415 { 416 in = new BufferedReader ( new InputStreamReader (inputStream)); 417 while((str=in.readLine())!=null) 418 list.add(str); 419 if(list.size()<1) 420 return null; 421 return (String [])list.toArray(new String [list.size()]); 422 423 } 424 catch (Exception e) 425 { 426 throw new ExecException(e.getMessage()); 427 } 428 finally 429 { 430 try 431 { 432 in.close(); 433 } 434 catch (Throwable t) 435 { 436 } 437 } 438 } 439 440 private OutputStream redirectProcessOutput(Process subProcess) throws ExecException 441 { 442 OutputStream out = null; 443 try 444 { 445 InputStream in = subProcess.getInputStream(); 446 if(mVerboseMode) { 448 out=System.err; 450 } else { 451 out=new FileOutputStream (mOutFile); 453 } 454 455 new FlusherThread(in, out).start(); 456 } 457 catch (Exception e) 458 { 459 throw new ExecException(e.getMessage()); 460 } 461 return out; 462 } 463 464 private OutputStream redirectProcessError(Process subProcess) throws ExecException 465 { 466 OutputStream out = null; 467 try 468 { 469 InputStream in = subProcess.getErrorStream(); 470 if(mVerboseMode) { 472 out=System.err; 474 } else { 475 out=new FileOutputStream (mErrFile); 477 } 478 new FlusherThread(in, out).start(); 479 } 480 catch (Exception e) 481 { 482 throw new ExecException(e.getMessage()); 483 } 484 return out; 485 } 486 487 public void setVerbose(boolean verbose) { 488 mVerboseMode=verbose; 489 } 490 491 private void sleep (long millis) 492 { 493 try 494 { 495 Thread.sleep(millis); 496 } 497 catch(InterruptedException ie) 498 { 499 } 501 } 502 503 507 protected String getFileBuffer(File file) { 508 final StringBuffer sb = new StringBuffer (); 509 BufferedReader reader = null; 510 try { 511 reader = new BufferedReader (new FileReader (file)); 512 String line = null; 513 while ((line = reader.readLine()) != null) { 514 sb.append(line); 515 sb.append(NEWLINE); 516 } 517 } 518 catch(Exception e) { 519 } 521 finally { 522 try { 523 reader.close(); 524 } 525 catch(Exception e) {} 526 } 527 return ( sb.toString() ); 528 } 529 protected String getLatestOutput(final File f) { 530 return ( new RAFileReader(f).readLastBytesAsString() ); 531 } 532 533 public void retainBuffers() { 534 if (this.retainExecutionLogs) { 535 this.lastExecutionErrorString = this.getLatestOutput(this.mErrFile); 536 this.lastExecutionOutputString = this.getLatestOutput(this.mOutFile); 537 } 538 } 539 540 private boolean debug() { 541 final String td = System.getProperty("java.io.tmpdir"); 542 final String n = "as_debug_process_executor"; final File f = new File (td, n); 544 return ( f.exists() ); 545 } 546 private String a2s(String [] a) { 547 final StringBuffer s = new StringBuffer (); 548 if (a != null) { 549 for (int i = 0 ; i < a.length ; i++) { 550 s.append(a[i]); 551 s.append(" "); 552 } 553 } 554 return ( s.toString() ); 555 } 556 private static class RAFileReader { 557 final File file; 558 final int LAST_BYTES = 4096; 559 final String RMODE = "r"; 561 RAFileReader(final File file) { 562 this.file= file; 563 } 564 565 String readLastBytesAsString() { 566 final int n = getNumberOfBytes(LAST_BYTES); 567 final StringBuffer sb = new StringBuffer (); 568 final long ln = file.length(); if (ln == 0) 570 return ( sb.toString() ); assert (n <= ln) : ("Asked to read number of bytes more than size of file"); 572 final long s = ln - n; 573 return ( readWithoutCheck(s) ); 574 } 575 576 private String readWithoutCheck(final long seekPos) { 577 final StringBuffer sb = new StringBuffer (); 578 RandomAccessFile rf = null; 579 long ln = 0L; 580 int lines = 0; 581 try { 582 rf = new RandomAccessFile (file, RMODE); 583 ln = rf.length(); 584 rf.seek(seekPos); 585 String tmp = rf.readLine(); 586 while (tmp != null) { 587 lines++; 588 sb.append(tmp); 589 sb.append('\n'); tmp = rf.readLine(); 592 } 593 } 594 catch (Exception e) { 595 } 597 finally { 598 try { 599 if (rf != null) 600 rf.close(); 601 } 602 catch(Exception e) {} } 604 return ( sb.toString() ); 609 } 610 611 private int getNumberOfBytes(final int max) { 612 final long ln = file.length(); 613 return ( max >= ln ? (int)ln : max ); 614 } 615 } 616 617 public Process getSubProcess() { 619 return mSubProcess; 620 } 621 622 public static void main(String args[]) 623 { 624 testProcessError(); 625 } 626 627 630 private static void testProcessError() { 631 ProcessExecutor executor = new ProcessExecutor( 632 new String []{"/usr/bin/ls", "-wrongPARAMS123"}); 633 try { 634 executor.execute(); 635 } 636 catch (ExecException ee) { 637 System.out.println(ee.getMessage()); 638 } 639 } 640 } 641 642 643 646 class FlusherThread extends Thread { 647 InputStream mInStream = null; 648 OutputStream mOutStream = null; 649 650 public static final int kSize = 1024; 651 652 FlusherThread(InputStream in, OutputStream out) { 653 mInStream = in; 654 mOutStream = out; 655 } 656 657 public void run() { 658 if (mInStream == null) return; 660 661 try { 663 int byteCnt=0; 664 byte[] buffer=new byte[4096]; 665 while ((byteCnt=mInStream.read(buffer)) != -1) { 666 if (mOutStream != null && byteCnt > 0) { 667 mOutStream.write(buffer, 0, byteCnt); 668 mOutStream.flush(); 669 } 670 yield(); 671 } 672 } catch (IOException e) { 673 } finally { 675 try { 676 mOutStream.close(); 677 } catch (IOException ioe) { 678 } 680 } 681 } 682 } 683 | Popular Tags |