Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 485   Methods: 21
NCLOC: 210   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Redirector.java 35.7% 37.9% 38.1% 37.3%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 package org.apache.tools.ant.taskdefs;
 55   
 
 56   
 import java.io.BufferedReader;
 57   
 import java.io.ByteArrayOutputStream;
 58   
 import java.io.ByteArrayInputStream;
 59   
 import java.io.File;
 60   
 import java.io.FileNotFoundException;
 61   
 import java.io.FileOutputStream;
 62   
 import java.io.FileInputStream;
 63   
 import java.io.IOException;
 64   
 import java.io.StringReader;
 65   
 import java.io.OutputStream;
 66   
 import java.io.InputStream;
 67   
 import java.io.PrintStream;
 68   
 import org.apache.tools.ant.BuildException;
 69   
 import org.apache.tools.ant.Project;
 70   
 import org.apache.tools.ant.Task;
 71   
 import org.apache.tools.ant.util.StringUtils;
 72   
 import org.apache.tools.ant.util.TeeOutputStream;
 73   
 
 74   
 /**
 75   
  * The Redirector class manages the setup and connection of 
 76   
  * input and output redirection for an Ant task.
 77   
  *
 78   
  * @author Conor MacNeill
 79   
  * @since Ant 1.6
 80   
  */
 81   
 public class Redirector {
 82   
     /** 
 83   
      * The file receiveing standard output. Will also receive standard error
 84   
      * unless standard error is redirected or logError is true.
 85   
      */
 86   
     private File out;
 87   
     
 88   
     /**
 89   
      * The file to which standard error is being redirected 
 90   
      */
 91   
     private File error;
 92   
     
 93   
     /** 
 94   
      * The file from which standard input is being taken.
 95   
      */
 96   
     private File input;
 97   
 
 98   
     /** 
 99   
       * Indicates if standard error should be logged to Ant's log system
 100   
       * rather than the output. This has no effect if standard error is 
 101   
       * redirected to a file or property.
 102   
       */
 103   
     private boolean logError = false;
 104   
     
 105   
     /**
 106   
      * Buffer used to capture output for storage into a property
 107   
      */
 108   
     private ByteArrayOutputStream baos = null;
 109   
     
 110   
     /**
 111   
      * Buffer used to capture error output for storage into a property
 112   
      */
 113   
     private ByteArrayOutputStream errorBaos = null;
 114   
     
 115   
     /** The name of the property into which output is to be stored */
 116   
     private String outputProperty;
 117   
     
 118   
     /** The name of the property into which error output is to be stored */
 119   
     private String errorProperty;
 120   
     
 121   
     /** String from which input is taken */
 122   
     private String inputString;
 123   
     
 124   
     /** Flag which indicates if error and output files are to be appended. */
 125   
     private boolean append = false;
 126   
     
 127   
     /** The task for which this redirector is working */ 
 128   
     private Task managingTask;
 129   
 
 130   
     /** The stream for output data */
 131   
     private OutputStream outputStream = null;
 132   
     
 133   
     /** The stream for error output */
 134   
     private OutputStream errorStream = null;
 135   
     
 136   
     /** The stream for input */
 137   
     private InputStream inputStream = null;
 138   
     
 139   
     /** Stream which are used for line oriented output */ 
 140   
     private PrintStream outPrintStream = null;
 141   
     
 142   
     /** Stream which is used for line oriented error output */
 143   
     private PrintStream errorPrintStream = null;
 144   
     
 145   
     /**
 146   
      * Create a redirector instance for the given task
 147   
      *
 148   
      * @param managingTask the task for which the redirector is to work
 149   
      */
 150  25
     public Redirector(Task managingTask) {
 151  25
         this.managingTask = managingTask;
 152   
     }
 153   
     
 154   
     /**
 155   
      * Set the input to use for the task
 156   
      *
 157   
      * @param input the file from which input is read.
 158   
      */
 159  0
     public void setInput(File input) {
 160  0
         this.input = input;
 161   
     }
 162   
 
 163   
     /**
 164   
      * Set the string to use as input
 165   
      *
 166   
      * @param inputString the string which is used as the input source
 167   
      */
 168  0
     public void setInputString(String inputString) {
 169  0
         this.inputString = inputString;
 170   
     }
 171   
         
 172   
     
 173   
     /**
 174   
      * File the output of the process is redirected to. If error is not 
 175   
      * redirected, it too will appear in the output
 176   
      *
 177   
      * @param out the file to which output stream is written
 178   
      */
 179  1
     public void setOutput(File out) {
 180  1
         this.out = out;
 181   
     }
 182   
 
 183   
     /**
 184   
      * Controls whether error output of exec is logged. This is only useful
 185   
      * when output is being redirected and error output is desired in the
 186   
      * Ant log
 187   
      *
 188   
      * @param logError if true the standard error is sent to the Ant log system
 189   
      *        and not sent to output.
 190   
      */
 191  0
     public void setLogError(boolean logError) {
 192  0
         this.logError = logError;
 193   
     }
 194   
     
 195   
     /**
 196   
      * Set the file to which standard error is to be redirected.
 197   
      *
 198   
      * @param error the file to which error is to be written
 199   
      */
 200  0
     public void setError(File error) {
 201  0
         this.error = error;
 202   
     }
 203   
 
 204   
     /**
 205   
      * Property name whose value should be set to the output of
 206   
      * the process.
 207   
      *
 208   
      * @param outputProperty the name of the property to be set with the 
 209   
      *        task's output.
 210   
      */
 211  1
     public void setOutputProperty(String outputProperty) {
 212  1
         this.outputProperty = outputProperty;
 213   
     }
 214   
 
 215   
     /**
 216   
      * Whether output should be appended to or overwrite an existing file.
 217   
      * Defaults to false.
 218   
      *
 219   
      * @param append if true output and error streams are appended to their
 220   
      *        respective files, if specified.
 221   
      */
 222  0
     public void setAppend(boolean append) {
 223  0
         this.append = append;
 224   
     }
 225   
 
 226   
     /**
 227   
      * Property name whose value should be set to the error of
 228   
      * the process.
 229   
      *
 230   
      * @param errorProperty the name of the property to be set 
 231   
      *        with the error output.
 232   
      */
 233  0
     public void setErrorProperty(String errorProperty) {
 234  0
         this.errorProperty = errorProperty;
 235   
     }
 236   
 
 237   
     /**
 238   
      * Set a property from a ByteArrayOutputStream
 239   
      *
 240   
      * @param baos contains the property value.
 241   
      * @param propertyName the property name.
 242   
      *
 243   
      * @exception IOException if the value cannot be read form the stream.
 244   
      */
 245  0
     private void setPropertyFromBAOS(ByteArrayOutputStream baos, 
 246   
                                      String propertyName) throws IOException {
 247   
     
 248  0
         BufferedReader in =
 249   
             new BufferedReader(new StringReader(Execute.toString(baos)));
 250  0
         String line = null;
 251  0
         StringBuffer val = new StringBuffer();
 252  0
         while ((line = in.readLine()) != null) {
 253  0
             if (val.length() != 0) {
 254  0
                 val.append(StringUtils.LINE_SEP);
 255   
             }
 256  0
             val.append(line);
 257   
         }
 258  0
         managingTask.getProject().setNewProperty(propertyName, val.toString());
 259   
     }
 260   
     
 261   
 
 262   
     /**
 263   
      * Create the input, error and output streams based on the 
 264   
      * configuration options.
 265   
      */
 266  20
     public void createStreams() {        
 267  20
         if (out == null && outputProperty == null) {
 268  19
             outputStream = new LogOutputStream(managingTask, Project.MSG_INFO);
 269  19
             errorStream = new LogOutputStream(managingTask, Project.MSG_WARN);
 270   
         } else {
 271  1
             if (out != null)  {
 272  1
                 try {
 273  1
                     outputStream 
 274   
                         = new FileOutputStream(out.getAbsolutePath(), append);
 275  1
                     managingTask.log("Output redirected to " + out, 
 276   
                                      Project.MSG_VERBOSE);
 277   
                 } catch (FileNotFoundException fne) {
 278  0
                     throw new BuildException("Cannot write to " + out, fne);
 279   
                 } catch (IOException ioe) {
 280  0
                     throw new BuildException("Cannot write to " + out, ioe);
 281   
                 }
 282   
             }
 283   
         
 284  1
             if (outputProperty != null) {
 285  0
                 baos = new ByteArrayOutputStream();
 286  0
                 managingTask.log("Output redirected to property: " 
 287   
                     + outputProperty, Project.MSG_VERBOSE);
 288  0
                 if (out == null) {
 289  0
                     outputStream = baos;
 290   
                 } else {
 291  0
                     outputStream = new TeeOutputStream(outputStream, baos);
 292   
                 }
 293   
             } else {
 294  1
                 baos = null;
 295   
             }
 296   
             
 297  1
             errorStream = outputStream;
 298   
         } 
 299   
 
 300  20
         if (logError) {
 301  0
             errorStream = new LogOutputStream(managingTask, Project.MSG_WARN);
 302   
         }
 303   
         
 304  20
         if (error != null)  {
 305  0
             try {
 306  0
                 errorStream 
 307   
                     = new FileOutputStream(error.getAbsolutePath(), append);
 308  0
                 managingTask.log("Error redirected to " + error, 
 309   
                     Project.MSG_VERBOSE);
 310   
             } catch (FileNotFoundException fne) {
 311  0
                 throw new BuildException("Cannot write to " + error, fne);
 312   
             } catch (IOException ioe) {
 313  0
                 throw new BuildException("Cannot write to " + error, ioe);
 314   
             }
 315   
         }
 316   
     
 317  20
         if (errorProperty != null) {
 318  0
             errorBaos = new ByteArrayOutputStream();
 319  0
             managingTask.log("Error redirected to property: " + errorProperty, 
 320   
                 Project.MSG_VERBOSE);
 321  0
             if (error == null) {
 322  0
                 errorStream = errorBaos;
 323   
             } else {
 324  0
                 errorStream = new TeeOutputStream(errorStream, errorBaos);
 325   
             }
 326   
         } else {
 327  20
             errorBaos = null;
 328   
         }
 329   
 
 330  20
         if (input != null && inputString != null) {
 331  0
             throw new BuildException("The \"input\" and \"inputstring\" "
 332   
                 + "attributes cannot both be specified");
 333   
         }
 334  20
         if (input != null) {
 335  0
             try {
 336  0
                 inputStream = new FileInputStream(input);
 337   
             } catch (FileNotFoundException fne) {
 338  0
                 throw new BuildException("Cannot read from " + input, fne);
 339   
             }
 340  20
         } else if (inputString != null) {
 341  0
             inputStream = new ByteArrayInputStream(inputString.getBytes());
 342   
         }
 343   
     }
 344   
     
 345   
     
 346   
     /**
 347   
      * Create the StreamHandler to use with our Execute instance.
 348   
      *
 349   
      * @return the execute stream handler to manage the input, output and
 350   
      * error streams.
 351   
      * 
 352   
      * @throws BuildException if the execute stream handler cannot be created.
 353   
      */
 354  15
     public ExecuteStreamHandler createHandler() throws BuildException {
 355  15
         createStreams();
 356  15
         return new PumpStreamHandler(outputStream, errorStream, inputStream);
 357   
     }
 358   
    
 359   
     /**
 360   
      * Pass output sent to System.out to specified output.
 361   
      *
 362   
      * @param line the data to be output
 363   
      */
 364  54
     protected void handleOutput(String line) {
 365  54
         if (outPrintStream == null) {
 366  1
             outPrintStream = new PrintStream(outputStream);
 367   
         }
 368  54
         outPrintStream.println(line);
 369   
     }
 370   
     
 371   
     /** 
 372   
      * Handle an input request
 373   
      *
 374   
      * @param buffer the buffer into which data is to be read.
 375   
      * @param offset the offset into the buffer at which data is stored.
 376   
      * @param length the amount of data to read
 377   
      *
 378   
      * @return the number of bytes read
 379   
      * 
 380   
      * @exception IOException if the data cannot be read
 381   
      */
 382  0
     protected int handleInput(byte[] buffer, int offset, int length) 
 383   
         throws IOException {
 384  0
         if (inputStream == null) {
 385  0
             return managingTask.getProject().defaultInput(buffer, offset, 
 386   
                                                           length);
 387   
         } else {
 388  0
             return inputStream.read(buffer, offset, length);
 389   
         }            
 390   
     }
 391   
     
 392   
     /**
 393   
      * Process data due to a flush operation.
 394   
      *
 395   
      * @param line the data being flushed.
 396   
      */
 397  0
     protected void handleFlush(String line) {
 398  0
         if (outPrintStream == null) {
 399  0
             outPrintStream = new PrintStream(outputStream);
 400   
         }
 401  0
         outPrintStream.print(line);
 402   
     }
 403   
     
 404   
     /**
 405   
      * Process error output
 406   
      *
 407   
      * @param line the error output data.
 408   
      */
 409  0
     protected void handleErrorOutput(String line) {
 410  0
         if (errorPrintStream == null) {
 411  0
             errorPrintStream = new PrintStream(errorStream);
 412   
         }
 413  0
         errorPrintStream.println(line);
 414   
     }
 415   
     
 416   
     /**
 417   
      * Handle a flush operation on the error stream
 418   
      *
 419   
      * @param line the error information being flushed.
 420   
      */
 421  0
     protected void handleErrorFlush(String line) {
 422  0
         if (errorPrintStream == null) {
 423  0
             errorPrintStream = new PrintStream(errorStream);
 424   
         }
 425  0
         errorPrintStream.print(line);
 426   
     }
 427   
 
 428   
     /**
 429   
      * Get the output stream for the redirector
 430   
      *
 431   
      * @return the redirector's output stream or null if no output 
 432   
      *         has been configured
 433   
      */
 434  54
     public OutputStream getOutputStream() {
 435  54
         return outputStream;
 436   
     }
 437   
     
 438   
     /**
 439   
      * Get the error stream for the redirector
 440   
      *
 441   
      * @return the redirector's error stream or null if no output 
 442   
      *         has been configured
 443   
      */
 444  0
     public OutputStream getErrorStream() {
 445  0
         return errorStream;
 446   
     }
 447   
 
 448   
     /**
 449   
      * Get the input stream for the redirector
 450   
      *
 451   
      * @return the redirector's input stream or null if no output 
 452   
      *         has been configured
 453   
      */
 454  0
     public InputStream getInputStream() {
 455  0
         return inputStream;
 456   
     }
 457   
     
 458   
     /**
 459   
      * Complete redirection. 
 460   
      *
 461   
      * This opertaion will close any streams and create any specified
 462   
      * property values.
 463   
      *
 464   
      * @throws IOException if the outptu properties cannot be read from their
 465   
      * output streams.
 466   
      */
 467  18
     public void complete() throws IOException {
 468  18
         System.out.flush();
 469  18
         System.err.flush();
 470   
         
 471  18
         if (inputStream != null) {
 472  0
             inputStream.close();
 473   
         }
 474  18
         outputStream.close();
 475  18
         errorStream.close();
 476   
         
 477  18
         if (baos != null) {
 478  0
             setPropertyFromBAOS(baos, outputProperty);
 479   
         }
 480  18
         if (errorBaos != null) {
 481  0
             setPropertyFromBAOS(errorBaos, errorProperty);
 482   
         }
 483   
     }
 484   
 }
 485