1 18 package org.apache.tools.ant.taskdefs; 19 20 import java.io.File ; 21 import java.io.Reader ; 22 import java.io.InputStream ; 23 import java.io.IOException ; 24 import java.io.PrintStream ; 25 import java.io.OutputStream ; 26 import java.io.StringReader ; 27 import java.io.BufferedReader ; 28 import java.io.InputStreamReader ; 29 import java.io.PipedOutputStream ; 30 import java.io.ByteArrayInputStream ; 31 import java.io.ByteArrayOutputStream ; 32 import java.util.Arrays ; 33 import java.util.Vector ; 34 35 import org.apache.tools.ant.Project; 36 import org.apache.tools.ant.ProjectComponent; 37 import org.apache.tools.ant.Task; 38 import org.apache.tools.ant.BuildException; 39 import org.apache.tools.ant.filters.util.ChainReaderHelper; 40 import org.apache.tools.ant.util.StringUtils; 41 import org.apache.tools.ant.util.TeeOutputStream; 42 import org.apache.tools.ant.util.ReaderInputStream; 43 import org.apache.tools.ant.util.LeadPipeInputStream; 44 import org.apache.tools.ant.util.LazyFileOutputStream; 45 import org.apache.tools.ant.util.OutputStreamFunneler; 46 import org.apache.tools.ant.util.ConcatFileInputStream; 47 import org.apache.tools.ant.util.KeepAliveOutputStream; 48 49 55 public class Redirector { 56 57 private static final String DEFAULT_ENCODING 58 = System.getProperty("file.encoding"); 59 60 private class PropertyOutputStream extends ByteArrayOutputStream { 61 private String property; 62 private boolean closed = false; 63 64 PropertyOutputStream(String property) { 65 super(); 66 this.property = property; 67 } 68 69 public void close() throws IOException { 70 if (!closed && !(append && appendProperties)) { 71 setPropertyFromBAOS(this, property); 72 closed = true; 73 } 74 } 75 } 76 77 81 private File [] input; 82 83 87 private File [] out; 88 89 92 private File [] error; 93 94 99 private boolean logError = false; 100 101 104 private PropertyOutputStream baos = null; 105 106 109 private PropertyOutputStream errorBaos = null; 110 111 112 private String outputProperty; 113 114 115 private String errorProperty; 116 117 118 private String inputString; 119 120 121 private boolean append = false; 122 123 124 private boolean alwaysLog = false; 125 126 127 private boolean createEmptyFiles = true; 128 129 130 private ProjectComponent managingTask; 131 132 133 private OutputStream outputStream = null; 134 135 136 private OutputStream errorStream = null; 137 138 139 private InputStream inputStream = null; 140 141 142 private PrintStream outPrintStream = null; 143 144 145 private PrintStream errorPrintStream = null; 146 147 148 private Vector outputFilterChains; 149 150 151 private Vector errorFilterChains; 152 153 154 private Vector inputFilterChains; 155 156 157 private String outputEncoding = DEFAULT_ENCODING; 158 159 160 private String errorEncoding = DEFAULT_ENCODING; 161 162 163 private String inputEncoding = DEFAULT_ENCODING; 164 165 166 private boolean appendProperties = true; 167 168 169 private ThreadGroup threadGroup = new ThreadGroup ("redirector"); 170 171 172 private boolean logInputString = true; 173 174 179 public Redirector(Task managingTask) { 180 this((ProjectComponent) managingTask); 181 } 182 183 190 public Redirector(ProjectComponent managingTask) { 191 this.managingTask = managingTask; 192 } 193 194 199 public void setInput(File input) { 200 setInput((input == null) ? null : new File [] {input}); 201 } 202 203 208 public synchronized void setInput(File [] input) { 209 this.input = input; 210 } 211 212 217 public synchronized void setInputString(String inputString) { 218 this.inputString = inputString; 219 } 220 221 227 public void setLogInputString(boolean logInputString) { 228 this.logInputString = logInputString; 229 } 230 231 237 void setInputStream(InputStream inputStream) { 238 this.inputStream = inputStream; 239 } 240 241 247 public void setOutput(File out) { 248 setOutput((out == null) ? null : new File [] {out}); 249 } 250 251 257 public synchronized void setOutput(File [] out) { 258 this.out = out; 259 } 260 261 266 public synchronized void setOutputEncoding(String outputEncoding) { 267 if (outputEncoding == null) { 268 throw new IllegalArgumentException ( 269 "outputEncoding must not be null"); 270 } else { 271 this.outputEncoding = outputEncoding; 272 } 273 } 274 275 280 public synchronized void setErrorEncoding(String errorEncoding) { 281 if (errorEncoding == null) { 282 throw new IllegalArgumentException ( 283 "errorEncoding must not be null"); 284 } else { 285 this.errorEncoding = errorEncoding; 286 } 287 } 288 289 294 public synchronized void setInputEncoding(String inputEncoding) { 295 if (inputEncoding == null) { 296 throw new IllegalArgumentException ( 297 "inputEncoding must not be null"); 298 } else { 299 this.inputEncoding = inputEncoding; 300 } 301 } 302 303 311 public synchronized void setLogError(boolean logError) { 312 this.logError = logError; 313 } 314 315 322 public synchronized void setAppendProperties(boolean appendProperties) { 323 this.appendProperties = appendProperties; 324 } 325 326 331 public void setError(File error) { 332 setError((error == null) ? null : new File [] {error}); 333 } 334 335 340 public synchronized void setError(File [] error) { 341 this.error = error; 342 } 343 344 351 public synchronized void setOutputProperty(String outputProperty) { 352 if (outputProperty == null 353 || !(outputProperty.equals(this.outputProperty))) { 354 this.outputProperty = outputProperty; 355 baos = null; 356 } 357 } 358 359 366 public synchronized void setAppend(boolean append) { 367 this.append = append; 368 } 369 370 377 public synchronized void setAlwaysLog(boolean alwaysLog) { 378 this.alwaysLog = alwaysLog; 379 } 380 381 386 public synchronized void setCreateEmptyFiles(boolean createEmptyFiles) { 387 this.createEmptyFiles = createEmptyFiles; 388 } 389 390 397 public synchronized void setErrorProperty(String errorProperty) { 398 if (errorProperty == null 399 || !(errorProperty.equals(this.errorProperty))) { 400 this.errorProperty = errorProperty; 401 errorBaos = null; 402 } 403 } 404 405 410 public synchronized void setInputFilterChains(Vector inputFilterChains) { 411 this.inputFilterChains = inputFilterChains; 412 } 413 414 419 public synchronized void setOutputFilterChains(Vector outputFilterChains) { 420 this.outputFilterChains = outputFilterChains; 421 } 422 423 428 public synchronized void setErrorFilterChains(Vector errorFilterChains) { 429 this.errorFilterChains = errorFilterChains; 430 } 431 432 440 private void setPropertyFromBAOS(ByteArrayOutputStream baos, 441 String propertyName) throws IOException { 442 443 BufferedReader in 444 = new BufferedReader (new StringReader (Execute.toString(baos))); 445 String line = null; 446 StringBuffer val = new StringBuffer (); 447 while ((line = in.readLine()) != null) { 448 if (val.length() != 0) { 449 val.append(StringUtils.LINE_SEP); 450 } 451 val.append(line); 452 } 453 managingTask.getProject().setNewProperty(propertyName, val.toString()); 454 } 455 456 460 public synchronized void createStreams() { 461 if (out != null && out.length > 0) { 462 String logHead = new StringBuffer ("Output ").append( 463 ((append) ? "appended" : "redirected")).append( 464 " to ").toString(); 465 outputStream = foldFiles(out, logHead, Project.MSG_VERBOSE); 466 } 467 if (outputProperty != null) { 468 if (baos == null) { 469 baos = new PropertyOutputStream(outputProperty); 470 managingTask.log("Output redirected to property: " 471 + outputProperty, Project.MSG_VERBOSE); 472 } 473 OutputStream keepAliveOutput = new KeepAliveOutputStream(baos); 475 outputStream = (outputStream == null) ? keepAliveOutput 476 : new TeeOutputStream(outputStream, keepAliveOutput); 477 } else { 478 baos = null; 479 } 480 481 if (error != null && error.length > 0) { 482 String logHead = new StringBuffer ("Error ").append( 483 ((append) ? "appended" : "redirected")).append( 484 " to ").toString(); 485 errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE); 486 } else if (!(logError || outputStream == null)) { 487 long funnelTimeout = 0L; 488 OutputStreamFunneler funneler 489 = new OutputStreamFunneler(outputStream, funnelTimeout); 490 try { 491 outputStream = funneler.getFunnelInstance(); 492 errorStream = funneler.getFunnelInstance(); 493 } catch (IOException eyeOhEx) { 494 throw new BuildException( 495 "error splitting output/error streams", eyeOhEx); 496 } 497 } 498 if (errorProperty != null) { 499 if (errorBaos == null) { 500 errorBaos = new PropertyOutputStream(errorProperty); 501 managingTask.log("Error redirected to property: " + errorProperty, 502 Project.MSG_VERBOSE); 503 } 504 OutputStream keepAliveError = new KeepAliveOutputStream(errorBaos); 506 errorStream = (error == null || error.length == 0) ? keepAliveError 507 : new TeeOutputStream(errorStream, keepAliveError); 508 } else { 509 errorBaos = null; 510 } 511 if (alwaysLog || outputStream == null) { 512 OutputStream outputLog 513 = new LogOutputStream(managingTask, Project.MSG_INFO); 514 outputStream = (outputStream == null) 515 ? outputLog : new TeeOutputStream(outputLog, outputStream); 516 } 517 if (alwaysLog || errorStream == null) { 518 OutputStream errorLog 519 = new LogOutputStream(managingTask, Project.MSG_WARN); 520 errorStream = (errorStream == null) 521 ? errorLog : new TeeOutputStream(errorLog, errorStream); 522 } 523 if ((outputFilterChains != null && outputFilterChains.size() > 0) 524 || !(outputEncoding.equalsIgnoreCase(inputEncoding))) { 525 try { 526 LeadPipeInputStream snk = new LeadPipeInputStream(); 527 snk.setManagingComponent(managingTask); 528 529 InputStream outPumpIn = snk; 530 531 Reader reader = new InputStreamReader (outPumpIn, inputEncoding); 532 533 if (outputFilterChains != null && outputFilterChains.size() > 0) { 534 ChainReaderHelper helper = new ChainReaderHelper(); 535 helper.setProject(managingTask.getProject()); 536 helper.setPrimaryReader(reader); 537 helper.setFilterChains(outputFilterChains); 538 reader = helper.getAssembledReader(); 539 } 540 outPumpIn = new ReaderInputStream(reader, outputEncoding); 541 542 Thread t = new Thread (threadGroup, new StreamPumper( 543 outPumpIn, outputStream, true), "output pumper"); 544 t.setPriority(Thread.MAX_PRIORITY); 545 outputStream = new PipedOutputStream (snk); 546 t.start(); 547 } catch (IOException eyeOhEx) { 548 throw new BuildException( 549 "error setting up output stream", eyeOhEx); 550 } 551 } 552 553 if ((errorFilterChains != null && errorFilterChains.size() > 0) 554 || !(errorEncoding.equalsIgnoreCase(inputEncoding))) { 555 try { 556 LeadPipeInputStream snk = new LeadPipeInputStream(); 557 snk.setManagingComponent(managingTask); 558 559 InputStream errPumpIn = snk; 560 561 Reader reader = new InputStreamReader (errPumpIn, inputEncoding); 562 563 if (errorFilterChains != null && errorFilterChains.size() > 0) { 564 ChainReaderHelper helper = new ChainReaderHelper(); 565 helper.setProject(managingTask.getProject()); 566 helper.setPrimaryReader(reader); 567 helper.setFilterChains(errorFilterChains); 568 reader = helper.getAssembledReader(); 569 } 570 errPumpIn = new ReaderInputStream(reader, errorEncoding); 571 572 Thread t = new Thread (threadGroup, new StreamPumper( 573 errPumpIn, errorStream, true), "error pumper"); 574 t.setPriority(Thread.MAX_PRIORITY); 575 errorStream = new PipedOutputStream (snk); 576 t.start(); 577 } catch (IOException eyeOhEx) { 578 throw new BuildException( 579 "error setting up error stream", eyeOhEx); 580 } 581 } 582 583 if (input != null && input.length > 0) { 587 managingTask.log("Redirecting input from file" 588 + ((input.length == 1) ? "" : "s"), Project.MSG_VERBOSE); 589 try { 590 inputStream = new ConcatFileInputStream(input); 591 } catch (IOException eyeOhEx) { 592 throw new BuildException(eyeOhEx); 593 } 594 ((ConcatFileInputStream) inputStream).setManagingComponent(managingTask); 595 } else if (inputString != null) { 596 StringBuffer buf = new StringBuffer ("Using input "); 597 if (logInputString) { 598 buf.append('"').append(inputString).append('"'); 599 } else { 600 buf.append("string"); 601 } 602 managingTask.log(buf.toString(), Project.MSG_VERBOSE); 603 inputStream = new ByteArrayInputStream (inputString.getBytes()); 604 } 605 606 if (inputStream != null 607 && inputFilterChains != null && inputFilterChains.size() > 0) { 608 ChainReaderHelper helper = new ChainReaderHelper(); 609 helper.setProject(managingTask.getProject()); 610 try { 611 helper.setPrimaryReader( 612 new InputStreamReader (inputStream, inputEncoding)); 613 } catch (IOException eyeOhEx) { 614 throw new BuildException( 615 "error setting up input stream", eyeOhEx); 616 } 617 helper.setFilterChains(inputFilterChains); 618 inputStream = new ReaderInputStream( 619 helper.getAssembledReader(), inputEncoding); 620 } 621 } 622 623 631 public synchronized ExecuteStreamHandler createHandler() 632 throws BuildException { 633 createStreams(); 634 return new PumpStreamHandler(outputStream, errorStream, inputStream); 635 } 636 637 642 protected synchronized void handleOutput(String output) { 643 if (outPrintStream == null) { 644 outPrintStream = new PrintStream (outputStream); 645 } 646 outPrintStream.print(output); 647 } 648 649 660 protected synchronized int handleInput(byte[] buffer, int offset, 661 int length) throws IOException { 662 if (inputStream == null) { 663 return managingTask.getProject().defaultInput(buffer, offset, 664 length); 665 } else { 666 return inputStream.read(buffer, offset, length); 667 } 668 } 669 670 675 protected synchronized void handleFlush(String output) { 676 if (outPrintStream == null) { 677 outPrintStream = new PrintStream (outputStream); 678 } 679 outPrintStream.print(output); 680 outPrintStream.flush(); 681 } 682 683 688 protected synchronized void handleErrorOutput(String output) { 689 if (errorPrintStream == null) { 690 errorPrintStream = new PrintStream (errorStream); 691 } 692 errorPrintStream.print(output); 693 } 694 695 700 protected synchronized void handleErrorFlush(String output) { 701 if (errorPrintStream == null) { 702 errorPrintStream = new PrintStream (errorStream); 703 } 704 errorPrintStream.print(output); 705 } 706 707 713 public synchronized OutputStream getOutputStream() { 714 return outputStream; 715 } 716 717 723 public synchronized OutputStream getErrorStream() { 724 return errorStream; 725 } 726 727 733 public synchronized InputStream getInputStream() { 734 return inputStream; 735 } 736 737 746 public synchronized void complete() throws IOException { 747 System.out.flush(); 748 System.err.flush(); 749 750 if (inputStream != null) { 751 inputStream.close(); 752 } 753 754 outputStream.flush(); 755 outputStream.close(); 756 757 errorStream.flush(); 758 errorStream.close(); 759 760 while (threadGroup.activeCount() > 0) { 762 try { 763 managingTask.log("waiting for " + threadGroup.activeCount() 764 + " Threads:", Project.MSG_DEBUG); 765 Thread [] thread = new Thread [threadGroup.activeCount()]; 766 threadGroup.enumerate(thread); 767 for (int i = 0; i < thread.length && thread[i] != null; i++) { 768 try { 769 managingTask.log(thread[i].toString(), Project.MSG_DEBUG); 770 } catch (NullPointerException enPeaEx) { 771 } 773 } 774 wait(1000); 775 } catch (InterruptedException eyeEx) { 776 } 778 } 779 780 setProperties(); 781 782 inputStream = null; 783 outputStream = null; 784 errorStream = null; 785 outPrintStream = null; 786 errorPrintStream = null; 787 } 788 789 793 public synchronized void setProperties() { 794 if (baos != null) { 795 try { 796 baos.close(); 797 } catch (IOException eyeOhEx) { 798 } 800 } 801 if (errorBaos != null) { 802 try { 803 errorBaos.close(); 804 } catch (IOException eyeOhEx) { 805 } 807 } 808 } 809 810 private OutputStream foldFiles(File [] file, String logHead, int loglevel) { 811 OutputStream result 812 = new LazyFileOutputStream(file[0], append, createEmptyFiles); 813 814 managingTask.log(logHead + file[0], loglevel); 815 char[] c = new char[logHead.length()]; 816 Arrays.fill(c, ' '); 817 String indent = new String (c); 818 819 for (int i = 1; i < file.length; i++) { 820 outputStream = new TeeOutputStream(outputStream, 821 new LazyFileOutputStream(file[i], append, createEmptyFiles)); 822 managingTask.log(indent + file[i], loglevel); 823 } 824 return result; 825 } 826 } 827 | Popular Tags |