Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 472   Methods: 12
NCLOC: 230   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
EchoProperties.java 52.2% 60.4% 91.7% 60.4%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2002 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.optional;
 55   
 
 56   
 import java.io.ByteArrayOutputStream;
 57   
 import java.io.File;
 58   
 import java.io.FileInputStream;
 59   
 import java.io.FileNotFoundException;
 60   
 import java.io.FileOutputStream;
 61   
 import java.io.IOException;
 62   
 import java.io.OutputStream;
 63   
 import java.io.OutputStreamWriter;
 64   
 import java.io.Writer;
 65   
 import java.util.Enumeration;
 66   
 import java.util.Hashtable;
 67   
 import java.util.Properties;
 68   
 import javax.xml.parsers.DocumentBuilder;
 69   
 import javax.xml.parsers.DocumentBuilderFactory;
 70   
 import org.apache.tools.ant.BuildException;
 71   
 import org.apache.tools.ant.Project;
 72   
 import org.apache.tools.ant.Task;
 73   
 import org.apache.tools.ant.types.EnumeratedAttribute;
 74   
 import org.apache.tools.ant.util.CollectionUtils;
 75   
 import org.apache.tools.ant.util.DOMElementWriter;
 76   
 import org.w3c.dom.Document;
 77   
 import org.w3c.dom.Element;
 78   
 
 79   
 /**
 80   
  *  Displays all the current properties in the build. The output can be sent to
 81   
  *  a file if desired. <P>
 82   
  *
 83   
  *  Attribute "destfile" defines a file to send the properties to. This can be
 84   
  *  processed as a standard property file later. <P>
 85   
  *
 86   
  *  Attribute "prefix" defines a prefix which is used to filter the properties
 87   
  *  only those properties starting with this prefix will be echoed. <P>
 88   
  *
 89   
  *  By default, the "failonerror" attribute is enabled. If an error occurs while
 90   
  *  writing the properties to a file, and this attribute is enabled, then a
 91   
  *  BuildException will be thrown. If disabled, then IO errors will be reported
 92   
  *  as a log statement, but no error will be thrown. <P>
 93   
  *
 94   
  *  Examples: <pre>
 95   
  *  &lt;echoproperties  /&gt;
 96   
  * </pre> Report the current properties to the log. <P>
 97   
  *
 98   
  *  <pre>
 99   
  *  &lt;echoproperties destfile="my.properties" /&gt;
 100   
  * </pre> Report the current properties to the file "my.properties", and will
 101   
  *  fail the build if the file could not be created or written to. <P>
 102   
  *
 103   
  *  <pre>
 104   
  *  &lt;echoproperties destfile="my.properties" failonerror="false"
 105   
  *      prefix="ant" /&gt;
 106   
  * </pre> Report all properties beginning with 'ant' to the file
 107   
  *  "my.properties", and will log a message if the file could not be created or
 108   
  *  written to, but will still allow the build to continue.
 109   
  *
 110   
  *@author     Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">
 111   
  *      groboclown@users.sourceforge.net</a>
 112   
  *@author     Ingmar Stein <a href="mailto:stein@xtramind.com">
 113   
         stein@xtramind.com</a>
 114   
  *@since      Ant 1.5
 115   
  */
 116   
 public class EchoProperties extends Task {
 117   
 
 118   
     /**
 119   
      * the properties element.
 120   
      */
 121   
     private static final String PROPERTIES = "properties";
 122   
 
 123   
     /**
 124   
      * the property element.
 125   
      */
 126   
     private static final String PROPERTY = "property";
 127   
 
 128   
     /**
 129   
      * name attribute for property, testcase and testsuite elements.
 130   
      */
 131   
     private static final String ATTR_NAME = "name";
 132   
 
 133   
     /**
 134   
      * value attribute for property elements.
 135   
      */
 136   
     private static final String ATTR_VALUE = "value";
 137   
 
 138   
     /**
 139   
      * the input file.
 140   
      */
 141   
     private File inFile = null;
 142   
 
 143   
     /**
 144   
      *  File object pointing to the output file. If this is null, then
 145   
      *  we output to the project log, not to a file.
 146   
      */
 147   
     private File destfile = null;
 148   
 
 149   
     /**
 150   
      *  If this is true, then errors generated during file output will become
 151   
      *  build errors, and if false, then such errors will be logged, but not
 152   
      *  thrown.
 153   
      */
 154   
     private boolean failonerror = true;
 155   
 
 156   
     /**
 157   
      *  Prefix string controls which properties to save.
 158   
      */
 159   
     private String prefix = null;
 160   
 
 161   
 
 162   
     private String format = "text";
 163   
 
 164   
     /**
 165   
      * Sets the input file.
 166   
      *
 167   
      * @param file  the input file
 168   
      */
 169  3
     public void setSrcfile( File file ) {
 170  3
         inFile = file;
 171   
     }
 172   
 
 173   
     /**
 174   
      *  Set a file to store the property output.  If this is never specified,
 175   
      *  then the output will be sent to the Ant log.
 176   
      *
 177   
      *@param destfile file to store the property output
 178   
      */
 179  8
     public void setDestfile(File destfile) {
 180  8
         this.destfile = destfile;
 181   
     }
 182   
 
 183   
 
 184   
     /**
 185   
      * If true, the task will fail if an error occurs writing the properties
 186   
      * file, otherwise errors are just logged.
 187   
      *
 188   
      *@param  failonerror  <tt>true</tt> if IO exceptions are reported as build
 189   
      *      exceptions, or <tt>false</tt> if IO exceptions are ignored.
 190   
      */
 191  5
     public void setFailOnError(boolean failonerror) {
 192  5
         this.failonerror = failonerror;
 193   
     }
 194   
 
 195   
 
 196   
     /**
 197   
      *  If the prefix is set, then only properties which start with this
 198   
      *  prefix string will be recorded.  If this is never set, or it is set
 199   
      *  to an empty string or <tt>null</tt>, then all properties will be
 200   
      *  recorded. <P>
 201   
      *
 202   
      *  For example, if the property is set as:
 203   
      *    <PRE>&lt;echoproperties  prefix="ant." /&gt;</PRE>
 204   
      *  then the property "ant.home" will be recorded, but "ant-example"
 205   
      *  will not.
 206   
      *
 207   
      *@param  prefix  The new prefix value
 208   
      */
 209  1
     public void setPrefix(String prefix) {
 210  1
         this.prefix = prefix;
 211   
     }
 212   
 
 213   
 
 214  1
     public void setFormat(FormatAttribute ea) {
 215  1
         format = ea.getValue();
 216   
     }
 217   
 
 218   
     public static class FormatAttribute extends EnumeratedAttribute {
 219   
         private String [] formats = new String[]{"xml", "text"};
 220   
 
 221  1
         public String[] getValues() {
 222  1
             return formats;
 223   
         }
 224   
     }
 225   
 
 226   
     /**
 227   
      *  Run the task.
 228   
      *
 229   
      *@exception  BuildException  trouble, probably file IO
 230   
      */
 231  12
     public void execute() throws BuildException {
 232   
         //copy the properties file
 233  12
         Hashtable allProps = new Hashtable();
 234   
 
 235   
         /* load properties from file if specified, otherwise
 236   
         use Ant's properties */
 237  12
         if(inFile == null) {
 238   
             // add ant properties
 239  9
             CollectionUtils.putAll(allProps, getProject().getProperties());
 240   
         } else {
 241  3
             if (inFile.exists() && inFile.isDirectory()) {
 242  3
                 String message = "srcfile is a directory!";
 243  3
                 if (failonerror) {
 244  2
                     throw new BuildException(message, getLocation());
 245   
                 } else {
 246  1
                     log(message, Project.MSG_ERR);
 247   
                 }
 248  1
                 return;
 249   
             }
 250   
 
 251  0
             if (inFile.exists() && !inFile.canRead()) {
 252  0
                 String message = "Can not read from the specified srcfile!";
 253  0
                 if (failonerror) {
 254  0
                     throw new BuildException( message, getLocation() );
 255   
                 } else {
 256  0
                     log( message, Project.MSG_ERR );
 257   
                 }
 258  0
                 return;
 259   
             }
 260   
 
 261  0
             FileInputStream in = null;
 262  0
             try {
 263  0
                 in = new FileInputStream( inFile );
 264  0
                 Properties props = new Properties();
 265  0
                 props.load(in);
 266  0
                 CollectionUtils.putAll(allProps, props);
 267   
             } catch(FileNotFoundException fnfe) {
 268  0
                 String message =
 269   
                     "Could not find file " + inFile.getAbsolutePath();
 270  0
                 if (failonerror) {
 271  0
                     throw new BuildException(message, fnfe, getLocation());
 272   
                 } else {
 273  0
                     log( message, Project.MSG_WARN );
 274   
                 }
 275  0
                 return;
 276   
             } catch( IOException ioe ) {
 277  0
                 String message =
 278   
                     "Could not read file " + inFile.getAbsolutePath();
 279  0
                 if (failonerror) {
 280  0
                     throw new BuildException(message, ioe, getLocation());
 281   
                 } else {
 282  0
                     log( message, Project.MSG_WARN );
 283   
                 }
 284  0
                 return;
 285   
             } finally {
 286  0
                 try {
 287  0
                     if( null != in ) {
 288  0
                         in.close();
 289   
                     }
 290   
                 } catch(IOException ioe) {}
 291   
             }
 292   
         }
 293   
 
 294  9
         OutputStream os = null;
 295  9
         try {
 296  9
             if (destfile == null) {
 297  1
                 os = new ByteArrayOutputStream();
 298  1
                 saveProperties(allProps, os);
 299  1
                 log(os.toString(), Project.MSG_INFO);
 300   
             } else {
 301  8
                 if (destfile.exists() && destfile.isDirectory()) {
 302  3
                     String message = "destfile is a directory!";
 303  3
                     if (failonerror) {
 304  2
                         throw new BuildException(message, getLocation());
 305   
                     } else {
 306  1
                         log(message, Project.MSG_ERR);
 307   
                     }
 308  1
                     return;
 309   
                 }
 310   
 
 311  5
                 if (destfile.exists() && !destfile.canWrite()) {
 312  0
                     String message =
 313   
                         "Can not write to the specified destfile!";
 314  0
                     if (failonerror) {
 315  0
                         throw new BuildException(message, getLocation());
 316   
                     } else {
 317  0
                         log(message, Project.MSG_ERR);
 318   
                     }
 319  0
                     return;
 320   
                 }
 321  5
                 os = new FileOutputStream(this.destfile);
 322  5
                 saveProperties(allProps, os);
 323   
             }
 324   
         } catch (IOException ioe) {
 325  0
             if (failonerror) {
 326  0
                 throw new BuildException(ioe, getLocation());
 327   
             } else {
 328  0
                 log(ioe.getMessage(), Project.MSG_INFO);
 329   
             }
 330   
         } finally {
 331  9
             if (os != null) {
 332  6
                 try {
 333  6
                     os.close();
 334   
                 } catch (IOException e) {
 335   
                 }
 336   
             }
 337   
         }
 338   
     }
 339   
 
 340   
 
 341   
     /**
 342   
      *  Send the key/value pairs in the hashtable to the given output stream.
 343   
      *  Only those properties matching the <tt>prefix</tt> constraint will be
 344   
      *  sent to the output stream.
 345   
      *  The output stream will be closed when this method returns.
 346   
      *
 347   
      *@param  allProps         propfile to save
 348   
      *@param  os               output stream
 349   
      *@exception  IOException  trouble
 350   
      */
 351  6
     protected void saveProperties(Hashtable allProps, OutputStream os)
 352   
              throws IOException, BuildException {
 353  6
         Properties props = new Properties();
 354  6
         Enumeration enum = allProps.keys();
 355  6
         while (enum.hasMoreElements()) {
 356  354
             String name = enum.nextElement().toString();
 357  354
             String value = allProps.get(name).toString();
 358  354
             if (prefix == null || name.indexOf(prefix) == 0) {
 359  296
                 props.put(name, value);
 360   
             }
 361   
         }
 362   
 
 363  6
         if ("text".equals(format)) {
 364  5
             jdkSaveProperties(props, os, "Ant properties");
 365  1
         } else if ("xml".equals(format)) {
 366  1
             xmlSaveProperties(props, os );
 367   
         }
 368   
     }
 369   
 
 370  1
     protected void xmlSaveProperties(Properties props,
 371   
                                      OutputStream os) throws IOException {
 372   
         // create XML document
 373  1
         Document doc = getDocumentBuilder().newDocument();
 374  1
         Element rootElement = doc.createElement( PROPERTIES );
 375   
 
 376   
         // output properties
 377  1
         String name;
 378  1
         Enumeration e = props.propertyNames();
 379  1
         while( e.hasMoreElements() ) {
 380  59
             name = (String)e.nextElement();
 381  59
             Element propElement = doc.createElement( PROPERTY );
 382  59
             propElement.setAttribute( ATTR_NAME, name );
 383  59
             propElement.setAttribute( ATTR_VALUE, props.getProperty( name ) );
 384  59
             rootElement.appendChild( propElement );
 385   
         }
 386   
 
 387  1
         Writer wri = null;
 388  1
         try {
 389  1
             wri = new OutputStreamWriter( os, "UTF8" );
 390  1
             wri.write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
 391  1
             ( new DOMElementWriter() ).write( rootElement, wri, 0, "\t" );
 392  1
             wri.flush();
 393   
         } catch( IOException ioe ) {
 394  0
             throw new BuildException( "Unable to write XML file", ioe );
 395   
         } finally {
 396  1
             if( wri != null ) {
 397  1
                 wri.close();
 398   
             }
 399   
         }
 400   
     }
 401   
 
 402   
     /**
 403   
      *  JDK 1.2 allows for the safer method
 404   
      *  <tt>Properties.store( OutputStream, String )</tt>, which throws an
 405   
      *  <tt>IOException</tt> on an output error.  This method attempts to
 406   
      *  use the JDK 1.2 method first, and if that does not exist, then the
 407   
      *  JDK 1.0 compatible method
 408   
      *  <tt>Properties.save( OutputStream, String )</tt> is used instead.
 409   
      *
 410   
      *@param props the properties to record
 411   
      *@param os record the properties to this output stream
 412   
      *@param header prepend this header to the property output
 413   
      *@exception IOException on an I/O error during a write.  Only thrown
 414   
      *      for JDK 1.2+.
 415   
      */
 416  5
     protected void jdkSaveProperties(Properties props, OutputStream os,
 417   
                                      String header) throws IOException {
 418  5
         try {
 419  5
             java.lang.reflect.Method m = props.getClass().getMethod(
 420   
                 "store", new Class[]{OutputStream.class, String.class});
 421  5
             m.invoke(props, new Object[]{os, header});
 422   
         } catch (java.lang.reflect.InvocationTargetException ite) {
 423  0
             Throwable t = ite.getTargetException();
 424  0
             if (t instanceof IOException) {
 425  0
                 throw (IOException) t;
 426   
             }
 427  0
             if (t instanceof RuntimeException) {
 428  0
                 throw (RuntimeException) t;
 429   
             }
 430   
 
 431   
             // not an expected exception.  Resort to JDK 1.0 to execute
 432   
             // this method
 433  0
             jdk10SaveProperties(props, os, header);
 434   
         } catch (ThreadDeath td) {
 435   
             // don't trap thread death errors.
 436  0
             throw td;
 437   
         } catch (Throwable ex) {
 438   
             // this 'store' method is not available, so resort to the JDK 1.0
 439   
             // compatible method.
 440  0
             jdk10SaveProperties(props, os, header);
 441   
         }
 442   
     }
 443   
 
 444   
 
 445   
     /**
 446   
      * Save the properties to the output stream using the JDK 1.0 compatible
 447   
      * method.  This won't throw an <tt>IOException</tt> on an output error.
 448   
      *
 449   
      *@param props the properties to record
 450   
      *@param os record the properties to this output stream
 451   
      *@param header prepend this header to the property output
 452   
      */
 453  0
     protected void jdk10SaveProperties(Properties props, OutputStream os,
 454   
                                        String header) {
 455  0
         props.save(os, header);
 456   
     }
 457   
 
 458   
     /**
 459   
      * Uses the DocumentBuilderFactory to get a DocumentBuilder instance.
 460   
      *
 461   
      * @return   The DocumentBuilder instance
 462   
      */
 463  1
     private static DocumentBuilder getDocumentBuilder() {
 464  1
         try {
 465  1
             return DocumentBuilderFactory.newInstance().newDocumentBuilder();
 466   
         } catch( Exception e ) {
 467  0
             throw new ExceptionInInitializerError( e );
 468   
         }
 469   
     }
 470   
 }
 471   
 
 472