Browse Source

Repository support; needs http client 2.x and commons-logging.

Broken: repository references (you'll see in the test results)
not tested: authenticated access to the repository.
Already had a feature request for multiple repository support;
would be nice. That and better diagnostics on failure.
Note that we dont currently probe ibiblio for availaibility; that was taking longer than the fetches themselves.


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276957 13f79535-47bb-0310-9956-ffa450edef68
master
Steve Loughran 20 years ago
parent
commit
045a7004a1
12 changed files with 1477 additions and 1 deletions
  1. +2
    -0
      WHATSNEW
  2. +21
    -0
      build.xml
  3. +112
    -0
      src/etc/testcases/taskdefs/optional/getlibraries.xml
  4. +1
    -0
      src/main/org/apache/tools/ant/taskdefs/defaults.properties
  5. +315
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/repository/GetLibraries.java
  6. +447
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/repository/HttpRepository.java
  7. +218
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/repository/Library.java
  8. +65
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/repository/MavenRepository.java
  9. +109
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/repository/Repository.java
  10. +76
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/repository/RepositoryRef.java
  11. +2
    -1
      src/main/org/apache/tools/ant/types/defaults.properties
  12. +109
    -0
      src/testcases/org/apache/tools/ant/taskdefs/optional/GetLibrariesTest.java

+ 2
- 0
WHATSNEW View File

@@ -68,6 +68,8 @@ Other changes:
* Added a new "failall" value for the onerror attribute of <typedef>. * Added a new "failall" value for the onerror attribute of <typedef>.
Bugzilla report 31685. Bugzilla report 31685.


* New task <getlibraries> can retrieve library files from a maven repository.

Changes from Ant 1.6.2 to current Ant 1.6 CVS version Changes from Ant 1.6.2 to current Ant 1.6 CVS version
===================================================== =====================================================




+ 21
- 0
build.xml View File

@@ -328,6 +328,11 @@
<filename name="${ant.package}/launch/**/*"/> <filename name="${ant.package}/launch/**/*"/>
</selector> </selector>


<selector id="needs.commons.httpclient">
<filename name="${optional.package}/repository/**/*"/>
</selector>


<patternset id="onlinetests"> <patternset id="onlinetests">
<exclude name="**/GetTest.java" if="offline"/> <exclude name="**/GetTest.java" if="offline"/>
<exclude name="**/SignJarTest.java" if="offline"/> <exclude name="**/SignJarTest.java" if="offline"/>
@@ -561,6 +566,17 @@
classpathref="classpath"/> classpathref="classpath"/>
</or> </or>
</condition> </condition>

<!-- http client needs commons logging -->
<condition property="commons.httpclient.present">
<and>
<available
classname="org.apache.commons.httpclient.HttpClient"
classpathref="classpath"/>
<isset property="commons.logging.present"/>
</and>
</condition>

<condition property="wsdl.found"> <condition property="wsdl.found">
<or> <or>
<available file="wsdl" filepath="${env.PATH}"/> <available file="wsdl" filepath="${env.PATH}"/>
@@ -679,6 +695,7 @@
<selector refid="needs.jdepend" unless="jdepend.present"/> <selector refid="needs.jdepend" unless="jdepend.present"/>
<selector refid="needs.swing" unless="swing.present"/> <selector refid="needs.swing" unless="swing.present"/>
<selector refid="needs.jsch" unless="jsch.present"/> <selector refid="needs.jsch" unless="jsch.present"/>
<selector refid="needs.commons.httpclient" unless="commons.httpclient.present"/>
</or> </or>
</not> </not>
</selector> </selector>
@@ -853,6 +870,7 @@
<selector refid="needs.jdepend"/> <selector refid="needs.jdepend"/>
<selector refid="needs.swing"/> <selector refid="needs.swing"/>
<selector refid="needs.jsch"/> <selector refid="needs.jsch"/>
<selector refid="needs.commons.httpclient"/>
</or> </or>
</not> </not>
</and> </and>
@@ -897,6 +915,7 @@
<optional-jar dep="swing"/> <optional-jar dep="swing"/>
<optional-jar dep="jsch"/> <optional-jar dep="jsch"/>
<optional-jar dep="jdepend"/> <optional-jar dep="jdepend"/>
<optional-jar dep="commons.httpclient"/>


<jar destfile="${build.lib}/${optional.jars.prefix}-weblogic.jar" <jar destfile="${build.lib}/${optional.jars.prefix}-weblogic.jar"
basedir="${build.classes}" basedir="${build.classes}"
@@ -1471,6 +1490,7 @@


<sysproperty key="ant.home" value="${ant.home}"/> <sysproperty key="ant.home" value="${ant.home}"/>
<sysproperty key="build.tests" file="${build.tests}"/> <sysproperty key="build.tests" file="${build.tests}"/>
<sysproperty key="offline" value="${offline}"/>
<sysproperty key="build.tests.value" value="${build.tests.value}"/> <sysproperty key="build.tests.value" value="${build.tests.value}"/>
<sysproperty key="tests-classpath.value" <sysproperty key="tests-classpath.value"
value="${tests-classpath.value}"/> value="${tests-classpath.value}"/>
@@ -1624,6 +1644,7 @@
<sysproperty key="ant.home" value="${ant.home}"/> <sysproperty key="ant.home" value="${ant.home}"/>
<sysproperty key="build.tests" file="${build.tests}"/> <sysproperty key="build.tests" file="${build.tests}"/>
<sysproperty key="build.tests.value" value="${build.tests.value}"/> <sysproperty key="build.tests.value" value="${build.tests.value}"/>
<sysproperty key="offline" value="${offline}"/>
<sysproperty key="tests-classpath.value" <sysproperty key="tests-classpath.value"
value="${tests-classpath.value}"/> value="${tests-classpath.value}"/>
<classpath refid="tests-classpath"/> <classpath refid="tests-classpath"/>


+ 112
- 0
src/etc/testcases/taskdefs/optional/getlibraries.xml View File

@@ -0,0 +1,112 @@
<?xml version="1.0"?>
<project name="getlibraries" basedir="." default="all">


<!-- use the normal one at ibiblio-->
<mavenrepository id="maven"/>

<target name="init">
<property name="lib.dir" value="getlib"/>
<mkdir dir="${lib.dir}"/>
<property name="commons.logging" value="commons-logging-1.0.1.jar"/>

<presetdef name="getlib">
<getlibraries destDir="${lib.dir}">
<library archive="commons-logging" project="commons-logging" version="1.0.1"/>
</getlibraries>
</presetdef>

<macrodef name="assert-downloaded">
<attribute name="library" default="${commons.logging}"/>
<sequential>
<available property="@{library}.exists"
file="${lib.dir}/@{library}"/>
<fail unless="@{library}.exists">
Not found: ${lib.dir}@{library}
</fail>
</sequential>
</macrodef>
</target>

<target name="cleanup">
<delete dir="${lib.dir}"/>
</target>

<target name="testEmpty" depends="init">
<getlibraries/>
</target>

<target name="testEmpty2" depends="init">
<getlibraries destDir="${lib.dir}">

</getlibraries>
</target>

<target name="testEmpty3" depends="init">
<getlibraries destDir="${lib.dir}">
<repository/>
</getlibraries>
</target>

<target name="testNoRepo" depends="init">
<getlib/>
</target>

<target name="testUnknownReference" depends="init">
<getlib>
<repository refid="unknown"/>
</getlib>
</target>


<target name="testFunctionalInline" depends="init">
<getlib repositoryref="maven">
</getlib>
<assert-downloaded/>
</target>

<target name="testMavenInline" depends="init">
<getlib>
<mavenrepository/>
</getlib>
<assert-downloaded/>
</target>

<target name="testTwoRepositories" depends="init">
<getlib>
<mavenrepository/>
<mavenrepository/>
</getlib>
</target>


<target name="testMavenInlineBadURL" depends="init">
<getlib>

</getlib>
</target>

<target name="testRenaming" depends="init">
<getlib>
<mavenrepository/>
<library archive="commons-logging" project="commons-logging" version="1.0.1"
destinationName="renamed.jar"
/>
</getlib>
<assert-downloaded/>
<assert-downloaded library="renamed.jar"/>
</target>


<target name="testOverwrite" depends="init">
<getlib>
<mavenrepository/>
</getlib>
<assert-downloaded/>
<getlib>
<mavenrepository/>
</getlib>
</target>

</project>


+ 1
- 0
src/main/org/apache/tools/ant/taskdefs/defaults.properties View File

@@ -203,6 +203,7 @@ rexec=org.apache.tools.ant.taskdefs.optional.net.RExecTask
scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef
ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm
apt=org.apache.tools.ant.taskdefs.Apt apt=org.apache.tools.ant.taskdefs.Apt
getlibraries=org.apache.tools.ant.taskdefs.optional.repository.GetLibraries


# deprecated ant tasks (kept for back compatibility) # deprecated ant tasks (kept for back compatibility)
starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut


+ 315
- 0
src/main/org/apache/tools/ant/taskdefs/optional/repository/GetLibraries.java View File

@@ -0,0 +1,315 @@
/*
* Copyright 2004 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.tools.ant.taskdefs.optional.repository;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Reference;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
* This task will retrieve one or more libraries from a repository. <ol>
* <li>Users must declare a repository, either inline or by reference</li>
* <li>Dependency checking is used (timestamps) unless forceDownload=true</li>
* <li>It is an error if, at the end of the task, a library is missing.
*
* @ant.task
* @since Ant 1.7
*/
public class GetLibraries extends Task {

/**
* destination
*/
private File destDir;

/**
* flag to force a download
*/
private boolean forceDownload = false;

/**
* flag to force offline
*/
private boolean offline = false;

/**
* list of libraries
*/
private List libraries = new LinkedList();

/**
* repository for retrieval
*/

private Repository repository;

public static final String ERROR_ONE_REPOSITORY_ONLY = "Only one repository is allowed";
public static final String ERROR_NO_DEST_DIR = "No destination directory";
public static final String ERROR_NO_REPOSITORY = "No repository defined";
public static final String ERROR_NO_LIBRARIES = "No libraries to load";
public static final String ERROR_REPO_PROBE_FAILED = "repository probe failed with ";
public static final String ERROR_LIBRARY_FETCH_FAILED = "failed to retrieve ";
public static final String ERROR_FORCED_DOWNLOAD_FAILED = "Failed to download every file on a forced download";
public static final String ERROR_INCOMPLETE_RETRIEVAL = "Not all libraries could be retrieved";

/**
* add a repository. Only one is (currently) supported
*
* @param repo
*/
public void add(Repository repo) {
if (repository != null) {
throw new BuildException(ERROR_ONE_REPOSITORY_ONLY);
}
repository = repo;
}


/**
* add a repository. Unless there is explicit support for a subclass
*
* @param repo
*/
public void addRepository(RepositoryRef repo) {
add(repo);
}


/**
* add a maven repository.
*/
/*
public void addMavenRepository(MavenRepository repo) {
add(repo);
}
*/

/**
* bind to a repository.
*/
public void setRepositoryRef(final Reference ref) {
//create a special repository that can only
//resolve references.
Repository r = new RepositoryRef(getProject(), ref);
add(r);
}


/**
* add a library for retrieval
*
* @param lib
*/
public void addLibrary(Library lib) {
libraries.add(lib);
}

/**
* destination directory for all library files
*
* @param destDir
*/
public void setDestDir(File destDir) {
this.destDir = destDir;
}

/**
* flag to force a download even if the clock indicates it aint needed.
*
* @param forceDownload
*/
public void setForceDownload(boolean forceDownload) {
this.forceDownload = forceDownload;
}

/**
* test for being offline
*
* @return true if the offline flag is set
*/
public boolean isOffline() {
return offline;
}

/**
* declare the system offline. This disables any attempt to retrieve files.
* In this mode, only the presence of files is verified. If forceDownload is
* true, or there is a missing library, then an error will be raised.
*
* @param offline
*/
public void setOffline(boolean offline) {
this.offline = offline;
}

public File getDestDir() {
return destDir;
}

public boolean isForceDownload() {
return forceDownload;
}

public List getLibraries() {
return libraries;
}

public Repository getRepository() {
return repository;
}

/**
* validate ourselves
*
* @throws BuildException
*/
public void validate() {
if (destDir == null || !destDir.exists() || !destDir.isDirectory()) {
throw new BuildException(ERROR_NO_DEST_DIR);
}
if (repository == null) {
throw new BuildException(ERROR_NO_REPOSITORY);
}
Iterator it = libraries.iterator();
while (it.hasNext()) {
Library library = (Library) it.next();
library.validate();
}
}

/**
* Called by the project to let the task do its work.
*
* @throws org.apache.tools.ant.BuildException
* if something goes wrong with the build
*/
public void execute() throws BuildException {
validate();
Repository repo = repository.resolve();
repo.validate();
int toFetch = libraries.size();
if (toFetch == 0) {
throw new BuildException(ERROR_NO_LIBRARIES);
}
int fetched = 0;
log("Getting libraries from " + repo.toString(), Project.MSG_VERBOSE);
log("Saving libraries to " + destDir.toString(), Project.MSG_VERBOSE);

bindAllLibraries();
if (isOffline()) {
log("No retrieval, task is \"offline\"");
verifyAllLibrariesPresent();
return;
}


//connect the repository
repo.connect(this);
try {

//check for reachability.
//it is up to each repository to decide that.
boolean reachable;
try {
log("Checking repository for reachability", Project.MSG_DEBUG);
reachable = repo.checkRepositoryReachable();
} catch (IOException e) {

log(ERROR_REPO_PROBE_FAILED + e.getMessage(),
Project.MSG_VERBOSE);
reachable = false;
}
if (!reachable) {
if (forceDownload) {
throw new BuildException(repo.toString()
+ " is unreachable and forceDownload is set");
}
} else {
log("Repository is live", Project.MSG_DEBUG);
}

//iterate through the libs we have
Iterator it = libraries.iterator();
while (it.hasNext()) {
Library library = (Library) it.next();
library.bind(destDir);
try {
if (repo.fetch(library)) {
fetched++;
}
} catch (IOException e) {
//failures to fetch are logged at verbose level
log(ERROR_LIBRARY_FETCH_FAILED + library);
log(e.getMessage(), Project.MSG_VERBOSE);
}
}
} finally {
repo.disconnect();
}

//at this point downloads have finished.
//we do still need to verify that everything worked.
if ((fetched < toFetch && forceDownload)) {
throw new BuildException(ERROR_FORCED_DOWNLOAD_FAILED);
}

verifyAllLibrariesPresent();

}

/**
* bind all libraries to our destination
*/
protected void bindAllLibraries() {
Iterator it = libraries.iterator();
while (it.hasNext()) {
Library library = (Library) it.next();
library.bind(destDir);
}
}

/**
* verify that all libraries are present
*/
protected void verifyAllLibrariesPresent() {
//iterate through the libs we have
boolean missing = false;

Iterator it = libraries.iterator();
while (it.hasNext()) {
Library library = (Library) it.next();
//check for the library existing
if (!library.exists()) {
//and log if one is missing
log("Missing: " + library.toString(),
Project.MSG_ERR);
missing = true;
}
}
if (missing) {
throw new BuildException(ERROR_INCOMPLETE_RETRIEVAL);
}
}

}

+ 447
- 0
src/main/org/apache/tools/ant/taskdefs/optional/repository/HttpRepository.java View File

@@ -0,0 +1,447 @@
/*
* Copyright 2004 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.tools.ant.taskdefs.optional.repository;

import org.apache.commons.httpclient.*;
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 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
* can share this datatype, it is *not* thread safe; you can only use it in one
* thread at at time
*
* @since Ant1.7
*/
public abstract class HttpRepository extends Repository {
/**
* repositoryURL of repository
*/
private String url;

/**
* username
*/
private String username;

/**
* password
*/
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;

/**
* no repository URL
*/
public static final String ERROR_NO_REPOSITORY_URL = "No repository URL";

/**
* owner class
*/
private GetLibraries owner;

/**
* 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;

/**
* get the base URL of the repository
*
* @return
*/
public String getUrl() {
return url;
}

/**
* Set the base URL of the repository
*
* @param url
*/
public void setUrl(String url) {
this.url = url;
}

public String getUsername() {
return username;
}

/**
* set the username for the remote repository
*
* @param username
*/
public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

/**
* set the password for the remote repository
*
* @param password
*/
public void setPassword(String password) {
this.password = password;
}

public String getRealm() {
return realm;
}

/**
* set the realm for authentication; empty string is equivalent to "any
* realm" (the default)
*
* @param 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;
}

/**
* validate yourself
*
* @throws org.apache.tools.ant.BuildException
* if unhappy
*/
public void validate() {
super.validate();
checkChildrenAllowed();
checkAttributesAllowed();
if (url == null || url.length() == 0) {
throw new BuildException(ERROR_NO_REPOSITORY_URL);
}
}

/**
* override point: connection is called at the start of the retrieval
* process
*
* @param newOwner
*
* @throws org.apache.tools.ant.BuildException
*
*/
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;
try {
repository = new URL(url);
} 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);
}

/**
* override point: connection is called at the start of the retrieval
* process
*
* @throws org.apache.tools.ant.BuildException
*
*/

public void disconnect() {
client = null;
retryhandler = null;
}

/**
* Test for a repository being reachable. This method is called after {@link
* #connect(org.apache.tools.ant.taskdefs.optional.repository.GetLibraries)}
* is called, before any files are to be retrieved.
* <p/>
* 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.
*
* @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
*
* @param library
*
* @return true if we retrieved
*
* @throws org.apache.tools.ant.BuildException
*
*/
public boolean fetch(Library library) throws IOException {

String path = getRemoteLibraryURL(library);
logVerbose("Library URL=" + path);
logVerbose("destination =" + library.getAbsolutePath());
GetMethod get = createGet(path);
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();
}

return true;
}

/**
* log something at the verbose level
*
* @param message text to log
*/
protected void logVerbose(String message) {
getOwner().log(message,
Project.MSG_VERBOSE);
}

protected void logDebug(String message) {
getOwner().log(message,
Project.MSG_DEBUG);
}

/**
* Get the path to a remote library. This is the full URL
*
* @param library
*
* @return URL to library
*/
protected abstract String getRemoteLibraryURL(Library library);

/**
* save a stream from a connection to a library. prerequisite: connection
* open and response=200.
*
* @param get
* @param library
*
* @throws java.io.IOException on any trouble.
*/
protected void saveStreamToLibrary(GetMethod get, Library library)
throws IOException {
//we only get here if we are happy
//so save it to a temp file
File tempDest = File.createTempFile("download", ".bin", getOwner()
.getDestDir());
logDebug("Saving file to " + tempDest);
FileOutputStream fos = new FileOutputStream(tempDest);
InputStream is = get.getResponseBodyAsStream();
boolean finished = false;
try {
byte[] buffer = new byte[BLOCKSIZE];
int length;

while ((length = is.read(buffer)) >= 0) {
fos.write(buffer, 0, length);
}
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) {
logVerbose("Deleting temporary file after failed download");
tempDest.delete();
}
}
logDebug("download complete; renaming destination file");
//then copy over the file
File libraryFile = library.getLibraryFile();
if (libraryFile.exists()) {
libraryFile.delete();
}
// set the dest file
if (!tempDest.renameTo(libraryFile)) {
tempDest.delete();
throw new IOException(
"Could not rename temp file to destination file");
}
}

/**
* Returns a string representation of the repository
*
* @return the base URL
*/
public String toString() {
return "Repository at " + getUrl();
}
}

+ 218
- 0
src/main/org/apache/tools/ant/taskdefs/optional/repository/Library.java View File

@@ -0,0 +1,218 @@
/*
* Copyright 2004 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.tools.ant.taskdefs.optional.repository;

import org.apache.tools.ant.BuildException;

import java.io.File;

/**
* How we represent libraries
*
* @since 20-Oct-2004
*/
public class Library {

//project "ant"
private String project;

//version "1.5"
private String version;

//archive prefix "ant-optional"
private String archive;

/**
* very optional attribute; name of the destination. Autocalculated if not
* set.
*/

private String destinationName;

private File libraryFile;

public static final String ERROR_NO_ARCHIVE = "No archive defined";
public static final String ERROR_NO_PROJECT = "No project defined";
public static final String ERROR_NO_VERSION = "No version defined";
public static final String ERROR_NO_SUFFIX = "No version defined";

/**
* suffix
*/
private String suffix = "jar";


public String getProject() {
return project;
}

public void setProject(String project) {
this.project = project;
}

public String getVersion() {
return version;
}

public void setVersion(String version) {
this.version = version;
}

public String getArchive() {
return archive;
}

public void setArchive(String archive) {
this.archive = archive;
}

public String getDestinationName() {
return destinationName;
}

public void setDestinationName(String destinationName) {
this.destinationName = destinationName;
}

/**
* get the suffix for this file.
*
* @return
*/
public String getSuffix() {
return suffix;
}

public void setSuffix(String suffix) {
this.suffix = suffix;
}

public File getLibraryFile() {
return libraryFile;
}

/**
* fault if the field is null or empty
*
* @param field
* @param message text for fault
*
* @throws BuildException if the field is not set up
*/
private void faultIfEmpty(String field, String message) {
if (field == null || field.length() == 0) {
throw new BuildException(message);
}
}

/**
* validate;
*
* @throws BuildException if invalid
*/
public void validate() {
faultIfEmpty(archive, ERROR_NO_ARCHIVE);
faultIfEmpty(project, ERROR_NO_PROJECT);
faultIfEmpty(version, ERROR_NO_VERSION);
faultIfEmpty(version, ERROR_NO_SUFFIX);
}

public String toString() {
return "Library " + getNormalFilename()
+ " from project " + project
+ " to " + getDestinationName();
}

/**
* calculare the destination file of a library
*
* @param baseDir
*
* @throws BuildException if invalid
*/
public void bind(File baseDir) {
validate();
if (destinationName == null) {
destinationName = getNormalFilename();
}
libraryFile = new File(baseDir, destinationName);
}

/**
* a test that is only valid after binding
*
* @return
*/
public boolean exists() {
return libraryFile.exists();
}

/**
* get the last modified date
*
* @return
*/
public long getLastModified() {
return libraryFile.lastModified();
}

/**
* get the filename from the rule of archive+version+'.'+suffix. Clearly
* only valid if all fields are defined.
*
* @return a string representing the expected name of the file at the
* source
*/
public String getNormalFilename() {
return archive + "-" + version + "." + suffix;
}

/**
* get the filename of the destination; no path.
*
* @return
*/
public String getDestFilename() {
if (destinationName == null) {
return getNormalFilename();
} else {
return destinationName;
}
}

/**
* get a maven path (project/filename)
*
* @param separator directory separator
*
* @return
*/
public String getMavenPath(char separator) {
return project + separator + "jars" + separator + getNormalFilename();
}

/**
* get the absolute path of this library
*
* @return
*/
public String getAbsolutePath() {
return libraryFile.getAbsolutePath();
}

}

+ 65
- 0
src/main/org/apache/tools/ant/taskdefs/optional/repository/MavenRepository.java View File

@@ -0,0 +1,65 @@
/*
* Copyright 2004 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.tools.ant.taskdefs.optional.repository;


/**
* A Maven repository knows about maven repository layout rules It also defaults
* to http://www.ibiblio.org/maven/
*
* @link http://maven.apache.org/reference/user-guide.html#Remote_Repository_Layout
* @link
* @since Ant1.7
*/
public class MavenRepository extends HttpRepository {
public static final String MAVEN_URL = "http://www.ibiblio.org/maven/";


/**
* bind to the main maven repository
*/
public MavenRepository() {
setUrl(MAVEN_URL);
}

/**
* Get the path to a remote library. This is the full URL
*
* @param library
*
* @return URL to library
*/
protected String getRemoteLibraryURL(Library library) {
String base = getUrl();
if (!base.endsWith("/")) {
base = base + '/';
}

return base + library.getMavenPath('/');
}

/**
* Returns a string representation of the repository
*
* @return the base URL
*/
public String toString() {
return "Maven Repository at " + getUrl();
}

}

+ 109
- 0
src/main/org/apache/tools/ant/taskdefs/optional/repository/Repository.java View File

@@ -0,0 +1,109 @@
/*
* Copyright 2004 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.tools.ant.taskdefs.optional.repository;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.DataType;

import java.io.IOException;

/**
* This type represents a repository; a place that stores libraries for
* retrieval. To use this type, you must use a non-abstract class, either one
* that ships with Ant, or one you implement and declare yourself.
* <p/>
* The &lt;getlibraries&gt; task lets you supply a repository by reference
* inline {@link GetLibraries#add(Repository)} or on the command line {@link
* GetLibraries#setRepositoryRef(org.apache.tools.ant.types.Reference)}
*
* @since Ant1.7
*/
public abstract class Repository extends DataType {


/**
* validate yourself
*
* @throws BuildException if unhappy
*/
public void validate() {
}

/**
* recursively resolve any references to get the real repository
*
* @return
*/
public final Repository resolve() {
if (getRefid() == null) {
return this;
} else {
Repository repository = (Repository) getCheckedRef(this.getClass(),
"Repository");
return repository;
}
}

/**
* override point: connection is called at the start of the retrieval
* process
*
* @param owner owner of the libraries
*
* @throws BuildException
*/
public void connect(GetLibraries owner) {

}

/**
* override point: connection is called at the start of the retrieval
* process
*
* @throws BuildException
*/

public void disconnect() {

}


/**
* Test for a repository being reachable. This method is called after {@link
* #connect(GetLibraries)} is called, before any files are to be retrieved.
* <p/>
* If it returns false the repository considers itself offline. Similarly,
* any ioexception is interpreted as being offline.
*
* @return true if the repository is online.
*
* @throws IOException
*/
public abstract boolean checkRepositoryReachable() throws IOException;

/**
* fetch a library from the repository
*
* @param library
*
* @return
*/
public abstract boolean fetch(Library library) throws IOException;


}

+ 76
- 0
src/main/org/apache/tools/ant/taskdefs/optional/repository/RepositoryRef.java View File

@@ -0,0 +1,76 @@
/*
* Copyright 2004 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.tools.ant.taskdefs.optional.repository;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Reference;

import java.io.IOException;

/**
* not a real repository; one to paste a reference into the chain for
* resolution.
*
* @since Ant1.7
*/
public final class RepositoryRef extends Repository {


/**
* create a repository reference
*
* @param reference
*/
public RepositoryRef(Project project, Reference reference) {
setRefid(reference);
setProject(project);
}

/**
* empty constructor
*/
public RepositoryRef() {
}

/**
* Test for a repository being reachable. This method is called after {@link
* #connect(GetLibraries)} is called, before any files are to be retrieved.
* <p/>
* If it returns false the repository considers itself offline. Similarly,
* any ioexception is interpreted as being offline.
*
* @return true if the repository is online.
*
* @throws java.io.IOException
*/
public boolean checkRepositoryReachable() throws IOException {
return false;
}

/**
* fetch a library from the repository
*
* @param library
*
* @return
*/
public boolean fetch(Library library) throws IOException {
throw new BuildException("Not Implemented");
}

}

+ 2
- 1
src/main/org/apache/tools/ant/types/defaults.properties View File

@@ -33,4 +33,5 @@ scriptfilter=org.apache.tools.ant.types.optional.ScriptFilter
propertyset=org.apache.tools.ant.types.PropertySet propertyset=org.apache.tools.ant.types.PropertySet
assertions=org.apache.tools.ant.types.Assertions assertions=org.apache.tools.ant.types.Assertions
concatfilter=org.apache.tools.ant.filters.ConcatFilter concatfilter=org.apache.tools.ant.filters.ConcatFilter
ispingable=org.apache.tools.ant.taskdefs.optional.condition.IsPingable
ispingable=org.apache.tools.ant.taskdefs.optional.condition.IsPingable
mavenrepository=org.apache.tools.ant.taskdefs.optional.repository.MavenRepository

+ 109
- 0
src/testcases/org/apache/tools/ant/taskdefs/optional/GetLibrariesTest.java View File

@@ -0,0 +1,109 @@
/*
* Copyright 2004 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.tools.ant.taskdefs.optional;

import org.apache.tools.ant.BuildFileTest;
import org.apache.tools.ant.taskdefs.optional.repository.GetLibraries;

/**
* test the test libraries stuff.
* skip all the tests if we are offline
*/
public class GetLibrariesTest extends BuildFileTest {
private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/";


public GetLibrariesTest(String name) {
super(name);
}

public void setUp() {
configureProject(TASKDEFS_DIR + "getlibraries.xml");
}


protected boolean offline() {
return "true".equals(System.getProperty("offline"));
}

public void tearDown() {
executeTarget("cleanup");
}

public void testEmpty() {
expectBuildException("testEmpty",GetLibraries.ERROR_NO_DEST_DIR);
}

public void testEmpty2() {
expectBuildException("testEmpty2", GetLibraries.ERROR_NO_REPOSITORY);
}

public void testEmpty3() {
expectBuildException("testEmpty3", GetLibraries.ERROR_NO_LIBRARIES);
}

public void testNoRepo() {
expectBuildException("testNoRepo", GetLibraries.ERROR_NO_REPOSITORY);
}

public void testUnknownReference() {
expectBuildException("testUnknownReference", "Reference unknown not found.");
}

/**
* refs are broken
* */
public void testFunctionalInline() {
if(offline()) {
return;
}
executeTarget("testFunctionalInline");
}
public void testMavenInline() {
if (offline()) {
return;
}
executeTarget("testMavenInline");
}

public void testTwoRepositories() {
expectBuildException("testTwoRepositories", GetLibraries.ERROR_ONE_REPOSITORY_ONLY);
}

public void testMavenInlineBadURL() {
if (offline()) {
return;
}
expectBuildException("testTwoRepositories",
GetLibraries.ERROR_INCOMPLETE_RETRIEVAL);
}

public void testRenaming() {
if (offline()) {
return;
}
executeTarget("testRenaming");
}

public void testOverwrite() {
if (offline()) {
return;
}
executeTarget("testOverwrite");
}
}

Loading…
Cancel
Save