You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by st...@apache.org on 2004/11/03 00:37:21 UTC

cvs commit: ant/src/main/org/apache/tools/ant/taskdefs Get.java

stevel      2004/11/02 15:37:21

  Modified:    .        build.xml
               src/main/org/apache/tools/ant/taskdefs/optional/repository
                        Repository.java HttpRepository.java
                        MavenRepository.java GetLibraries.java
                        RepositoryRef.java
               src/testcases/org/apache/tools/ant/taskdefs/optional/repository
                        GetLibrariesTest.java
               src/etc/testcases/taskdefs/optional getlibraries.xml
               src/main/org/apache/tools/ant/taskdefs Get.java
  Log:
  1. Updated repository work; now has the following from Russel Gold's contrib
   -uses <get> to get
   -sets a classpath after
  2. some changes to Get to make this work. They also lay the way to adding progress indicators to guis, if that is felt useful in IDEs (it may be, once downloads become more common)
  3. starting on security. This will need to work with <checksum> to get done. Currently the md5 can be fetched if asked for, and if so it must exist.
  
  Revision  Changes    Path
  1.440     +0 -1      ant/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/ant/build.xml,v
  retrieving revision 1.439
  retrieving revision 1.440
  diff -u -r1.439 -r1.440
  --- build.xml	29 Oct 2004 08:54:32 -0000	1.439
  +++ build.xml	2 Nov 2004 23:37:20 -0000	1.440
  @@ -329,7 +329,6 @@
     </selector>
   
     <selector id="needs.apache-httpclient">
  -    <filename name="${optional.package}/repository/**/*"/>
     </selector>
   
   
  
  
  
  1.2       +1 -1      ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/Repository.java
  
  Index: Repository.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/Repository.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Repository.java	25 Oct 2004 23:13:38 -0000	1.1
  +++ Repository.java	2 Nov 2004 23:37:21 -0000	1.2
  @@ -53,7 +53,7 @@
           if (getRefid() == null) {
               return this;
           } else {
  -            Repository repository = (Repository) getCheckedRef(this.getClass(),
  +            Repository repository = (Repository) getCheckedRef(Repository.class, 
                       "Repository");
               return repository;
           }
  
  
  
  1.3       +44 -145   ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/HttpRepository.java
  
  Index: HttpRepository.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/HttpRepository.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- HttpRepository.java	30 Oct 2004 21:03:44 -0000	1.2
  +++ HttpRepository.java	2 Nov 2004 23:37:21 -0000	1.3
  @@ -16,25 +16,15 @@
    */
   package org.apache.tools.ant.taskdefs.optional.repository;
   
  -import org.apache.commons.httpclient.Credentials;
  -import org.apache.commons.httpclient.DefaultMethodRetryHandler;
  -import org.apache.commons.httpclient.HttpClient;
  -import org.apache.commons.httpclient.HttpMethod;
  -import org.apache.commons.httpclient.HttpStatus;
  -import org.apache.commons.httpclient.UsernamePasswordCredentials;
  -import org.apache.commons.httpclient.cookie.CookiePolicy;
  -import org.apache.commons.httpclient.methods.GetMethod;
  +
   import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.Project;
  -import org.apache.tools.ant.util.FileUtils;
  +import org.apache.tools.ant.taskdefs.Get;
   
   import java.io.File;
  -import java.io.FileOutputStream;
   import java.io.IOException;
  -import java.io.InputStream;
   import java.net.MalformedURLException;
   import java.net.URL;
  -import java.util.Date;
   
   /**
    * This is a base class for repositories that are built on URLs. Although you
  @@ -59,21 +49,10 @@
        */
       private String password;
   
  -
       /**
        * auth realm; can be null
        */
  -    private String realm;
  -
  -    /**
  -     * this is our http client
  -     */
  -    private HttpClient client;
  -
  -    /**
  -     * number of times to retry fetches
  -     */
  -    private int retries = 1;
  +//    private String realm;
   
       /**
        * no repository URL
  @@ -88,7 +67,6 @@
       /**
        * retry logic
        */
  -    private DefaultMethodRetryHandler retryhandler;
       public static final String ERROR_REENTRANT_USE = "Repository is already in use";
       private static final String IF_MODIFIED_SINCE = "If-Modified-Since";
       private static final int BLOCKSIZE = 8192;
  @@ -136,10 +114,12 @@
       public void setPassword(String password) {
           this.password = password;
       }
  +/*
   
       public String getRealm() {
           return realm;
       }
  +*/
   
       /**
        * set the realm for authentication; empty string is equivalent to "any
  @@ -147,39 +127,13 @@
        *
        * @param realm
        */
  -    public void setRealm(String realm) {
  +/*    public void setRealm(String realm) {
           if (realm != null) {
               this.realm = realm;
           } else {
               this.realm = null;
           }
  -    }
  -
  -
  -    /**
  -     * @return number of times to retry fetches
  -     */
  -    public int getRetries() {
  -        return retries;
  -    }
  -
  -    /**
  -     * number of times to retry fetches
  -     *
  -     * @param retries
  -     */
  -    public void setRetries(int retries) {
  -        this.retries = retries;
  -    }
  -
  -    /**
  -     * get the client
  -     *
  -     * @return
  -     */
  -    public HttpClient getClient() {
  -        return client;
  -    }
  +    }*/
   
       public GetLibraries getOwner() {
           return owner;
  @@ -211,17 +165,9 @@
        */
       public void connect(GetLibraries newOwner) {
           this.owner = newOwner;
  -        if (client != null) {
  -            throw new BuildException(ERROR_REENTRANT_USE);
  -        }
           if (!url.endsWith("/")) {
               url = url + '/';
           }
  -        client = new HttpClient();
  -        //retry handler
  -        retryhandler = new DefaultMethodRetryHandler();
  -        retryhandler.setRequestSentRetryEnabled(false);
  -        retryhandler.setRetryCount(retries);
   
           //validate the URL
           URL repository;
  @@ -230,18 +176,6 @@
           } catch (MalformedURLException e) {
               throw new BuildException(e);
           }
  -        //authentication
  -        if (username != null) {
  -            Credentials defaultcreds =
  -                    new UsernamePasswordCredentials(username, password);
  -            client.getState().setCredentials(realm,
  -                    repository.getHost(),
  -                    defaultcreds);
  -            //turn auth on on first call
  -            client.getState().setAuthenticationPreemptive(true);
  -        }
  -        //cookies
  -        client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);
       }
   
       /**
  @@ -253,8 +187,6 @@
        */
   
       public void disconnect() {
  -        client = null;
  -        retryhandler = null;
       }
   
       /**
  @@ -265,53 +197,16 @@
        * If it returns false the repository considers itself offline. Similarly,
        * any ioexception is interpreted as being offline.
        * <p/>
  -     * The Http implementation probes for the base URL being reachable, and
  -     * returning a 200 status code.
  -     *
  +     * The Http implementation does nothing
        * @return true if the repository is online.
        *
        * @throws java.io.IOException
        */
       public boolean checkRepositoryReachable() throws IOException {
  -        //return pingBaseURL();
           return true;
       }
   
  -    private boolean pingBaseURL() throws IOException {
  -        GetMethod get = createGet(getUrl());
  -        client.executeMethod(get);
  -        return get.getStatusCode() == HttpStatus.SC_OK;
  -    }
   
  -    /**
  -     * create a new getMethod against any URI
  -     *
  -     * @param url
  -     *
  -     * @return
  -     */
  -    public GetMethod createGet(String url) {
  -        GetMethod method = new GetMethod(url);
  -
  -        method.setMethodRetryHandler(retryhandler);
  -        method.setDoAuthentication(true);
  -        method.setFollowRedirects(true);
  -
  -        return method;
  -    }
  -
  -    /**
  -     * @param method
  -     * @param timestamp
  -     *
  -     * @link http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#if-modified-since
  -     * @link http://www.w3.org/Protocols/rfc850/rfc850.html#z10
  -     */
  -    public void setIfModifiedSinceHeader(HttpMethod method, long timestamp) {
  -        Date date = new Date(timestamp);
  -        //ooh, naughty, deprecated. and like why is it deprecated?
  -        method.setRequestHeader(IF_MODIFIED_SINCE, date.toGMTString());
  -    }
   
       /**
        * fetch a library from the repository
  @@ -327,42 +222,40 @@
   
           String path = getRemoteLibraryURL(library);
           logVerbose("Library URL=" + path);
  +        URL remoteURL=new URL(path);
           logVerbose("destination =" + library.getAbsolutePath());
  -        GetMethod get = createGet(path);
  +        long start, finish;
  +        start = System.currentTimeMillis();
  +        finish = System.currentTimeMillis();
           boolean useTimestamps = !getOwner().isForceDownload() &&
                   !library.exists();
  -        if (useTimestamps) {
  -            setIfModifiedSinceHeader(get, library.getLastModified());
  -        }
  -        try {
  -            long start, finish;
  -            start = System.currentTimeMillis();
  -            client.executeMethod(get);
  -            if (useTimestamps && get.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
  -                logDebug("File is not modified");
  -                //we get here if there is no change in timestamp
  -                //so no fetch
  -                return false;
  -            }
  -            if (get.getStatusCode() != HttpStatus.SC_OK) {
  -                String message = "Request Failed:"
  -                        + get.getStatusCode()
  -                        + " from " + get.getPath();
  -                logVerbose(message);
  -                logVerbose(get.getStatusLine().toString());
  -                logVerbose(get.getStatusText());
  -                throw new BuildException(message);
  -            }
  -            saveStreamToLibrary(get, library);
  -            finish = System.currentTimeMillis();
  -            long diff = finish - start;
  -            logVerbose("downloaded in " + diff / 1000 + " seconds");
  -        } finally {
  -            // Release the connection.
  -            get.releaseConnection();
  -        }
  +        boolean success=get(remoteURL, library.getLibraryFile(),useTimestamps,
  +                username, password);
  +        long diff = finish - start;
  +        logVerbose("downloaded in " + diff / 1000 + " seconds");
   
  -        return true;
  +        return success;
  +    }
  +
  +    /**
  +     * get the
  +     * @param url
  +     * @param destFile
  +     * @param useTimestamp
  +     * @return
  +     */
  +    public boolean get(URL url,File destFile,boolean useTimestamp,String user,String passwd)
  +            throws IOException {
  +        Get getTask = new Get();
  +        getTask.setProject(getProject());
  +        getTask.setTaskName("dependencies");
  +        getTask.setDest(destFile);
  +        getTask.setUsername(user);
  +        getTask.setPassword(passwd);
  +        getTask.setUseTimestamp(useTimestamp);
  +        getTask.setSrc(url);
  +        getTask.setIgnoreErrors(true);
  +        return getTask.doGet(Project.MSG_VERBOSE,null);
       }
   
       /**
  @@ -375,6 +268,10 @@
                   Project.MSG_VERBOSE);
       }
   
  +    /**
  +     * log at debug level
  +     * @param message
  +     */
       protected void logDebug(String message) {
           getOwner().log(message,
                   Project.MSG_DEBUG);
  @@ -398,6 +295,7 @@
        *
        * @throws java.io.IOException on any trouble.
        */
  +    /*
       protected void saveStreamToLibrary(GetMethod get, Library library)
               throws IOException {
           //we only get here if we are happy
  @@ -440,6 +338,7 @@
                       "Could not rename temp file to destination file");
           }
       }
  +    */
   
       /**
        * Returns a string representation of the repository
  
  
  
  1.2       +79 -0     ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/MavenRepository.java
  
  Index: MavenRepository.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/MavenRepository.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- MavenRepository.java	25 Oct 2004 23:13:38 -0000	1.1
  +++ MavenRepository.java	2 Nov 2004 23:37:21 -0000	1.2
  @@ -17,6 +17,16 @@
   
   package org.apache.tools.ant.taskdefs.optional.repository;
   
  +import org.apache.tools.ant.util.FileUtils;
  +
  +import java.io.IOException;
  +import java.io.File;
  +import java.io.FileInputStream;
  +import java.io.FileReader;
  +import java.io.InputStreamReader;
  +import java.io.Reader;
  +import java.net.URL;
  +
   
   /**
    * A Maven repository knows about maven repository layout rules It also defaults
  @@ -31,6 +41,16 @@
   
   
       /**
  +     * check the MD5 flag
  +     */
  +    public boolean checkMD5;
  +
  +    /**
  +     * this is what we think the MD5 type is
  +     */
  +    protected static final String MAVEN_MD5_FILE_TYPE = "US-ASCII";
  +
  +    /**
        * bind to the main maven repository
        */
       public MavenRepository() {
  @@ -38,6 +58,14 @@
       }
   
       /**
  +     * set this to check the MD5 signatures. SECURITY IS NOT YET FUNCTIONAL
  +     * @param checkMD5
  +     */
  +    public void setCheckMD5(boolean checkMD5) {
  +        this.checkMD5 = checkMD5;
  +    }
  +
  +    /**
        * Get the path to a remote library. This is the full URL
        *
        * @param library
  @@ -62,4 +90,55 @@
           return "Maven Repository at " + getUrl();
       }
   
  +    /**
  +     * fetch a library from the repository
  +     *
  +     * @param library
  +     *
  +     * @return true if we retrieved
  +     *
  +     * @throws org.apache.tools.ant.BuildException
  +     *
  +     */
  +    public boolean fetch(Library library) throws IOException {
  +        boolean  fetched=super.fetch(library);
  +        if(fetched && checkMD5) {
  +            //we got here if there was a fetch. so we now get the MD5 info from the file,
  +            boolean successful=false;
  +            String md5path = getRemoteLibraryURL(library) + ".md5";
  +            File md5file = File.createTempFile(library.getArchive(),".md5");
  +            Reader in = null;
  +            try {
  +                URL md5url=new URL(md5path);
  +                logVerbose("getting md5 file from " + md5path +" to "+md5file.getAbsolutePath());
  +                get(md5url,md5file, false,getUsername(), getPassword());
  +                in = new InputStreamReader(new FileInputStream(md5file),MAVEN_MD5_FILE_TYPE);
  +                char md5data[] =new char[32];
  +                in.read(md5data);
  +                logDebug("md5 data "+md5data);
  +                //TODO: verify this against a <checksum> generated signature.
  +
  +                successful=true;
  +            } catch (IOException e) {
  +                logVerbose("IO failure on MD5 fetch "+e.getMessage());
  +                throw e;
  +            } finally {
  +                FileUtils.close(in);
  +                if(md5file.exists()) {
  +                    md5file.delete();
  +                }
  +                if(!successful) {
  +                    //if security checks failed for any reason,
  +                    //delete the library file
  +                    //brute force paranoia
  +                    library.getLibraryFile().delete();
  +                }
  +            }
  +        }
  +        return fetched;
  +
  +    }
  +
   }
  +
  +// e1b1720a761ca36eaa47e1c7d802e676
  \ No newline at end of file
  
  
  
  1.3       +8 -15     ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/GetLibraries.java
  
  Index: GetLibraries.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/GetLibraries.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- GetLibraries.java	30 Oct 2004 21:03:44 -0000	1.2
  +++ GetLibraries.java	2 Nov 2004 23:37:21 -0000	1.3
  @@ -105,16 +105,6 @@
           add(repo);
       }
   
  -
  -    /**
  -     * add a maven repository.
  -     */
  -/*
  -    public void addMavenRepository(MavenRepository repo) {
  -        add(repo);
  -    }
  -*/
  -
       /**
        * bind to a repository.
        */
  @@ -173,12 +163,17 @@
           this.offline = offline;
       }
   
  +
  +    /**
  +     * get the destination directory
  +     * @return
  +     */
       public File getDestDir() {
           return destDir;
       }
   
       /**
  -     * get fore download flag
  +     * get force download flag
        * @return
        */
       public boolean isForceDownload() {
  @@ -224,7 +219,7 @@
        * @throws BuildException
        */
       public void validate() {
  -        if (destDir == null || !destDir.exists() || !destDir.isDirectory()) {
  +        if (destDir == null || !destDir.isDirectory()) {
               throw new BuildException(ERROR_NO_DEST_DIR);
           }
           if (repository == null) {
  @@ -245,6 +240,7 @@
        */
       public void execute() throws BuildException {
           validate();
  +        destDir.mkdirs();
           Repository repo = repository.resolve();
           repo.validate();
           if (libraries.size() == 0) {
  @@ -262,7 +258,6 @@
               return;
           }
   
  -
           //connect the repository
           repo.connect(this);
           try {
  @@ -413,7 +408,6 @@
               return (_next != null);
           }
   
  -
           /**
            * get the next element
            * @return
  @@ -426,7 +420,6 @@
               _next = null;
               return result;
           }
  -
   
           /**
            * removal is not supported
  
  
  
  1.2       +4 -1      ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/RepositoryRef.java
  
  Index: RepositoryRef.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/optional/repository/RepositoryRef.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RepositoryRef.java	25 Oct 2004 23:13:38 -0000	1.1
  +++ RepositoryRef.java	2 Nov 2004 23:37:21 -0000	1.2
  @@ -29,6 +29,9 @@
    * @since Ant1.7
    */
   public final class RepositoryRef extends Repository {
  +    /** this constant name is only funny to COM developers  
  +     */
  +    public static final String E_NOTIMPL = "Not Implemented";
   
   
       /**
  @@ -70,7 +73,7 @@
        * @return
        */
       public boolean fetch(Library library) throws IOException {
  -        throw new BuildException("Not Implemented");
  +        throw new BuildException(E_NOTIMPL);
       }
   
   }
  
  
  
  1.4       +5 -1      ant/src/testcases/org/apache/tools/ant/taskdefs/optional/repository/GetLibrariesTest.java
  
  Index: GetLibrariesTest.java
  ===================================================================
  RCS file: /home/cvs/ant/src/testcases/org/apache/tools/ant/taskdefs/optional/repository/GetLibrariesTest.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- GetLibrariesTest.java	30 Oct 2004 21:03:44 -0000	1.3
  +++ GetLibrariesTest.java	2 Nov 2004 23:37:21 -0000	1.4
  @@ -66,7 +66,7 @@
       /**
        * refs are  broken
        * */
  -    public void NotestFunctionalInline() {
  +    public void testFunctionalInline() {
           execIfOnline("testFunctionalInline");
       }
       
  @@ -113,6 +113,10 @@
   
       public void testPathID() {
           execIfOnline("testPathID");
  +    }
  +
  +    public void testSecurity() {
  +        execIfOnline("testSecurity");
       }
   
    }
  
  
  
  1.3       +7 -0      ant/src/etc/testcases/taskdefs/optional/getlibraries.xml
  
  Index: getlibraries.xml
  ===================================================================
  RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/optional/getlibraries.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- getlibraries.xml	30 Oct 2004 21:03:44 -0000	1.2
  +++ getlibraries.xml	2 Nov 2004 23:37:21 -0000	1.3
  @@ -157,5 +157,12 @@
         Did not find commons logging in the path
       </fail>
     </target>
  +
  +  <target name="testSecurity" depends="init">
  +    <getlib>
  +      <mavenrepository checkMD5="true"/>
  +    </getlib>
  +    <assert-downloaded/>
  +  </target>
   </project>
   
  
  
  
  1.44      +244 -140  ant/src/main/org/apache/tools/ant/taskdefs/Get.java
  
  Index: Get.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Get.java,v
  retrieving revision 1.43
  retrieving revision 1.44
  diff -u -r1.43 -r1.44
  --- Get.java	22 Apr 2004 14:48:31 -0000	1.43
  +++ Get.java	2 Nov 2004 23:37:21 -0000	1.44
  @@ -21,6 +21,7 @@
   import java.io.FileOutputStream;
   import java.io.IOException;
   import java.io.InputStream;
  +import java.io.PrintStream;
   import java.net.HttpURLConnection;
   import java.net.URL;
   import java.net.URLConnection;
  @@ -51,12 +52,47 @@
       private String pword = null;
   
   
  +
       /**
        * Does the work.
        *
        * @exception BuildException Thrown in unrecoverable error.
        */
       public void execute() throws BuildException {
  +
  +        //set up logging
  +        int logLevel = Project.MSG_INFO;
  +        DownloadProgress progress=null;
  +        if (verbose) {
  +            progress = new VerboseProgress(System.out);
  +        }
  +
  +        //execute the get
  +        try {
  +            doGet(logLevel, progress);
  +        } catch (IOException ioe) {
  +            log("Error getting " + source + " to " + dest);
  +            if (!ignoreErrors) {
  +                throw new BuildException(ioe, getLocation());
  +            }
  +        }
  +    }
  +
  +    /**
  +     * make a get request, with the supplied progress and logging info.
  +     * All the other config parameters are set at the task level,
  +     * source, dest, ignoreErrors, etc.
  +     * @param logLevel level to log at, see {@link Project#log(String, int)}
  +     * @param progress progress callback; null for no-callbacks
  +     * @return true for a successful download, false otherwise.
  +     * The return value is only relevant when {@link #ignoreErrors} is true, as
  +     * when false all failures raise BuildExceptions. 
  +     * @throws IOException for network trouble
  +     * @throws BuildException for argument errors, or other trouble when ignoreErrors
  +     * is false.
  +     */
  +    public boolean doGet(int logLevel, DownloadProgress progress)
  +            throws IOException {
           if (source == null) {
               throw new BuildException("src attribute is required", getLocation());
           }
  @@ -67,172 +103,155 @@
   
           if (dest.exists() && dest.isDirectory()) {
               throw new BuildException("The specified destination is a directory",
  -                                     getLocation());
  +                    getLocation());
           }
   
           if (dest.exists() && !dest.canWrite()) {
               throw new BuildException("Can't write to " + dest.getAbsolutePath(),
  -                                     getLocation());
  +                    getLocation());
           }
  +        //dont do any progress, unless asked
  +        if(progress==null) {
  +            progress = new NullProgress();
  +        }
  +        log("Getting: " + source, logLevel);
   
  -        try {
  -
  -            log("Getting: " + source);
  -
  -            //set the timestamp to the file date.
  -            long timestamp = 0;
  -
  -            boolean hasTimestamp = false;
  -            if (useTimestamp && dest.exists()) {
  -                timestamp = dest.lastModified();
  -                if (verbose) {
  -                    Date t = new Date(timestamp);
  -                    log("local file date : " + t.toString());
  -                }
  +        //set the timestamp to the file date.
  +        long timestamp = 0;
   
  -                hasTimestamp = true;
  +        boolean hasTimestamp = false;
  +        if (useTimestamp && dest.exists()) {
  +            timestamp = dest.lastModified();
  +            if (verbose) {
  +                Date t = new Date(timestamp);
  +                log("local file date : " + t.toString(), logLevel);
               }
  +            hasTimestamp = true;
  +        }
   
  -            //set up the URL connection
  -            URLConnection connection = source.openConnection();
  -            //modify the headers
  -            //NB: things like user authentication could go in here too.
  -            if (useTimestamp && hasTimestamp) {
  -                connection.setIfModifiedSince(timestamp);
  -            }
  -            // prepare Java 1.1 style credentials
  -            if (uname != null || pword != null) {
  -                String up = uname + ":" + pword;
  -                String encoding;
  -                // check to see if sun's Base64 encoder is available.
  -                try {
  -                    Object encoder =
  -                            Class.forName("sun.misc.BASE64Encoder").newInstance();
  -                    encoding = (String)
  -                            encoder.getClass().getMethod("encode", new Class[] {byte[].class})
  -                            .invoke(encoder, new Object[] {up.getBytes()});
  -
  -                } catch (Exception ex) { // sun's base64 encoder isn't available
  -                    Base64Converter encoder = new Base64Converter();
  -                    encoding = encoder.encode(up.getBytes());
  -                }
  -                connection.setRequestProperty ("Authorization",
  -                                               "Basic " + encoding);
  -            }
  +        //set up the URL connection
  +        URLConnection connection = source.openConnection();
  +        //modify the headers
  +        //NB: things like user authentication could go in here too.
  +        if (useTimestamp && hasTimestamp) {
  +            connection.setIfModifiedSince(timestamp);
  +        }
  +        // prepare Java 1.1 style credentials
  +        if (uname != null || pword != null) {
  +            String up = uname + ":" + pword;
  +            String encoding;
  +            //we do not use the sun impl for portability,
  +            //and always use our own implementation for consistent
  +            //testing
  +            Base64Converter encoder = new Base64Converter();
  +            encoding = encoder.encode(up.getBytes());
  +            connection.setRequestProperty ("Authorization",
  +                    "Basic " + encoding);
  +        }
   
  -            //connect to the remote site (may take some time)
  -            connection.connect();
  -            //next test for a 304 result (HTTP only)
  -            if (connection instanceof HttpURLConnection) {
  -                HttpURLConnection httpConnection
  +        //connect to the remote site (may take some time)
  +        connection.connect();
  +        //next test for a 304 result (HTTP only)
  +        if (connection instanceof HttpURLConnection) {
  +            HttpURLConnection httpConnection
                       = (HttpURLConnection) connection;
  -                if (httpConnection.getResponseCode()
  +            if (httpConnection.getResponseCode()
                       == HttpURLConnection.HTTP_NOT_MODIFIED)  {
  -                    //not modified so no file download. just return
  -                    //instead and trace out something so the user
  -                    //doesn't think that the download happened when it
  -                    //didn't
  -                    log("Not modified - so not downloaded");
  -                    return;
  -                }
  -                // test for 401 result (HTTP only)
  -                if (httpConnection.getResponseCode()
  +                //not modified so no file download. just return
  +                //instead and trace out something so the user
  +                //doesn't think that the download happened when it
  +                //didn't
  +                log("Not modified - so not downloaded", logLevel);
  +                return false;
  +            }
  +            // test for 401 result (HTTP only)
  +            if (httpConnection.getResponseCode()
                       == HttpURLConnection.HTTP_UNAUTHORIZED)  {
  -                    String message = "HTTP Authorization failure";
  -                    if (ignoreErrors) {
  -                        log(message, Project.MSG_WARN);
  -                        return;
  -                    } else {
  -                        throw new BuildException(message);
  -                    }
  +                String message = "HTTP Authorization failure";
  +                if (ignoreErrors) {
  +                    log(message, logLevel);
  +                    return false;
  +                } else {
  +                    throw new BuildException(message);
                   }
  -
               }
   
  -            //REVISIT: at this point even non HTTP connections may
  -            //support the if-modified-since behaviour -we just check
  -            //the date of the content and skip the write if it is not
  -            //newer. Some protocols (FTP) don't include dates, of
  -            //course.
  -
  -            InputStream is = null;
  -            for (int i = 0; i < 3; i++) {
  -                try {
  -                    is = connection.getInputStream();
  -                    break;
  -                } catch (IOException ex) {
  -                    log("Error opening connection " + ex);
  -                }
  +        }
  +
  +        //REVISIT: at this point even non HTTP connections may
  +        //support the if-modified-since behaviour -we just check
  +        //the date of the content and skip the write if it is not
  +        //newer. Some protocols (FTP) don't include dates, of
  +        //course.
  +
  +        InputStream is = null;
  +        for (int i = 0; i < 3; i++) {
  +            //this three attempt trick is to get round quirks in different
  +            //Java implementations. Some of them take a few goes to bind
  +            //property; we ignore the first couple of such failures.
  +            try {
  +                is = connection.getInputStream();
  +                break;
  +            } catch (IOException ex) {
  +                log("Error opening connection " + ex,logLevel);
               }
  -            if (is == null) {
  -                log("Can't get " + source + " to " + dest);
  -                if (ignoreErrors) {
  -                    return;
  -                }
  -                throw new BuildException("Can't get " + source + " to " + dest,
  -                                         getLocation());
  +        }
  +        if (is == null) {
  +            log("Can't get " + source + " to " + dest,logLevel);
  +            if (ignoreErrors) {
  +                return false;
               }
  +            throw new BuildException("Can't get " + source + " to " + dest,
  +                    getLocation());
  +        }
   
  -            FileOutputStream fos = new FileOutputStream(dest);
  -            boolean finished = false;
  -            try {
  -                byte[] buffer = new byte[100 * 1024];
  -                int length;
  -                int dots = 0;
  -
  -                while ((length = is.read(buffer)) >= 0) {
  -                    fos.write(buffer, 0, length);
  -                    if (verbose) {
  -                        System.out.print(".");
  -                        if (dots++ > 50) {
  -                            System.out.flush();
  -                            dots = 0;
  -                        }
  -                    }
  -                }
  -                if (verbose) {
  -                    System.out.println();
  -                }
  -                finished = true;
  -            } finally {
  -                if (fos != null) {
  -                    fos.close();
  -                }
  -                is.close();
  -                // we have started to (over)write dest, but failed.
  -                // Try to delete the garbage we'd otherwise leave
  -                // behind.
  -                if (!finished) {
  -                    dest.delete();
  -                }
  +        FileOutputStream fos = new FileOutputStream(dest);
  +        progress.beginDownload();
  +        boolean finished = false;
  +        try {
  +            byte[] buffer = new byte[100 * 1024];
  +            int length;
  +            while ((length = is.read(buffer)) >= 0) {
  +                fos.write(buffer, 0, length);
  +                progress.onTick();
  +            }
  +            finished = true;
  +        } finally {
  +            FileUtils.close(fos);
  +            FileUtils.close(is);
  +
  +            // we have started to (over)write dest, but failed.
  +            // Try to delete the garbage we'd otherwise leave
  +            // behind.
  +            if (!finished) {
  +                dest.delete();
               }
  +        }
  +        progress.endDownload();
   
  -            //if (and only if) the use file time option is set, then
  -            //the saved file now has its timestamp set to that of the
  -            //downloaded file
  -            if (useTimestamp)  {
  -                long remoteTimestamp = connection.getLastModified();
  -                if (verbose)  {
  -                    Date t = new Date(remoteTimestamp);
  -                    log("last modified = " + t.toString()
  +        //if (and only if) the use file time option is set, then
  +        //the saved file now has its timestamp set to that of the
  +        //downloaded file
  +        if (useTimestamp)  {
  +            long remoteTimestamp = connection.getLastModified();
  +            if (verbose)  {
  +                Date t = new Date(remoteTimestamp);
  +                log("last modified = " + t.toString()
                           + ((remoteTimestamp == 0)
  -                          ? " - using current time instead"
  -                          : ""));
  -                }
  -                if (remoteTimestamp != 0) {
  -                    FileUtils.newFileUtils()
  -                        .setFileLastModified(dest, remoteTimestamp);
  -                }
  +                        ? " - using current time instead"
  +                        : ""),logLevel);
               }
  -        } catch (IOException ioe) {
  -            log("Error getting " + source + " to " + dest);
  -            if (ignoreErrors) {
  -                return;
  +            if (remoteTimestamp != 0) {
  +                FileUtils.newFileUtils()
  +                        .setFileLastModified(dest, remoteTimestamp);
               }
  -            throw new BuildException(ioe, getLocation());
           }
  +
  +        //successful download
  +        return true;
       }
   
  +
       /**
        * Set the URL to get.
        *
  @@ -317,7 +336,7 @@
       *
       *********************************************************************/
   
  -    private static class  Base64Converter {
  +    protected static class  Base64Converter {
   
           public final char [ ]  alphabet = {
               'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',   //  0 to  7
  @@ -388,4 +407,89 @@
               return new String(out);
           }
        }
  +
  +    public interface DownloadProgress {
  +        /**
  +         * begin a download
  +         */
  +        public void beginDownload();
  +
  +        /**
  +         * tick handler
  +         *
  +         */
  +        public void onTick();
  +
  +        /**
  +         * end a download
  +         */
  +        public void endDownload();
  +    }
  +
  +    /**
  +     * do nothing with progress info
  +     */
  +    public static class NullProgress implements DownloadProgress {
  +
  +        /**
  +         * begin a download
  +         */
  +        public void beginDownload() {
  +
  +        }
  +
  +        /**
  +         * tick handler
  +         *
  +         */
  +        public void onTick() {
  +        }
  +
  +        /**
  +         * end a download
  +         */
  +        public void endDownload() {
  +
  +        }
  +    }
  +
  +    /**
  +     * verbose progress system prints to some output stream
  +     */
  +    public static class VerboseProgress implements DownloadProgress  {
  +        private int dots = 0;
  +        PrintStream out;
  +
  +        public VerboseProgress(PrintStream out) {
  +            this.out = out;
  +        }
  +
  +        /**
  +         * begin a download
  +         */
  +        public void beginDownload() {
  +            dots=0;
  +        }
  +
  +        /**
  +         * tick handler
  +         *
  +         */
  +        public void onTick() {
  +            out.print(".");
  +            if (dots++ > 50) {
  +                out.flush();
  +                dots = 0;
  +            }
  +        }
  +
  +        /**
  +         * end a download
  +         */
  +        public void endDownload() {
  +            out.println();
  +            out.flush();
  +        }
  +    }
  +
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org