Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 433   Methods: 10
NCLOC: 230   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
Get.java 33.9% 33.6% 30% 33.5%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-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   
 
 55   
 package org.apache.tools.ant.taskdefs;
 56   
 
 57   
 import java.io.File;
 58   
 import java.io.FileOutputStream;
 59   
 import java.io.IOException;
 60   
 import java.io.InputStream;
 61   
 import java.net.HttpURLConnection;
 62   
 import java.net.URL;
 63   
 import java.net.URLConnection;
 64   
 import java.util.Date;
 65   
 import org.apache.tools.ant.BuildException;
 66   
 import org.apache.tools.ant.Project;
 67   
 import org.apache.tools.ant.Task;
 68   
 import org.apache.tools.ant.util.FileUtils;
 69   
 import org.apache.tools.ant.util.JavaEnvUtils;
 70   
 
 71   
 /**
 72   
  * Gets a particular file from a URL source.
 73   
  * Options include verbose reporting, timestamp based fetches and controlling
 74   
  * actions on failures. NB: access through a firewall only works if the whole
 75   
  * Java runtime is correctly configured.
 76   
  *
 77   
  * @author costin@dnt.ro
 78   
  * @author gg@grtmail.com (Added Java 1.1 style HTTP basic auth)
 79   
  *
 80   
  * @since Ant 1.1
 81   
  *
 82   
  * @ant.task category="network"
 83   
  */
 84   
 public class Get extends Task {
 85   
     private URL source; // required
 86   
     private File dest; // required
 87   
     private boolean verbose = false;
 88   
     private boolean useTimestamp = false; //off by default
 89   
     private boolean ignoreErrors = false;
 90   
     private String uname = null;
 91   
     private String pword = null;
 92   
 
 93   
 
 94   
     /**
 95   
      * Does the work.
 96   
      *
 97   
      * @exception BuildException Thrown in unrecoverable error.
 98   
      */
 99  3
     public void execute() throws BuildException {
 100  3
         if (source == null) {
 101  1
             throw new BuildException("src attribute is required", getLocation());
 102   
         }
 103   
 
 104  2
         if (dest == null) {
 105  0
             throw new BuildException("dest attribute is required", getLocation());
 106   
         }
 107   
 
 108  2
         if (dest.exists() && dest.isDirectory()) {
 109  1
             throw new BuildException("The specified destination is a directory",
 110   
                                      getLocation());
 111   
         }
 112   
 
 113  1
         if (dest.exists() && !dest.canWrite()) {
 114  0
             throw new BuildException("Can't write to " + dest.getAbsolutePath(),
 115   
                                      getLocation());
 116   
         }
 117   
 
 118  1
         try {
 119   
 
 120  1
             log("Getting: " + source);
 121   
 
 122   
             //set the timestamp to the file date.
 123  1
             long timestamp = 0;
 124   
 
 125  1
             boolean hasTimestamp = false;
 126  1
             if (useTimestamp && dest.exists()) {
 127  0
                 timestamp = dest.lastModified();
 128  0
                 if (verbose) {
 129  0
                     Date t = new Date(timestamp);
 130  0
                     log("local file date : " + t.toString());
 131   
                 }
 132   
 
 133  0
                 hasTimestamp = true;
 134   
             }
 135   
 
 136   
             //set up the URL connection
 137  1
             URLConnection connection = source.openConnection();
 138   
             //modify the headers
 139   
             //NB: things like user authentication could go in here too.
 140  1
             if (useTimestamp && hasTimestamp) {
 141  0
                 connection.setIfModifiedSince(timestamp);
 142   
             }
 143   
             // prepare Java 1.1 style credentials
 144  1
             if (uname != null || pword != null) {
 145  0
                 String up = uname + ":" + pword;
 146  0
                 String encoding;
 147   
                 // check to see if sun's Base64 encoder is available.
 148  0
                 try {
 149  0
                     Object encoder =
 150   
                             Class.forName("sun.misc.BASE64Encoder").newInstance();
 151  0
                     encoding = (String) 
 152   
                             encoder.getClass().getMethod("encode", new Class[] {byte[].class})
 153   
                             .invoke(encoder, new Object[] {up.getBytes()});
 154   
 
 155   
                 } catch (Exception ex) { // sun's base64 encoder isn't available
 156  0
                     Base64Converter encoder = new Base64Converter();
 157  0
                     encoding = encoder.encode(up.getBytes());
 158   
                 }
 159  0
                 connection.setRequestProperty ("Authorization",
 160   
                                                "Basic " + encoding);
 161   
             }
 162   
 
 163   
             //connect to the remote site (may take some time)
 164  1
             connection.connect();
 165   
             //next test for a 304 result (HTTP only)
 166  1
             if (connection instanceof HttpURLConnection) {
 167  1
                 HttpURLConnection httpConnection
 168   
                     = (HttpURLConnection) connection;
 169  1
                 if (httpConnection.getResponseCode()
 170   
                     == HttpURLConnection.HTTP_NOT_MODIFIED)  {
 171   
                     //not modified so no file download. just return
 172   
                     //instead and trace out something so the user
 173   
                     //doesn't think that the download happened when it
 174   
                     //didnt
 175  0
                     log("Not modified - so not downloaded");
 176  0
                     return;
 177   
                 }
 178   
                 // test for 401 result (HTTP only)
 179  1
                 if (httpConnection.getResponseCode()
 180   
                     == HttpURLConnection.HTTP_UNAUTHORIZED)  {
 181  0
                     String message="HTTP Authorization failure";
 182  0
                     if(ignoreErrors) {
 183  0
                         log(message,Project.MSG_WARN);
 184  0
                         return;
 185   
                     } else {
 186  0
                         throw new BuildException(message);
 187   
                     }
 188   
                 }
 189   
 
 190   
             }
 191   
 
 192   
             //REVISIT: at this point even non HTTP connections may
 193   
             //support the if-modified-since behaviour -we just check
 194   
             //the date of the content and skip the write if it is not
 195   
             //newer. Some protocols (FTP) dont include dates, of
 196   
             //course.
 197   
 
 198  1
             InputStream is = null;
 199  1
             for (int i = 0; i < 3 ; i++) {
 200  1
                 try {
 201  1
                     is = connection.getInputStream();
 202  1
                     break;
 203   
                 } catch (IOException ex) {
 204  0
                     log("Error opening connection " + ex);
 205   
                 }
 206   
             }
 207  1
             if (is == null) {
 208  0
                 log("Can't get " + source + " to " + dest);
 209  0
                 if (ignoreErrors) {
 210  0
                     return;
 211   
                 }
 212  0
                 throw new BuildException("Can't get " + source + " to " + dest,
 213   
                                          getLocation());
 214   
             }
 215   
 
 216  1
             FileOutputStream fos = new FileOutputStream(dest);
 217  1
             boolean finished = false;
 218  1
             try {
 219  1
                 byte[] buffer = new byte[100 * 1024];
 220  1
                 int length;
 221   
 
 222  ?
                 while ((length = is.read(buffer)) >= 0) {
 223  7
                     fos.write(buffer, 0, length);
 224  7
                     if (verbose) {
 225  0
                         System.out.print(".");
 226   
                     }
 227   
                 }
 228  1
                 if (verbose) {
 229  0
                     System.out.println();
 230   
                 }
 231  1
                 finished = true;
 232   
             } finally {
 233  1
                 if (fos != null) {
 234  1
                     fos.close();
 235   
                 }
 236  1
                 is.close();
 237   
                 // we have started to (over)write dest, but failed.
 238   
                 // Try to delete the garbage we'd otherwise leave
 239   
                 // behind.
 240  1
                 if (!finished) {
 241  0
                     dest.delete();
 242   
                 }
 243   
             }
 244   
 
 245   
             //if (and only if) the use file time option is set, then
 246   
             //the saved file now has its timestamp set to that of the
 247   
             //downloaded file
 248  1
             if (useTimestamp)  {
 249  0
                 long remoteTimestamp = connection.getLastModified();
 250  0
                 if (verbose)  {
 251  0
                     Date t = new Date(remoteTimestamp);
 252  0
                     log("last modified = " + t.toString()
 253   
                         + ((remoteTimestamp == 0)
 254   
                           ? " - using current time instead"
 255   
                           : ""));
 256   
                 }
 257  0
                 if (remoteTimestamp != 0) {
 258  0
                     FileUtils.newFileUtils()
 259   
                         .setFileLastModified(dest, remoteTimestamp);
 260   
                 }
 261   
             }
 262   
         } catch (IOException ioe) {
 263  0
             log("Error getting " + source + " to " + dest);
 264  0
             if (ignoreErrors) {
 265  0
                 return;
 266   
             }
 267  0
             throw new BuildException(ioe, getLocation());
 268   
         }
 269   
     }
 270   
 
 271   
     /**
 272   
      * Set the URL to get.
 273   
      *
 274   
      * @param u URL for the file.
 275   
      */
 276  2
     public void setSrc(URL u) {
 277  2
         this.source = u;
 278   
     }
 279   
 
 280   
     /**
 281   
      * Where to copy the source file.
 282   
      *
 283   
      * @param dest Path to file.
 284   
      */
 285  2
     public void setDest(File dest) {
 286  2
         this.dest = dest;
 287   
     }
 288   
 
 289   
     /**
 290   
      * If true, show verbose progress information.
 291   
      *
 292   
      * @param v if "true" then be verbose
 293   
      */
 294  0
     public void setVerbose(boolean v) {
 295  0
         verbose = v;
 296   
     }
 297   
 
 298   
     /**
 299   
      * If true, log errors but do not treat as fatal.
 300   
      *
 301   
      * @param v if "true" then don't report download errors up to ant
 302   
      */
 303  0
     public void setIgnoreErrors(boolean v) {
 304  0
         ignoreErrors = v;
 305   
     }
 306   
 
 307   
     /**
 308   
      * If true, conditionally download a file based on the timestamp
 309   
      * of the local copy.
 310   
      *
 311   
      * <p>In this situation, the if-modified-since header is set so
 312   
      * that the file is only fetched if it is newer than the local
 313   
      * file (or there is no local file) This flag is only valid on
 314   
      * HTTP connections, it is ignored in other cases.  When the flag
 315   
      * is set, the local copy of the downloaded file will also have
 316   
      * its timestamp set to the remote file time.</p>
 317   
      *
 318   
      * <p>Note that remote files of date 1/1/1970 (GMT) are treated as
 319   
      * 'no timestamp', and web servers often serve files with a
 320   
      * timestamp in the future by replacing their timestamp with that
 321   
      * of the current time. Also, inter-computer clock differences can
 322   
      * cause no end of grief.</p>
 323   
      * @param v "true" to enable file time fetching
 324   
      */
 325  0
     public void setUseTimestamp(boolean v) {
 326  0
         if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
 327  0
             useTimestamp = v;
 328   
         }
 329   
     }
 330   
 
 331   
 
 332   
     /**
 333   
      * Username for basic auth.
 334   
      *
 335   
      * @param u username for authentication
 336   
      */
 337  0
     public void setUsername(String u) {
 338  0
         this.uname = u;
 339   
     }
 340   
 
 341   
     /**
 342   
      * password for the basic authentication.
 343   
      *
 344   
      * @param p password for authentication
 345   
      */
 346  0
     public void setPassword(String p) {
 347  0
         this.pword = p;
 348   
     }
 349   
 
 350   
     /*********************************************************************
 351   
     * BASE 64 encoding of a String or an array of bytes.
 352   
     *
 353   
     * Based on RFC 1421.
 354   
     *
 355   
     * @author
 356   
     *    Unknown
 357   
     * @author
 358   
     *    <a HREF="gg@grtmail.com">Gautam Guliani</a>
 359   
     *********************************************************************/
 360   
 
 361   
     class  Base64Converter {
 362   
 
 363   
         public final char [ ]  alphabet = {
 364   
             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',   //  0 to  7
 365   
             'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',   //  8 to 15
 366   
             'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',   // 16 to 23
 367   
             'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',   // 24 to 31
 368   
             'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',   // 32 to 39
 369   
             'o', 'p', 'q', 'r', 's', 't', 'u', 'v',   // 40 to 47
 370   
             'w', 'x', 'y', 'z', '0', '1', '2', '3',   // 48 to 55
 371   
             '4', '5', '6', '7', '8', '9', '+', '/' }; // 56 to 63
 372   
 
 373   
 
 374  0
         public String  encode(String  s) {
 375  0
             return encode (s.getBytes());
 376   
         }
 377   
 
 378  0
         public String  encode(byte[ ] octetString) {
 379  0
             int  bits24;
 380  0
             int  bits6;
 381   
 
 382  0
             char [ ]  out
 383   
               = new char[((octetString.length - 1) / 3 + 1) * 4];
 384   
 
 385  0
             int outIndex = 0;
 386  0
             int i = 0;
 387   
 
 388  0
             while ((i + 3) <= octetString.length) {
 389   
                 // store the octets
 390  0
                 bits24 = (octetString[i++] & 0xFF) << 16;
 391  0
                 bits24 |= (octetString[i++] & 0xFF) << 8;
 392   
 
 393  0
                 bits6 = (bits24 & 0x00FC0000) >> 18;
 394  0
                 out[outIndex++] = alphabet[bits6];
 395  0
                 bits6 = (bits24 & 0x0003F000) >> 12;
 396  0
                 out[outIndex++] = alphabet[bits6];
 397  0
                 bits6  = (bits24 & 0x00000FC0) >> 6;
 398  0
                 out[outIndex++] = alphabet[bits6];
 399  0
                 bits6 = (bits24 & 0x0000003F);
 400  0
                 out[outIndex++] = alphabet[bits6];
 401   
             }
 402   
 
 403  0
             if (octetString.length - i == 2) {
 404   
                 // store the octets
 405  0
                 bits24 = (octetString[i] & 0xFF) << 16;
 406  0
                 bits24 |= (octetString[i + 1] & 0xFF) << 8;
 407  0
                 bits6 = (bits24 & 0x00FC0000) >> 18;
 408  0
                 out[outIndex++] = alphabet[bits6];
 409  0
                 bits6 = (bits24 & 0x0003F000) >> 12;
 410  0
                 out[outIndex++] = alphabet[bits6];
 411  0
                 bits6 = (bits24 & 0x00000FC0) >> 6;
 412  0
                 out[outIndex++] = alphabet[bits6];
 413   
 
 414   
                 // padding
 415  0
                 out[outIndex++] = '=';
 416  0
             } else if (octetString.length - i == 1) {
 417   
                 // store the octets
 418  0
                 bits24 = (octetString[i] & 0xFF) << 16;
 419  0
                 bits6 = (bits24 & 0x00FC0000) >> 18;
 420  0
                 out[outIndex++] = alphabet[bits6];
 421  0
                 bits6 = (bits24 & 0x0003F000) >> 12;
 422  0
                 out[outIndex++] = alphabet[ bits6 ];
 423   
 
 424   
                 // padding
 425  0
                 out[outIndex++] = '=';
 426  0
                 out[outIndex++] = '=';
 427   
             }
 428   
 
 429  0
             return new String(out);
 430   
         }
 431   
      }
 432   
 }
 433