You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by bo...@apache.org on 2006/06/28 22:24:20 UTC

svn commit: r417866 [2/3] - in /ant/sandbox/antlibs/http/trunk: docs/ src/etc/testcases/http/ src/main/org/apache/ant/http/ src/war/WEB-INF/ src/war/resources/

Modified: ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpPost.java
URL: http://svn.apache.org/viewvc/ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpPost.java?rev=417866&r1=417865&r2=417866&view=diff
==============================================================================
--- ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpPost.java (original)
+++ ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpPost.java Wed Jun 28 13:24:19 2006
@@ -1,195 +1,195 @@
-/*
- * Copyright  2001-2006 The Apache Software Foundation
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- */
-
-package org.apache.ant.http;
-
-import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.Project;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.net.URLConnection;
-import java.util.Vector;
-
-/**
- * this class does post of form content or raw files. you can have one or the
- * other -as soon as a file is specified all the other properties are dropped on
- * the floor. a file post will have content type determined from the extension,
- * you can override it
- *
- * @created March 17, 2001
- */
-
-public class HttpPost extends HttpTask {
-
-    /**
-     * file to upload. Null is ok
-     */
-
-    protected File postFile = null;
-
-    /**
-     * set the file to post.
-     */
-    public void setUploadFile(File postFile) {
-        this.postFile = postFile;
-    }
-
-    /**
-     * query the post file.
-     *
-     * @return the file or null for 'not defined'
-     */
-    public File getUploadFile() {
-        return postFile;
-    }
-
-    /**
-     * content type. ignored when the file is null, and even then we guess it if
-     * aint specified
-     */
-
-    private String contentType;
-
-    /**
-     * set the content type. Recommended if a file is being uploaded
-     */
-    public void setContentType(String contentType) {
-        this.contentType = contentType;
-    }
-
-    /**
-     * query the content type.
-     *
-     * @return the content type or null for 'not defined'
-     */
-    public String getContentType() {
-        return contentType;
-    }
-
-    /**
-     * in a POST, params go in the payload, not in the URL.
-     *
-     * @return false always
-     */
-
-    protected boolean areParamsAddedToUrl() {
-        return false;
-    }
-
-    /**
-     * this override of the base connect pumps up the parameter vector as form
-     * data.
-     *
-     * @param connection where to connect to
-     * @throws BuildException build trouble
-     * @throws IOException    IO trouble
-     */
-    protected URLConnection doConnect(URLConnection connection)
-            throws BuildException, IOException {
-
-        if (postFile == null) {
-            return doConnectFormPost(connection);
-        } else {
-            return doConnectFilePost(connection);
-        }
-    }
-
-    /**
-     * feed up the parameter vector as form data.
-     *
-     * @param connection where to connect to
-     * @throws BuildException build trouble
-     * @throws IOException    IO trouble
-     */
-    protected URLConnection doConnectFormPost(URLConnection connection)
-            throws BuildException, IOException {
-
-        log("Posting data as a form", Project.MSG_VERBOSE);
-        // Create the output payload
-        ByteArrayOutputStream byteStream = new ByteArrayOutputStream(256);
-        PrintWriter out = new PrintWriter(byteStream);
-        writePostData(out);
-        out.flush();
-        out.close();
-        byte[] data = byteStream.toByteArray();
-        //send it
-
-        return doConnectWithUpload(connection,
-                "application/x-www-form-urlencoded",
-                byteStream.size(),
-                new ByteArrayInputStream(data));
-    }
-
-    /**
-     * feed up the data file.
-     *
-     * @param connection where to connect to
-     * @throws BuildException build trouble
-     * @throws IOException    IO trouble
-     */
-    protected URLConnection doConnectFilePost(URLConnection connection)
-            throws BuildException, IOException {
-        int size = (int) postFile.length();
-        log("Posting file " + postFile, Project.MSG_VERBOSE);
-        InputStream instream = new FileInputStream(postFile);
-        String type = contentType;
-        if (type == null) {
-            type = ContentGuesser.guessContentType(postFile.getName());
-        }
-        return doConnectWithUpload(connection,
-                type,
-                size,
-                instream);
-    }
-
-
-    /**
-     * write out post data in form mode.
-     *
-     * @param out Description of Parameter
-     */
-    protected void writePostData(PrintWriter out) {
-        HttpRequestParameter param;
-        Vector params = getRequestParameters();
-        for (int i = 0; i < params.size(); i++) {
-            if (i > 0) {
-                out.print('&');
-            }
-            param = (HttpRequestParameter) params.get(i);
-            out.print(param.toString());
-            log("parameter : " + param.toString(), Project.MSG_DEBUG);
-        }
-    }
-
-    /**
-     * this must be overridden by implementations to set the request method to
-     * GET, POST, whatever.
-     *
-     * @return the method string
-     */
-    public String getRequestMethod() {
-        return "POST";
-    }
-
-
-}
+/*
+ * Copyright  2001-2006 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.ant.http;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.URLConnection;
+import java.util.Vector;
+
+/**
+ * this class does post of form content or raw files. you can have one or the
+ * other -as soon as a file is specified all the other properties are dropped on
+ * the floor. a file post will have content type determined from the extension,
+ * you can override it
+ *
+ * @created March 17, 2001
+ */
+
+public class HttpPost extends HttpTask {
+
+    /**
+     * file to upload. Null is ok
+     */
+
+    protected File postFile = null;
+
+    /**
+     * set the file to post.
+     */
+    public void setUploadFile(File postFile) {
+        this.postFile = postFile;
+    }
+
+    /**
+     * query the post file.
+     *
+     * @return the file or null for 'not defined'
+     */
+    public File getUploadFile() {
+        return postFile;
+    }
+
+    /**
+     * content type. ignored when the file is null, and even then we guess it if
+     * aint specified
+     */
+
+    private String contentType;
+
+    /**
+     * set the content type. Recommended if a file is being uploaded
+     */
+    public void setContentType(String contentType) {
+        this.contentType = contentType;
+    }
+
+    /**
+     * query the content type.
+     *
+     * @return the content type or null for 'not defined'
+     */
+    public String getContentType() {
+        return contentType;
+    }
+
+    /**
+     * in a POST, params go in the payload, not in the URL.
+     *
+     * @return false always
+     */
+
+    protected boolean areParamsAddedToUrl() {
+        return false;
+    }
+
+    /**
+     * this override of the base connect pumps up the parameter vector as form
+     * data.
+     *
+     * @param connection where to connect to
+     * @throws BuildException build trouble
+     * @throws IOException    IO trouble
+     */
+    protected URLConnection doConnect(URLConnection connection)
+            throws BuildException, IOException {
+
+        if (postFile == null) {
+            return doConnectFormPost(connection);
+        } else {
+            return doConnectFilePost(connection);
+        }
+    }
+
+    /**
+     * feed up the parameter vector as form data.
+     *
+     * @param connection where to connect to
+     * @throws BuildException build trouble
+     * @throws IOException    IO trouble
+     */
+    protected URLConnection doConnectFormPost(URLConnection connection)
+            throws BuildException, IOException {
+
+        log("Posting data as a form", Project.MSG_VERBOSE);
+        // Create the output payload
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream(256);
+        PrintWriter out = new PrintWriter(byteStream);
+        writePostData(out);
+        out.flush();
+        out.close();
+        byte[] data = byteStream.toByteArray();
+        //send it
+
+        return doConnectWithUpload(connection,
+                "application/x-www-form-urlencoded",
+                byteStream.size(),
+                new ByteArrayInputStream(data));
+    }
+
+    /**
+     * feed up the data file.
+     *
+     * @param connection where to connect to
+     * @throws BuildException build trouble
+     * @throws IOException    IO trouble
+     */
+    protected URLConnection doConnectFilePost(URLConnection connection)
+            throws BuildException, IOException {
+        int size = (int) postFile.length();
+        log("Posting file " + postFile, Project.MSG_VERBOSE);
+        InputStream instream = new FileInputStream(postFile);
+        String type = contentType;
+        if (type == null) {
+            type = ContentGuesser.guessContentType(postFile.getName());
+        }
+        return doConnectWithUpload(connection,
+                type,
+                size,
+                instream);
+    }
+
+
+    /**
+     * write out post data in form mode.
+     *
+     * @param out Description of Parameter
+     */
+    protected void writePostData(PrintWriter out) {
+        HttpRequestParameter param;
+        Vector params = getRequestParameters();
+        for (int i = 0; i < params.size(); i++) {
+            if (i > 0) {
+                out.print('&');
+            }
+            param = (HttpRequestParameter) params.get(i);
+            out.print(param.toString());
+            log("parameter : " + param.toString(), Project.MSG_DEBUG);
+        }
+    }
+
+    /**
+     * this must be overridden by implementations to set the request method to
+     * GET, POST, whatever.
+     *
+     * @return the method string
+     */
+    public String getRequestMethod() {
+        return "POST";
+    }
+
+
+}

Propchange: ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpPost.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpRequestParameter.java
URL: http://svn.apache.org/viewvc/ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpRequestParameter.java?rev=417866&r1=417865&r2=417866&view=diff
==============================================================================
--- ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpRequestParameter.java (original)
+++ ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpRequestParameter.java Wed Jun 28 13:24:19 2006
@@ -1,106 +1,106 @@
-/*
- * Copyright  2001-2006 The Apache Software Foundation
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- */
-
-package org.apache.ant.http;
-
-import org.apache.tools.ant.ProjectComponent;
-
-import java.net.URLEncoder;
-
-/**
- * This class is used to store name-value pairs for request parameters and
- * headers.
- *
- * @created March 17, 2001
- */
-
-public class HttpRequestParameter extends ProjectComponent {
-
-    /**
-     * request name.
-     */
-    private String name;
-
-    /**
-     * request value.
-     */
-    private String value;
-
-
-    /**
-     * Sets the Name of the request.
-     *
-     * @param name The new Name value
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * What is the request name?
-     *
-     * @return The Name value
-     */
-    public String getName() {
-        return name;
-    }
-
-
-    /**
-     * Sets the Value of the request.
-     *
-     * @param value The new Value value
-     */
-    public void setValue(String value) {
-        this.value = value;
-    }
-
-
-
-    /**
-     * What is the request value?
-     *
-     * @return The Value
-     */
-    public String getValue() {
-        return value;
-    }
-
-
-    /**
-     * set the inline text, with property expansion.
-     *
-     * @param text Text to add to the request.
-     */
-    public void addText(String text) {
-        this.value = getProject().replaceProperties(text);
-    }
-
-
-    /**
-     * simple stringifier returning name and value encoded for use in HTTP
-     * requests Although deprecated, the new version only came with Java1.4.
-     *
-     * @return a string for informational purposes
-     */
-    public String toString() {
-        return URLEncoder.encode(getName()) +
-                '=' + URLEncoder.encode(getValue());
-    }
-
-}
-
+/*
+ * Copyright  2001-2006 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.ant.http;
+
+import org.apache.tools.ant.ProjectComponent;
+
+import java.net.URLEncoder;
+
+/**
+ * This class is used to store name-value pairs for request parameters and
+ * headers.
+ *
+ * @created March 17, 2001
+ */
+
+public class HttpRequestParameter extends ProjectComponent {
+
+    /**
+     * request name.
+     */
+    private String name;
+
+    /**
+     * request value.
+     */
+    private String value;
+
+
+    /**
+     * Sets the Name of the request.
+     *
+     * @param name The new Name value
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * What is the request name?
+     *
+     * @return The Name value
+     */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Sets the Value of the request.
+     *
+     * @param value The new Value value
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+
+
+    /**
+     * What is the request value?
+     *
+     * @return The Value
+     */
+    public String getValue() {
+        return value;
+    }
+
+
+    /**
+     * set the inline text, with property expansion.
+     *
+     * @param text Text to add to the request.
+     */
+    public void addText(String text) {
+        this.value = getProject().replaceProperties(text);
+    }
+
+
+    /**
+     * simple stringifier returning name and value encoded for use in HTTP
+     * requests Although deprecated, the new version only came with Java1.4.
+     *
+     * @return a string for informational purposes
+     */
+    public String toString() {
+        return URLEncoder.encode(getName()) +
+                '=' + URLEncoder.encode(getValue());
+    }
+
+}
+

Propchange: ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpRequestParameter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpTask.java
URL: http://svn.apache.org/viewvc/ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpTask.java?rev=417866&r1=417865&r2=417866&view=diff
==============================================================================
--- ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpTask.java (original)
+++ ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpTask.java Wed Jun 28 13:24:19 2006
@@ -1,1083 +1,1083 @@
-/*
- * Copyright  2001-2006 The Apache Software Foundation
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- */
-
-
-package org.apache.ant.http;
-
-import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.Project;
-import org.apache.tools.ant.Task;
-import org.apache.tools.ant.types.EnumeratedAttribute;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Date;
-import java.util.Vector;
-
-/**
- * This class is a foundational class for all the tasks which implement http
- * methods. To implement a subclass you *must* provide an implementation of
- * getRequestMethod(). Consider also stating the parameter policy
- * (areParamsAddedToUrl()) and then, if needed, overriding doConnect, and the
- * onConnected(), OnDownloadFinished() methods.
- *
- * @created March 17, 2001
- */
-public abstract class HttpTask extends Task {
-
-    /**
-     * flag to control action on execution trouble.
-     */
-    protected boolean failOnError = true;
-
-    /**
-     * this sets the size of the buffer and the hash for download (Kilobytes).
-     */
-
-    protected int blockSize = 64;
-
-    /**
-     * property to set on success.
-     */
-
-    protected String status;
-
-    /**
-     * source URL- required.
-     */
-    private String source;
-
-    /**
-     * destination for download.
-     */
-    private File destFile;
-    /**
-     * verbose flag gives extra information.
-     */
-    private boolean verbose = false;
-
-    /**
-     * timestamp based download flag. off by default.
-     */
-    private boolean useTimestamp = false;
-
-    /**
-     * authorization mechanism in use.
-     */
-    private int authType = AUTH_NONE;
-
-    /**
-     * username for authentication.
-     */
-    private String username;
-
-    /**
-     * password for authentication.
-     */
-    private String password;
-
-    /**
-     * parameters to send on a request.
-     */
-    private Vector params = new Vector();
-
-    /**
-     * headers to send on a request
-     */
-    private Vector headers = new Vector();
-
-    /**
-     * cache policy.
-     */
-    private boolean usecaches = false;
-
-    /**
-     * the name of a destination property.
-     */
-
-    private String destProperty = null;
-
-    /**
-     * a flag to control whether or not response codes are acted on.
-     */
-    private boolean useResponseCode = true;
-
-    /**
-     * No authentication specified.
-     */
-    public final static int AUTH_NONE = 0;
-
-    /**
-     * basic 'cleartext' authentication.
-     */
-    public final static int AUTH_BASIC = 1;
-
-    /**
-     * digest auth. not actually supported but present for completeness.
-     */
-    public final static int AUTH_DIGEST = 2;
-
-
-    /**
-     * turn caching on or off. only relevant for protocols and methods which are
-     * cacheable (HEAD, GET) on http.
-     *
-     * @param usecaches The new UseCaches value
-     */
-    public void setUseCaches(boolean usecaches) {
-        this.usecaches = usecaches;
-    }
-
-    /**
-     * control whether response codes are used to determine success/failure.
-     *
-     * @param useResponseCode the new value
-     */
-    public void setUseResponseCode(boolean useResponseCode) {
-        this.useResponseCode = useResponseCode;
-    }
-
-
-    /**
-     * Set the URL.
-     *
-     * @param u URL for the operation.
-     */
-    public void setURL(String u) {
-        this.source = u;
-    }
-
-
-    /**
-     * the local destination for any response. this can be null for "don't
-     * download".
-     *
-     * @param destFile Path to file.
-     */
-    public void setDestFile(File destFile) {
-        this.destFile = destFile;
-    }
-
-    /**
-     * the local destination for any response. this can be null for "don't
-     * download"
-     *
-     * @param name Path to file.
-     */
-    public void setDestinationProperty(String name) {
-        this.destProperty = name;
-    }
-
-
-    /**
-     * Be verbose, if set to " <CODE>true</CODE> ".
-     *
-     * @param verbose The new Verbose value
-     */
-    public void setVerbose(boolean verbose) {
-        this.verbose = verbose;
-    }
-
-
-    /**
-     * set the fail on error flag.
-     *
-     * @param b The new FailOnError value
-     */
-    public void setFailOnError(boolean b) {
-        failOnError = b;
-    }
-
-
-    /**
-     * Use timestamps, if set to " <CODE>true</CODE> ". <p>
-     * <p/>
-     * In this situation, the if-modified-since header is set so that the file
-     * is only fetched if it is newer than the local file (or there is no local
-     * file) This flag is only valid on HTTP connections, it is ignored in other
-     * cases. When the flag is set, the local copy of the downloaded file will
-     * also have its timestamp set to the remote file time. <br> Note that
-     * remote files of date 1/1/1970 (GMT) are treated as 'no timestamp', and
-     * web servers often serve files with a timestamp in the future by replacing
-     * their timestamp with that of the current time. Also, inter-computer clock
-     * differences can cause no end of grief.
-     *
-     * @param usetimestamp The new UseTimestamp value
-     */
-    public void setUseTimestamp(boolean usetimestamp) {
-        this.useTimestamp = usetimestamp;
-    }
-
-
-    /**
-     * Sets the Authtype attribute of the HttpTask object REVISIT/REFACTOR.
-     *
-     * @param type The new Authtype value
-     */
-    public void setAuthtype(AuthMethodType type) {
-        this.authType = type.getIndex();
-    }
-
-
-    /**
-     * Sets the Username used for authentication. setting the username
-     * implicitly turns authentication on.
-     *
-     * @param username The new Username value
-     */
-    public void setUsername(String username) {
-        this.username = username;
-        if (authType == AUTH_NONE) {
-            authType = AUTH_BASIC;
-        }
-    }
-
-
-    /**
-     * Sets the Password for an authenticated request.
-     *
-     * @param password The new Password value
-     */
-    public void setPassword(String password) {
-        this.password = password;
-    }
-
-
-    /**
-     * set a property to be set in the event of success.
-     *
-     * @param status The new SuccessProperty value
-     */
-    public void setStatus(String status) {
-        this.status = status;
-    }
-
-    /**
-     * get the block size in kilobytes.
-     */
-
-    public int getBlockSize() {
-        return blockSize;
-    }
-
-    /**
-     * set the new block size for download (in kilobytes).
-     *
-     * @param blocksize the new value 
-     */
-    public void setBlockSize(int blocksize) {
-        this.blockSize = blocksize;
-    }
-
-
-    /**
-     * query cache policy.
-     *
-     * @return The UseCaches value
-     */
-    public boolean getUseCaches() {
-        return usecaches;
-    }
-
-
-    /**
-     * query fail on error flag.
-     *
-     * @return The FailFailOnError value
-     */
-    public boolean getFailOnError() {
-        return failOnError;
-    }
-
-
-    /**
-     * get the username.
-     *
-     * @return current username or null for 'none'
-     */
-    public String getUsername() {
-        return username;
-    }
-
-
-    /**
-     * get the password.
-     *
-     * @return current password or null for 'none'
-     */
-    public String getPassword() {
-        return password;
-    }
-
-
-    /**
-     * @return The RemoteURL value.
-     */
-    public String getURL() {
-        return source;
-    }
-
-
-    /**
-     * Get the vector of access parameters.
-     *
-     * @return The RequestParameters value
-     */
-    public Vector getRequestParameters() {
-        return params;
-    }
-
-
-    /**
-     * accessor of success property name
-     *
-     * @return The SuccessProperty value
-     */
-    public String getStatus() {
-        return status;
-    }
-
-    /**
-     * accessor of destination property name
-     *
-     * @return The destination value
-     */
-    public String getDestinationProperty() {
-        return destProperty;
-    }
-
-    /**
-     * accessor of destination
-     *
-     * @return Thedestination
-     */
-    public File getDestFile() {
-        return destFile;
-    }
-
-
-    /**
-     * if the user wanted a success property, this sets it. of course, it is only
-     * relevant if failonerror=false
-     */
-
-    public void noteSuccess() {
-        if (status != null && status.length() > 0) {
-            getProject().setProperty(status, "true");
-        }
-    }
-
-
-    /**
-     * Does the work.
-     *
-     * @throws BuildException Thrown in unrecoverable error.
-     */
-    public void execute() {
-
-        //check arguments, will bail out if there
-        //was trouble 
-        verifyArguments();
-
-        //set up the URL connection
-        URL url = buildURL();
-
-        try {
-
-            //now create a connection
-            URLConnection connection = url.openConnection();
-
-            //set caching option to whatever
-            connection.setUseCaches(getUseCaches());
-
-            //set the timestamp option if flag is set and
-            //the local file actually exists.
-            long localTimestamp = getTimestamp();
-            if (localTimestamp != 0) {
-                if (verbose) {
-                    Date t = new Date(localTimestamp);
-                    log("local file date : " + t.toString());
-                }
-                connection.setIfModifiedSince(localTimestamp);
-            }
-
-            // Set auth header, if specified
-            //NB: verifyArguments will already have checked that you can't
-            //have a null username with a non-null strategy.
-            HttpAuthenticationStrategy authStrategy = getAuthStrategy();
-            if (authStrategy != null) {
-                authStrategy.setAuthenticationHeader(connection,
-                        null,
-                        username,
-                        password);
-            }
-
-            // Set explicitly specified request headers
-            HttpRequestParameter header;
-            for (int i = 0; i < headers.size(); i++) {
-                header = (HttpRequestParameter) headers.get(i);
-                connection.setRequestProperty(header.getName(),
-                        header.getValue());
-            }
-
-            //cast to an http connection if we can,
-            //then set the request method pulled from the subclass
-            String method = getRequestMethod();
-            HttpURLConnection httpConnection = null;
-            if (connection instanceof HttpURLConnection) {
-                httpConnection = (HttpURLConnection) connection;
-                httpConnection.setRequestMethod(method);
-            }
-            log("making " + method + " to " + url);
-
-            //call self or subclass for the connect.
-            //the connection object may change identity at this point.
-            connection = doConnect(connection);
-
-            //then provide a bit of overridable post processing for the fun of it
-            if (!onConnected(connection)) {
-                return;
-            }
-
-            //repeat the cast.
-            if (connection instanceof HttpURLConnection) {
-                httpConnection = (HttpURLConnection) connection;
-            }
-            if (httpConnection != null) {
-                // check for a 304 result (HTTP only) when we set the timestamp
-                // earlier on (A fractional performance tweak)
-                if (localTimestamp != 0) {
-                    if (getResponseCode(httpConnection) ==
-                            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("Local file is up to date - so nothing was downloaded");
-                        noteSuccess();
-                        return;
-                    }
-                }
-
-            }
-
-            //get the input stream
-            InputStream is = getInputStream(connection);
-
-            //bail out if the input stream isn't valid at this point
-            //again, though we should have got to this point earlier.
-
-            if (is == null) {
-                log("Can't get " + url, Project.MSG_ERR);
-                if (getFailOnError()) {
-                    return;
-                }
-                throw new BuildException("Can't reach URL");
-            }
-
-            //pick a file or null stream for saving content
-            OutputStream out = null;
-            if (destFile != null) {
-                log("Saving output to " + destFile, Project.MSG_DEBUG);
-                out = new FileOutputStream(destFile);
-            } else {
-                if (destProperty != null) {
-                    //save contents to a property
-                    log("Saving output to property " + destProperty,
-                            Project.MSG_DEBUG);
-                    out = new ByteArrayOutputStream(blockSize * 1024);
-                } else {
-                    //discard everything
-                    out = new NullOutputStream();
-                }
-            }
-
-            //get content length
-            //do it this way instead of calling getContentLength() because
-            //that way is sporadically unreliable (length is downgraded to 
-            //size of small packets)
-            int contentLength = connection.getHeaderFieldInt("Content-Length",
-                    -1);
-            int bytesRead = 0;
-
-            //now start download.
-            byte[] buffer = new byte[blockSize * 1024];
-            int length;
-
-            while ((length = is.read(buffer)) >= 0 &&
-                    (contentLength == -1 || bytesRead < contentLength)) {
-                bytesRead += length;
-                out.write(buffer, 0, length);
-                if (verbose) {
-                    showProgressChar('.');
-                }
-            }
-
-            //finished successfully - clean up.
-            if (verbose) {
-                showProgressChar('\n');
-            }
-
-            //if it we were saving to a byte array, then
-            //set the destination property with its contents
-            if (out instanceof ByteArrayOutputStream) {
-                getProject().setProperty(destProperty,
-                        out.toString());
-            }
-
-            //everything is downloaded; close files
-            out.flush();
-            out.close();
-            is.close();
-            is = null;
-            out = null;
-
-            //another overridable notification method
-            if (!onDownloadFinished(connection)) {
-                return;
-            }
-
-            //REFACTOR: move this down to HttpHead? What if a post wants
-            //to set a date?
-            //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) {
-
-                    destFile.setLastModified(remoteTimestamp);
-                }
-            }
-
-
-            String failureString = null;
-            if (contentLength > -1 && bytesRead != contentLength) {
-                failureString = "Incomplete download -Expected " + contentLength
-                        + "received " + bytesRead + " bytes";
-            } else {
-
-                //finally clean anything up.
-                //http requests have their response code checked, and only
-                //those in the success range are deemed successful.
-                if (httpConnection != null && useResponseCode) {
-                    int statusCode = httpConnection.getResponseCode();
-                    if (statusCode < 200 || statusCode > 299) {
-                        failureString = "Server error code " +
-                                statusCode +
-                                " received";
-                    }
-                }
-            }
-
-            //check for an error message
-            if (failureString == null) {
-                noteSuccess();
-            } else {
-                if (failOnError) {
-                    throw new BuildException(failureString);
-                } else {
-                    log(failureString, Project.MSG_ERR);
-                }
-            }
-
-        }
-        catch (IOException ioe) {
-            log("Error performing " + getRequestMethod() + " on " + url +
-                    " : " + ioe.toString(), Project.MSG_ERR);
-            if (failOnError) {
-                throw new BuildException(ioe);
-            }
-        }
-    }
-
-    /**
-     * show a progress character. Not as useful as you think, given buffering.
-     */
-
-    protected void showProgressChar(char c) {
-        System.out.write(c);
-    }
-
-
-    /**
-     * Adds a form / request parameter.
-     *
-     * @param param The feature to be added to the HttpRequestParameter
-     *              attribute
-     */
-    public void addParam(HttpRequestParameter param) {
-        params.add(param);
-    }
-
-
-    /**
-     * Adds an HTTP request header.
-     *
-     * @param header The feature to be added to the Header attribute
-     */
-    public void addHeader(HttpRequestParameter header) {
-        headers.add(header);
-    }
-
-
-    /**
-     * this must be overridden by implementations to set the request method to
-     * GET, POST, whatever NB: this method only gets called for an http request
-     *
-     * @return the method string
-     */
-    protected abstract String getRequestMethod();
-
-
-    /**
-     * determine the timestamp to use if the flag is set and the local file
-     * actually exists.
-     *
-     * @return 0 for 'no timestamp', a number otherwhise
-     */
-
-    protected long getTimestamp() {
-        long timestamp = 0;
-        if (useTimestamp && destFile != null && destFile.exists()) {
-            timestamp = destFile.lastModified();
-        } else {
-            timestamp = 0;
-        }
-        return timestamp;
-    }
-
-
-    /**
-     * ask for authentication details. An empty string means 'no auth'
-     *
-     * @return an RFC2617 auth string
-     */
-
-    protected String getAuthenticationString() {
-        // Set authorization eader, if specified
-        if (authType == AUTH_BASIC && username != null) {
-            password = password == null ? "" : password;
-            String encodeStr = username + ":" + password;
-            Base64Encode encoder = new Base64Encode();
-            char[] encodedPass = encoder.encodeBase64(encodeStr.getBytes());
-            String authStr = "BASIC " + new String(encodedPass);
-            return authStr;
-        } else {
-            return null;
-        }
-    }
-
-
-    /**
-     * this overridable method verifies that all the params are valid the base
-     * implementation checks for remote url validity and if the destination is
-     * not null, write access to what mustnt be a directory. sublcasses can call
-     * the base class as well as check their own data
-     *
-     * @throws BuildException only throw this when the failonerror flag is true
-     */
-
-    protected void verifyArguments()
-            throws BuildException {
-        //check remote params -but only create an exception, not throw it
-        if (getURL() == null) {
-            throw new BuildException("target URL missing");
-        }
-        //check destination parameters  -but only create an exception, not throw it
-        if (destFile != null && destFile.exists()) {
-            if (destFile.isDirectory()) {
-                throw new BuildException(
-                        "The specified destination is a directory");
-            } else if (!destFile.canWrite()) {
-                throw new BuildException("Can't write to " +
-                        destFile.getAbsolutePath());
-            }
-        }
-        //check auth policy
-        if (authType != AUTH_NONE && username == null) {
-            throw new BuildException(
-                    "no username defined to use with authorisation");
-        }
-    }
-
-
-    /**
-     * build a URL from the source url, maybe with parameters attached
-     *
-     * @return Description of the Returned Value
-     * @throws BuildException Description of Exception
-     */
-    protected URL buildURL()
-            throws BuildException {
-        String urlbase = getURL();
-        try {
-            if (areParamsAddedToUrl()) {
-                urlbase = parameterizeURL();
-            }
-            return new URL(urlbase);
-        }
-        catch (MalformedURLException e) {
-            throw new BuildException("Invalid URL");
-        }
-    }
-
-
-    /**
-     * take a url and add parameters to it. if there are no parameters the base
-     * url string is returned
-     *
-     * @return a string to be used for URL creation
-     * @throws BuildException Description of Exception
-     */
-    protected String parameterizeURL()
-            throws BuildException {
-        //return immediately if there are no parameters
-        if (params.size() == 0) {
-            return getURL();
-        }
-
-        StringBuffer buf = new StringBuffer(getURL());
-        //this devious little line code recognises a parameter string already
-        //in the source url, and if so doesnt add a new one
-        buf.append(source.indexOf('?') == -1 ? '?' : '&');
-        HttpRequestParameter param;
-
-        //run through the parameter list, encode the name/value pairs and
-        //append them to the list
-        for (int i = 0; i < params.size(); i++) {
-            if (i > 0) {
-                buf.append('&');
-            }
-            param = (HttpRequestParameter) params.get(i);
-            buf.append(param.toString());
-        }
-        return buf.toString();
-    }
-
-
-    /**
-     * query for the request wanting parameters on the url default is true,
-     * subclasses may want to change
-     *
-     * @return true if a url should have params attached.
-     */
-
-    protected boolean areParamsAddedToUrl() {
-        return true;
-    }
-
-    /**
-     * get the auth policy a null return value means 'no policy chosen'
-     *
-     * @return current authorisation strategy or null
-     */
-
-    protected HttpAuthenticationStrategy getAuthStrategy() {
-        HttpAuthenticationStrategy strategy = null;
-        switch (authType) {
-            case AUTH_BASIC:
-                strategy = new HttpBasicAuth();
-                break;
-            
-            case AUTH_NONE:
-                break;
-
-            case AUTH_DIGEST:
-            default:
-                throw new BuildException("Authentication method "
-                        +authType+" not supported");
-        }
-        return strategy;
-
-    }
-
-    /**
-     * this method opens the connection. It can recognise a 401 error code and
-     * in digest auth will then open a new connection with the supplied nonce
-     * encoded. That is why it can return a new connection object.
-     *
-     * @param connection where to connect to
-     * @return a new connection. This may be different than the old one
-     * @throws BuildException build trouble
-     * @throws IOException    IO trouble
-     */
-
-    protected URLConnection makeConnectionWithAuthHandling(URLConnection connection)
-            throws BuildException, IOException {
-        log("Connecting to " + connection.toString(), Project.MSG_DEBUG);
-        connection.connect();
-        URLConnection returnConnection = connection;
-        log("connected", Project.MSG_DEBUG);
-        if (connection instanceof HttpURLConnection) {
-            HttpURLConnection httpConnection = (HttpURLConnection) connection;
-            if (getResponseCode(httpConnection) ==
-                    HttpURLConnection
-                            .HTTP_UNAUTHORIZED
-                    && authType == AUTH_DIGEST) {
-                //duplicating all the settings then reconnect
-                //and return it
-                log("Digest authentication needed but not yet supported",
-                        Project.MSG_DEBUG);
-            }
-        }
-
-        return returnConnection;
-    }
-
-
-    /**
-     * by making a query for a value from the connection, we force the client
-     * code to actually do the http request and go into input mode. so next we
-     * can check for trouble.
-     */
-    void probeConnection(HttpURLConnection connection) {
-        connection.getHeaderFieldKey(0);
-    }
-
-
-    /**
-     * get a response from a connection request. This code fixes a problem found
-     * in HttpURLConnection, that any attempt to get the response code would
-     * trigger a FileNotFound
-     *
-     * @param connection the current http link
-     * @return whatever we get back
-     * @throws IOException if anything other than file not found gets thrown,
-     *                     and even a FileNotFound exception if that gets thrown
-     *                     too many times.
-     * @see <a href="http://developer.java.sun.com/developer/bugParade/bugs/4160499.html">
-     *      BugParade details </a> "If the requested file does not exist, and
-     *      ends in .html, .htm, .txt or /, you will get the error stream with
-     *      no exception thrown. If the file does not end like any of these you
-     *      can catch the exception and immediately request it again to get the
-     *      error stream. The response code can be obtained with
-     *      getResponseCode()." which means, to really get the response code you
-     *      need to ask twice.
-     */
-    protected int getResponseCode(HttpURLConnection connection)
-            throws IOException {
-        //force the creation of the input stream
-        //(which is what HttpURLConnection.getResponseCode() does internally
-        //that way the bug handler code is only needed once.
-
-        //probeConnection(connection);
-        IOException swallowed = null;
-        boolean caught = false;
-        int response = 0;
-        for (int attempts = 0; attempts < 5; attempts++) {
-            try {
-                response = connection.getResponseCode();
-                caught = true;
-                break;
-            }
-            catch (FileNotFoundException ex) {
-                log("Swallowed FileNotFoundException in getResponseCode",
-                        Project.MSG_VERBOSE);
-                log(ex.toString(), Project.MSG_DEBUG);
-                swallowed = ex;
-            }
-        }
-        if (!caught && swallowed != null) {
-            throw swallowed;
-        }
-        return response;
-    }
-
-    /**
-     * get an input stream from a connection This code tries to fix a problem
-     * found in HttpURLConnection, that any attempt to get the response code
-     * would trigger a FileNotFound BugParade ID 4160499 : <blockquote> "If the
-     * requested file does not exist, and ends in .html, .htm, .txt or /, you
-     * will get the error stream with no exception thrown. If the file does not
-     * end like any of these you can catch the exception and immediately request
-     * it again to get the error stream. The response code can be obtained with
-     * getResponseCode()." <blockquote> which means, to really get the response
-     * code you need to ask twice. More to the point this handling is not
-     * consistent across JVMs: on java 1.3 you can ask as often as you like but
-     * you are not going to get the input stream on a JSP page when it has some
-     * 500 class error.
-     *
-     * @param connection the current link
-     * @return the input stream.
-     * @throws IOException if anything other than file not found gets thrown,
-     *                     and even a FileNotFound exception if that gets thrown
-     *                     too many times.
-     */
-
-    protected InputStream getInputStream(URLConnection connection)
-            throws IOException {
-        IOException swallowed = null;
-        InputStream instream = null;
-        for (int attempts = 0; attempts < 5; attempts++) {
-            try {
-                instream = connection.getInputStream();
-                break;
-            }
-            catch (FileNotFoundException ex) {
-                log("Swallowed IO exception in getInputStream",
-                        Project.MSG_VERBOSE);
-                log(ex.toString(), Project.MSG_DEBUG);
-                swallowed = ex;
-            }
-        }
-        if (instream == null && swallowed != null) {
-            throw swallowed;
-        }
-        return instream;
-    }
-
-
-    /**
-     * this method is inteded for overriding. it is called when connecting to a
-     * URL, and the base implementation just calls connect() on the parameter.
-     * any subclass that wants to pump its own datastream up (like post) must
-     * override this
-     *
-     * @param connection where to connect to
-     * @throws BuildException build trouble
-     * @throws IOException    IO trouble
-     */
-
-    protected URLConnection doConnect(URLConnection connection)
-            throws BuildException, IOException {
-        return makeConnectionWithAuthHandling(connection);
-    }
-
-
-    /**
-     * this is a method for upload centric post-like requests
-     *
-     * @param connection    who we talk to
-     * @param contentType   Description of Parameter
-     * @param contentLength Description of Parameter
-     * @param content       Description of Parameter
-     * @throws IOException something went wrong with the IO
-     */
-    protected URLConnection doConnectWithUpload(URLConnection connection,
-                                                String contentType,
-                                                int contentLength,
-                                                InputStream content)
-            throws IOException {
-
-        log("uploading " + contentLength + " bytes of type " + contentType,
-                Project.MSG_VERBOSE);
-        //tell the connection we are in output mode
-        connection.setDoOutput(true);
-
-        // Set content length and type headers
-        connection.setRequestProperty("Content-Length",
-                String.valueOf(contentLength));
-        connection.setRequestProperty("Content-Type", contentType);
-        connection = makeConnectionWithAuthHandling(connection);
-        OutputStream toServer = connection.getOutputStream();
-
-        //create a buffer which is the smaller of
-        //the content length and the block size (in KB)
-        int buffersize = blockSize * 1024;
-        if (contentLength < buffersize) {
-            buffersize = contentLength;
-        }
-        byte[] buffer = new byte[buffersize];
-        int remaining = contentLength;
-
-        while (remaining > 0) {
-            int read = content.read(buffer);
-            log("block of " + read, Project.MSG_DEBUG);
-            toServer.write(buffer, 0, read);
-            remaining -= read;
-            if (verbose) {
-                showProgressChar('^');
-            }
-        }
-        if (verbose) {
-            showProgressChar('\n');
-        }
-        log("upload completed", Project.MSG_DEBUG);
-        return connection;
-    }
-
-    /**
-     * internal event handler called after a connect can throw an exception or
-     * return false for an immediate exit from the process
-     *
-     * @param connection the now open connection
-     * @return true if the execution is to continue
-     * @throws BuildException Description of Exception
-     */
-    protected boolean onConnected(URLConnection connection)
-            throws BuildException {
-        return true;
-    }
-
-
-    /**
-     * internal event handler called after the download is complete the code can
-     * still bail out at this point, and the connection may contain headers of
-     * interest. can throw an exception or return false for an immediate exit
-     * from the process
-     *
-     * @param connection the now open connection
-     * @return true if the execution is to continue
-     * @throws BuildException Description of Exception
-     */
-    protected boolean onDownloadFinished(URLConnection connection)
-            throws BuildException {
-        return true;
-    }
-
-
-    /**
-     * Enumerated attribute for "authType" with the value "basic" (note,
-     * eventually we can add "digest" authentication)
-     *
-     * @created March 17, 2001
-     */
-    public static class AuthMethodType extends EnumeratedAttribute {
-        /**
-         * Gets the possible values of authorisation supported
-         *
-         * @return The Values value
-         */
-        public String[] getValues() {
-            return new String[]{
-                    "none",
-                    "basic",
-                    //commented out until implemented
-                    //        "digest"
-            };
-        }
-
-    }
-}
-
+/*
+ * Copyright  2001-2006 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+
+package org.apache.ant.http;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Date;
+import java.util.Vector;
+
+/**
+ * This class is a foundational class for all the tasks which implement http
+ * methods. To implement a subclass you *must* provide an implementation of
+ * getRequestMethod(). Consider also stating the parameter policy
+ * (areParamsAddedToUrl()) and then, if needed, overriding doConnect, and the
+ * onConnected(), OnDownloadFinished() methods.
+ *
+ * @created March 17, 2001
+ */
+public abstract class HttpTask extends Task {
+
+    /**
+     * flag to control action on execution trouble.
+     */
+    protected boolean failOnError = true;
+
+    /**
+     * this sets the size of the buffer and the hash for download (Kilobytes).
+     */
+
+    protected int blockSize = 64;
+
+    /**
+     * property to set on success.
+     */
+
+    protected String status;
+
+    /**
+     * source URL- required.
+     */
+    private String source;
+
+    /**
+     * destination for download.
+     */
+    private File destFile;
+    /**
+     * verbose flag gives extra information.
+     */
+    private boolean verbose = false;
+
+    /**
+     * timestamp based download flag. off by default.
+     */
+    private boolean useTimestamp = false;
+
+    /**
+     * authorization mechanism in use.
+     */
+    private int authType = AUTH_NONE;
+
+    /**
+     * username for authentication.
+     */
+    private String username;
+
+    /**
+     * password for authentication.
+     */
+    private String password;
+
+    /**
+     * parameters to send on a request.
+     */
+    private Vector params = new Vector();
+
+    /**
+     * headers to send on a request
+     */
+    private Vector headers = new Vector();
+
+    /**
+     * cache policy.
+     */
+    private boolean usecaches = false;
+
+    /**
+     * the name of a destination property.
+     */
+
+    private String destProperty = null;
+
+    /**
+     * a flag to control whether or not response codes are acted on.
+     */
+    private boolean useResponseCode = true;
+
+    /**
+     * No authentication specified.
+     */
+    public final static int AUTH_NONE = 0;
+
+    /**
+     * basic 'cleartext' authentication.
+     */
+    public final static int AUTH_BASIC = 1;
+
+    /**
+     * digest auth. not actually supported but present for completeness.
+     */
+    public final static int AUTH_DIGEST = 2;
+
+
+    /**
+     * turn caching on or off. only relevant for protocols and methods which are
+     * cacheable (HEAD, GET) on http.
+     *
+     * @param usecaches The new UseCaches value
+     */
+    public void setUseCaches(boolean usecaches) {
+        this.usecaches = usecaches;
+    }
+
+    /**
+     * control whether response codes are used to determine success/failure.
+     *
+     * @param useResponseCode the new value
+     */
+    public void setUseResponseCode(boolean useResponseCode) {
+        this.useResponseCode = useResponseCode;
+    }
+
+
+    /**
+     * Set the URL.
+     *
+     * @param u URL for the operation.
+     */
+    public void setURL(String u) {
+        this.source = u;
+    }
+
+
+    /**
+     * the local destination for any response. this can be null for "don't
+     * download".
+     *
+     * @param destFile Path to file.
+     */
+    public void setDestFile(File destFile) {
+        this.destFile = destFile;
+    }
+
+    /**
+     * the local destination for any response. this can be null for "don't
+     * download"
+     *
+     * @param name Path to file.
+     */
+    public void setDestinationProperty(String name) {
+        this.destProperty = name;
+    }
+
+
+    /**
+     * Be verbose, if set to " <CODE>true</CODE> ".
+     *
+     * @param verbose The new Verbose value
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+
+    /**
+     * set the fail on error flag.
+     *
+     * @param b The new FailOnError value
+     */
+    public void setFailOnError(boolean b) {
+        failOnError = b;
+    }
+
+
+    /**
+     * Use timestamps, if set to " <CODE>true</CODE> ". <p>
+     * <p/>
+     * In this situation, the if-modified-since header is set so that the file
+     * is only fetched if it is newer than the local file (or there is no local
+     * file) This flag is only valid on HTTP connections, it is ignored in other
+     * cases. When the flag is set, the local copy of the downloaded file will
+     * also have its timestamp set to the remote file time. <br> Note that
+     * remote files of date 1/1/1970 (GMT) are treated as 'no timestamp', and
+     * web servers often serve files with a timestamp in the future by replacing
+     * their timestamp with that of the current time. Also, inter-computer clock
+     * differences can cause no end of grief.
+     *
+     * @param usetimestamp The new UseTimestamp value
+     */
+    public void setUseTimestamp(boolean usetimestamp) {
+        this.useTimestamp = usetimestamp;
+    }
+
+
+    /**
+     * Sets the Authtype attribute of the HttpTask object REVISIT/REFACTOR.
+     *
+     * @param type The new Authtype value
+     */
+    public void setAuthtype(AuthMethodType type) {
+        this.authType = type.getIndex();
+    }
+
+
+    /**
+     * Sets the Username used for authentication. setting the username
+     * implicitly turns authentication on.
+     *
+     * @param username The new Username value
+     */
+    public void setUsername(String username) {
+        this.username = username;
+        if (authType == AUTH_NONE) {
+            authType = AUTH_BASIC;
+        }
+    }
+
+
+    /**
+     * Sets the Password for an authenticated request.
+     *
+     * @param password The new Password value
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+
+    /**
+     * set a property to be set in the event of success.
+     *
+     * @param status The new SuccessProperty value
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    /**
+     * get the block size in kilobytes.
+     */
+
+    public int getBlockSize() {
+        return blockSize;
+    }
+
+    /**
+     * set the new block size for download (in kilobytes).
+     *
+     * @param blocksize the new value 
+     */
+    public void setBlockSize(int blocksize) {
+        this.blockSize = blocksize;
+    }
+
+
+    /**
+     * query cache policy.
+     *
+     * @return The UseCaches value
+     */
+    public boolean getUseCaches() {
+        return usecaches;
+    }
+
+
+    /**
+     * query fail on error flag.
+     *
+     * @return The FailFailOnError value
+     */
+    public boolean getFailOnError() {
+        return failOnError;
+    }
+
+
+    /**
+     * get the username.
+     *
+     * @return current username or null for 'none'
+     */
+    public String getUsername() {
+        return username;
+    }
+
+
+    /**
+     * get the password.
+     *
+     * @return current password or null for 'none'
+     */
+    public String getPassword() {
+        return password;
+    }
+
+
+    /**
+     * @return The RemoteURL value.
+     */
+    public String getURL() {
+        return source;
+    }
+
+
+    /**
+     * Get the vector of access parameters.
+     *
+     * @return The RequestParameters value
+     */
+    public Vector getRequestParameters() {
+        return params;
+    }
+
+
+    /**
+     * accessor of success property name
+     *
+     * @return The SuccessProperty value
+     */
+    public String getStatus() {
+        return status;
+    }
+
+    /**
+     * accessor of destination property name
+     *
+     * @return The destination value
+     */
+    public String getDestinationProperty() {
+        return destProperty;
+    }
+
+    /**
+     * accessor of destination
+     *
+     * @return Thedestination
+     */
+    public File getDestFile() {
+        return destFile;
+    }
+
+
+    /**
+     * if the user wanted a success property, this sets it. of course, it is only
+     * relevant if failonerror=false
+     */
+
+    public void noteSuccess() {
+        if (status != null && status.length() > 0) {
+            getProject().setProperty(status, "true");
+        }
+    }
+
+
+    /**
+     * Does the work.
+     *
+     * @throws BuildException Thrown in unrecoverable error.
+     */
+    public void execute() {
+
+        //check arguments, will bail out if there
+        //was trouble 
+        verifyArguments();
+
+        //set up the URL connection
+        URL url = buildURL();
+
+        try {
+
+            //now create a connection
+            URLConnection connection = url.openConnection();
+
+            //set caching option to whatever
+            connection.setUseCaches(getUseCaches());
+
+            //set the timestamp option if flag is set and
+            //the local file actually exists.
+            long localTimestamp = getTimestamp();
+            if (localTimestamp != 0) {
+                if (verbose) {
+                    Date t = new Date(localTimestamp);
+                    log("local file date : " + t.toString());
+                }
+                connection.setIfModifiedSince(localTimestamp);
+            }
+
+            // Set auth header, if specified
+            //NB: verifyArguments will already have checked that you can't
+            //have a null username with a non-null strategy.
+            HttpAuthenticationStrategy authStrategy = getAuthStrategy();
+            if (authStrategy != null) {
+                authStrategy.setAuthenticationHeader(connection,
+                        null,
+                        username,
+                        password);
+            }
+
+            // Set explicitly specified request headers
+            HttpRequestParameter header;
+            for (int i = 0; i < headers.size(); i++) {
+                header = (HttpRequestParameter) headers.get(i);
+                connection.setRequestProperty(header.getName(),
+                        header.getValue());
+            }
+
+            //cast to an http connection if we can,
+            //then set the request method pulled from the subclass
+            String method = getRequestMethod();
+            HttpURLConnection httpConnection = null;
+            if (connection instanceof HttpURLConnection) {
+                httpConnection = (HttpURLConnection) connection;
+                httpConnection.setRequestMethod(method);
+            }
+            log("making " + method + " to " + url);
+
+            //call self or subclass for the connect.
+            //the connection object may change identity at this point.
+            connection = doConnect(connection);
+
+            //then provide a bit of overridable post processing for the fun of it
+            if (!onConnected(connection)) {
+                return;
+            }
+
+            //repeat the cast.
+            if (connection instanceof HttpURLConnection) {
+                httpConnection = (HttpURLConnection) connection;
+            }
+            if (httpConnection != null) {
+                // check for a 304 result (HTTP only) when we set the timestamp
+                // earlier on (A fractional performance tweak)
+                if (localTimestamp != 0) {
+                    if (getResponseCode(httpConnection) ==
+                            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("Local file is up to date - so nothing was downloaded");
+                        noteSuccess();
+                        return;
+                    }
+                }
+
+            }
+
+            //get the input stream
+            InputStream is = getInputStream(connection);
+
+            //bail out if the input stream isn't valid at this point
+            //again, though we should have got to this point earlier.
+
+            if (is == null) {
+                log("Can't get " + url, Project.MSG_ERR);
+                if (getFailOnError()) {
+                    return;
+                }
+                throw new BuildException("Can't reach URL");
+            }
+
+            //pick a file or null stream for saving content
+            OutputStream out = null;
+            if (destFile != null) {
+                log("Saving output to " + destFile, Project.MSG_DEBUG);
+                out = new FileOutputStream(destFile);
+            } else {
+                if (destProperty != null) {
+                    //save contents to a property
+                    log("Saving output to property " + destProperty,
+                            Project.MSG_DEBUG);
+                    out = new ByteArrayOutputStream(blockSize * 1024);
+                } else {
+                    //discard everything
+                    out = new NullOutputStream();
+                }
+            }
+
+            //get content length
+            //do it this way instead of calling getContentLength() because
+            //that way is sporadically unreliable (length is downgraded to 
+            //size of small packets)
+            int contentLength = connection.getHeaderFieldInt("Content-Length",
+                    -1);
+            int bytesRead = 0;
+
+            //now start download.
+            byte[] buffer = new byte[blockSize * 1024];
+            int length;
+
+            while ((length = is.read(buffer)) >= 0 &&
+                    (contentLength == -1 || bytesRead < contentLength)) {
+                bytesRead += length;
+                out.write(buffer, 0, length);
+                if (verbose) {
+                    showProgressChar('.');
+                }
+            }
+
+            //finished successfully - clean up.
+            if (verbose) {
+                showProgressChar('\n');
+            }
+
+            //if it we were saving to a byte array, then
+            //set the destination property with its contents
+            if (out instanceof ByteArrayOutputStream) {
+                getProject().setProperty(destProperty,
+                        out.toString());
+            }
+
+            //everything is downloaded; close files
+            out.flush();
+            out.close();
+            is.close();
+            is = null;
+            out = null;
+
+            //another overridable notification method
+            if (!onDownloadFinished(connection)) {
+                return;
+            }
+
+            //REFACTOR: move this down to HttpHead? What if a post wants
+            //to set a date?
+            //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) {
+
+                    destFile.setLastModified(remoteTimestamp);
+                }
+            }
+
+
+            String failureString = null;
+            if (contentLength > -1 && bytesRead != contentLength) {
+                failureString = "Incomplete download -Expected " + contentLength
+                        + "received " + bytesRead + " bytes";
+            } else {
+
+                //finally clean anything up.
+                //http requests have their response code checked, and only
+                //those in the success range are deemed successful.
+                if (httpConnection != null && useResponseCode) {
+                    int statusCode = httpConnection.getResponseCode();
+                    if (statusCode < 200 || statusCode > 299) {
+                        failureString = "Server error code " +
+                                statusCode +
+                                " received";
+                    }
+                }
+            }
+
+            //check for an error message
+            if (failureString == null) {
+                noteSuccess();
+            } else {
+                if (failOnError) {
+                    throw new BuildException(failureString);
+                } else {
+                    log(failureString, Project.MSG_ERR);
+                }
+            }
+
+        }
+        catch (IOException ioe) {
+            log("Error performing " + getRequestMethod() + " on " + url +
+                    " : " + ioe.toString(), Project.MSG_ERR);
+            if (failOnError) {
+                throw new BuildException(ioe);
+            }
+        }
+    }
+
+    /**
+     * show a progress character. Not as useful as you think, given buffering.
+     */
+
+    protected void showProgressChar(char c) {
+        System.out.write(c);
+    }
+
+
+    /**
+     * Adds a form / request parameter.
+     *
+     * @param param The feature to be added to the HttpRequestParameter
+     *              attribute
+     */
+    public void addParam(HttpRequestParameter param) {
+        params.add(param);
+    }
+
+
+    /**
+     * Adds an HTTP request header.
+     *
+     * @param header The feature to be added to the Header attribute
+     */
+    public void addHeader(HttpRequestParameter header) {
+        headers.add(header);
+    }
+
+
+    /**
+     * this must be overridden by implementations to set the request method to
+     * GET, POST, whatever NB: this method only gets called for an http request
+     *
+     * @return the method string
+     */
+    protected abstract String getRequestMethod();
+
+
+    /**
+     * determine the timestamp to use if the flag is set and the local file
+     * actually exists.
+     *
+     * @return 0 for 'no timestamp', a number otherwhise
+     */
+
+    protected long getTimestamp() {
+        long timestamp = 0;
+        if (useTimestamp && destFile != null && destFile.exists()) {
+            timestamp = destFile.lastModified();
+        } else {
+            timestamp = 0;
+        }
+        return timestamp;
+    }
+
+
+    /**
+     * ask for authentication details. An empty string means 'no auth'
+     *
+     * @return an RFC2617 auth string
+     */
+
+    protected String getAuthenticationString() {
+        // Set authorization eader, if specified
+        if (authType == AUTH_BASIC && username != null) {
+            password = password == null ? "" : password;
+            String encodeStr = username + ":" + password;
+            Base64Encode encoder = new Base64Encode();
+            char[] encodedPass = encoder.encodeBase64(encodeStr.getBytes());
+            String authStr = "BASIC " + new String(encodedPass);
+            return authStr;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * this overridable method verifies that all the params are valid the base
+     * implementation checks for remote url validity and if the destination is
+     * not null, write access to what mustnt be a directory. sublcasses can call
+     * the base class as well as check their own data
+     *
+     * @throws BuildException only throw this when the failonerror flag is true
+     */
+
+    protected void verifyArguments()
+            throws BuildException {
+        //check remote params -but only create an exception, not throw it
+        if (getURL() == null) {
+            throw new BuildException("target URL missing");
+        }
+        //check destination parameters  -but only create an exception, not throw it
+        if (destFile != null && destFile.exists()) {
+            if (destFile.isDirectory()) {
+                throw new BuildException(
+                        "The specified destination is a directory");
+            } else if (!destFile.canWrite()) {
+                throw new BuildException("Can't write to " +
+                        destFile.getAbsolutePath());
+            }
+        }
+        //check auth policy
+        if (authType != AUTH_NONE && username == null) {
+            throw new BuildException(
+                    "no username defined to use with authorisation");
+        }
+    }
+
+
+    /**
+     * build a URL from the source url, maybe with parameters attached
+     *
+     * @return Description of the Returned Value
+     * @throws BuildException Description of Exception
+     */
+    protected URL buildURL()
+            throws BuildException {
+        String urlbase = getURL();
+        try {
+            if (areParamsAddedToUrl()) {
+                urlbase = parameterizeURL();
+            }
+            return new URL(urlbase);
+        }
+        catch (MalformedURLException e) {
+            throw new BuildException("Invalid URL");
+        }
+    }
+
+
+    /**
+     * take a url and add parameters to it. if there are no parameters the base
+     * url string is returned
+     *
+     * @return a string to be used for URL creation
+     * @throws BuildException Description of Exception
+     */
+    protected String parameterizeURL()
+            throws BuildException {
+        //return immediately if there are no parameters
+        if (params.size() == 0) {
+            return getURL();
+        }
+
+        StringBuffer buf = new StringBuffer(getURL());
+        //this devious little line code recognises a parameter string already
+        //in the source url, and if so doesnt add a new one
+        buf.append(source.indexOf('?') == -1 ? '?' : '&');
+        HttpRequestParameter param;
+
+        //run through the parameter list, encode the name/value pairs and
+        //append them to the list
+        for (int i = 0; i < params.size(); i++) {
+            if (i > 0) {
+                buf.append('&');
+            }
+            param = (HttpRequestParameter) params.get(i);
+            buf.append(param.toString());
+        }
+        return buf.toString();
+    }
+
+
+    /**
+     * query for the request wanting parameters on the url default is true,
+     * subclasses may want to change
+     *
+     * @return true if a url should have params attached.
+     */
+
+    protected boolean areParamsAddedToUrl() {
+        return true;
+    }
+
+    /**
+     * get the auth policy a null return value means 'no policy chosen'
+     *
+     * @return current authorisation strategy or null
+     */
+
+    protected HttpAuthenticationStrategy getAuthStrategy() {
+        HttpAuthenticationStrategy strategy = null;
+        switch (authType) {
+            case AUTH_BASIC:
+                strategy = new HttpBasicAuth();
+                break;
+            
+            case AUTH_NONE:
+                break;
+
+            case AUTH_DIGEST:
+            default:
+                throw new BuildException("Authentication method "
+                        +authType+" not supported");
+        }
+        return strategy;
+
+    }
+
+    /**
+     * this method opens the connection. It can recognise a 401 error code and
+     * in digest auth will then open a new connection with the supplied nonce
+     * encoded. That is why it can return a new connection object.
+     *
+     * @param connection where to connect to
+     * @return a new connection. This may be different than the old one
+     * @throws BuildException build trouble
+     * @throws IOException    IO trouble
+     */
+
+    protected URLConnection makeConnectionWithAuthHandling(URLConnection connection)
+            throws BuildException, IOException {
+        log("Connecting to " + connection.toString(), Project.MSG_DEBUG);
+        connection.connect();
+        URLConnection returnConnection = connection;
+        log("connected", Project.MSG_DEBUG);
+        if (connection instanceof HttpURLConnection) {
+            HttpURLConnection httpConnection = (HttpURLConnection) connection;
+            if (getResponseCode(httpConnection) ==
+                    HttpURLConnection
+                            .HTTP_UNAUTHORIZED
+                    && authType == AUTH_DIGEST) {
+                //duplicating all the settings then reconnect
+                //and return it
+                log("Digest authentication needed but not yet supported",
+                        Project.MSG_DEBUG);
+            }
+        }
+
+        return returnConnection;
+    }
+
+
+    /**
+     * by making a query for a value from the connection, we force the client
+     * code to actually do the http request and go into input mode. so next we
+     * can check for trouble.
+     */
+    void probeConnection(HttpURLConnection connection) {
+        connection.getHeaderFieldKey(0);
+    }
+
+
+    /**
+     * get a response from a connection request. This code fixes a problem found
+     * in HttpURLConnection, that any attempt to get the response code would
+     * trigger a FileNotFound
+     *
+     * @param connection the current http link
+     * @return whatever we get back
+     * @throws IOException if anything other than file not found gets thrown,
+     *                     and even a FileNotFound exception if that gets thrown
+     *                     too many times.
+     * @see <a href="http://developer.java.sun.com/developer/bugParade/bugs/4160499.html">
+     *      BugParade details </a> "If the requested file does not exist, and
+     *      ends in .html, .htm, .txt or /, you will get the error stream with
+     *      no exception thrown. If the file does not end like any of these you
+     *      can catch the exception and immediately request it again to get the
+     *      error stream. The response code can be obtained with
+     *      getResponseCode()." which means, to really get the response code you
+     *      need to ask twice.
+     */
+    protected int getResponseCode(HttpURLConnection connection)
+            throws IOException {
+        //force the creation of the input stream
+        //(which is what HttpURLConnection.getResponseCode() does internally
+        //that way the bug handler code is only needed once.
+
+        //probeConnection(connection);
+        IOException swallowed = null;
+        boolean caught = false;
+        int response = 0;
+        for (int attempts = 0; attempts < 5; attempts++) {
+            try {
+                response = connection.getResponseCode();
+                caught = true;
+                break;
+            }
+            catch (FileNotFoundException ex) {
+                log("Swallowed FileNotFoundException in getResponseCode",
+                        Project.MSG_VERBOSE);
+                log(ex.toString(), Project.MSG_DEBUG);
+                swallowed = ex;
+            }
+        }
+        if (!caught && swallowed != null) {
+            throw swallowed;
+        }
+        return response;
+    }
+
+    /**
+     * get an input stream from a connection This code tries to fix a problem
+     * found in HttpURLConnection, that any attempt to get the response code
+     * would trigger a FileNotFound BugParade ID 4160499 : <blockquote> "If the
+     * requested file does not exist, and ends in .html, .htm, .txt or /, you
+     * will get the error stream with no exception thrown. If the file does not
+     * end like any of these you can catch the exception and immediately request
+     * it again to get the error stream. The response code can be obtained with
+     * getResponseCode()." <blockquote> which means, to really get the response
+     * code you need to ask twice. More to the point this handling is not
+     * consistent across JVMs: on java 1.3 you can ask as often as you like but
+     * you are not going to get the input stream on a JSP page when it has some
+     * 500 class error.
+     *
+     * @param connection the current link
+     * @return the input stream.
+     * @throws IOException if anything other than file not found gets thrown,
+     *                     and even a FileNotFound exception if that gets thrown
+     *                     too many times.
+     */
+
+    protected InputStream getInputStream(URLConnection connection)
+            throws IOException {
+        IOException swallowed = null;
+        InputStream instream = null;
+        for (int attempts = 0; attempts < 5; attempts++) {
+            try {
+                instream = connection.getInputStream();
+                break;
+            }
+            catch (FileNotFoundException ex) {
+                log("Swallowed IO exception in getInputStream",
+                        Project.MSG_VERBOSE);
+                log(ex.toString(), Project.MSG_DEBUG);
+                swallowed = ex;
+            }
+        }
+        if (instream == null && swallowed != null) {
+            throw swallowed;
+        }
+        return instream;
+    }
+
+
+    /**
+     * this method is inteded for overriding. it is called when connecting to a
+     * URL, and the base implementation just calls connect() on the parameter.
+     * any subclass that wants to pump its own datastream up (like post) must
+     * override this
+     *
+     * @param connection where to connect to
+     * @throws BuildException build trouble
+     * @throws IOException    IO trouble
+     */
+
+    protected URLConnection doConnect(URLConnection connection)
+            throws BuildException, IOException {
+        return makeConnectionWithAuthHandling(connection);
+    }
+
+
+    /**
+     * this is a method for upload centric post-like requests
+     *
+     * @param connection    who we talk to
+     * @param contentType   Description of Parameter
+     * @param contentLength Description of Parameter
+     * @param content       Description of Parameter
+     * @throws IOException something went wrong with the IO
+     */
+    protected URLConnection doConnectWithUpload(URLConnection connection,
+                                                String contentType,
+                                                int contentLength,
+                                                InputStream content)
+            throws IOException {
+
+        log("uploading " + contentLength + " bytes of type " + contentType,
+                Project.MSG_VERBOSE);
+        //tell the connection we are in output mode
+        connection.setDoOutput(true);
+
+        // Set content length and type headers
+        connection.setRequestProperty("Content-Length",
+                String.valueOf(contentLength));
+        connection.setRequestProperty("Content-Type", contentType);
+        connection = makeConnectionWithAuthHandling(connection);
+        OutputStream toServer = connection.getOutputStream();
+
+        //create a buffer which is the smaller of
+        //the content length and the block size (in KB)
+        int buffersize = blockSize * 1024;
+        if (contentLength < buffersize) {
+            buffersize = contentLength;
+        }
+        byte[] buffer = new byte[buffersize];
+        int remaining = contentLength;
+
+        while (remaining > 0) {
+            int read = content.read(buffer);
+            log("block of " + read, Project.MSG_DEBUG);
+            toServer.write(buffer, 0, read);
+            remaining -= read;
+            if (verbose) {
+                showProgressChar('^');
+            }
+        }
+        if (verbose) {
+            showProgressChar('\n');
+        }
+        log("upload completed", Project.MSG_DEBUG);
+        return connection;
+    }
+
+    /**
+     * internal event handler called after a connect can throw an exception or
+     * return false for an immediate exit from the process
+     *
+     * @param connection the now open connection
+     * @return true if the execution is to continue
+     * @throws BuildException Description of Exception
+     */
+    protected boolean onConnected(URLConnection connection)
+            throws BuildException {
+        return true;
+    }
+
+
+    /**
+     * internal event handler called after the download is complete the code can
+     * still bail out at this point, and the connection may contain headers of
+     * interest. can throw an exception or return false for an immediate exit
+     * from the process
+     *
+     * @param connection the now open connection
+     * @return true if the execution is to continue
+     * @throws BuildException Description of Exception
+     */
+    protected boolean onDownloadFinished(URLConnection connection)
+            throws BuildException {
+        return true;
+    }
+
+
+    /**
+     * Enumerated attribute for "authType" with the value "basic" (note,
+     * eventually we can add "digest" authentication)
+     *
+     * @created March 17, 2001
+     */
+    public static class AuthMethodType extends EnumeratedAttribute {
+        /**
+         * Gets the possible values of authorisation supported
+         *
+         * @return The Values value
+         */
+        public String[] getValues() {
+            return new String[]{
+                    "none",
+                    "basic",
+                    //commented out until implemented
+                    //        "digest"
+            };
+        }
+
+    }
+}
+

Propchange: ant/sandbox/antlibs/http/trunk/src/main/org/apache/ant/http/HttpTask.java
------------------------------------------------------------------------------
    svn:eol-style = native



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