TransferListener downloadMonitor, String checksumPolicy, boolean force )
throws TransferFailedException, ResourceDoesNotExistException
{
String protocol = repository.getProtocol();
Wagon wagon;
try
{
wagon = getWagon( protocol );
}
catch ( UnsupportedProtocolException e )
{
throw new TransferFailedException( "Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e );
}
if ( downloadMonitor != null )
{
wagon.addTransferListener( downloadMonitor );
}
File temp = new File( destination + ".tmp" );
temp.deleteOnExit();
boolean downloaded = false;
try
{
connectWagon( wagon, repository );
boolean firstRun = true;
boolean retry = true;
// this will run at most twice. The first time, the firstRun flag is turned off, and if the retry flag
// is set on the first run, it will be turned off and not re-set on the second try. This is because the
// only way the retry flag can be set is if ( firstRun == true ).
while ( firstRun || retry )
{
ChecksumObserver md5ChecksumObserver = null;
ChecksumObserver sha1ChecksumObserver = null;
try
{
// TODO: configure on repository
int i = 0;
md5ChecksumObserver = addChecksumObserver( wagon, CHECKSUM_ALGORITHMS[i++] );
sha1ChecksumObserver = addChecksumObserver( wagon, CHECKSUM_ALGORITHMS[i++] );
// reset the retry flag.
retry = false;
// This should take care of creating destination directory now on
if ( destination.exists() && !force )
{
try
{
downloaded = wagon.getIfNewer( remotePath, temp, destination.lastModified() );
if ( !downloaded )
{
// prevent additional checks of this artifact until it expires again
destination.setLastModified( System.currentTimeMillis() );
}
}
catch ( UnsupportedOperationException e )
{
// older wagons throw this. Just get() instead
wagon.get( remotePath, temp );
downloaded = true;
}
}
else
{
wagon.get( remotePath, temp );
downloaded = true;
}
}
finally
{
wagon.removeTransferListener( md5ChecksumObserver );
wagon.removeTransferListener( sha1ChecksumObserver );
}
if ( downloaded )
{
// keep the checksum files from showing up on the download monitor...
if ( downloadMonitor != null )
{
wagon.removeTransferListener( downloadMonitor );
}
// try to verify the SHA-1 checksum for this file.
try
{
verifyChecksum( sha1ChecksumObserver, destination, temp, remotePath, ".sha1", wagon );
}
catch ( ChecksumFailedException e )
{
// if we catch a ChecksumFailedException, it means the transfer/read succeeded, but the checksum
// doesn't match. This could be a problem with the server (ibiblio HTTP-200 error page), so we'll
// try this up to two times. On the second try, we'll handle it as a bona-fide error, based on the
// repository's checksum checking policy.
if ( firstRun )
{
logger.warn( "*** CHECKSUM FAILED - " + e.getMessage() + " - RETRYING" );
retry = true;
}
else
{
handleChecksumFailure( checksumPolicy, e.getMessage(), e.getCause() );
}
}
catch ( ResourceDoesNotExistException sha1TryException )
{
logger.debug( "SHA1 not found, trying MD5: " + sha1TryException.getMessage() );
// if this IS NOT a ChecksumFailedException, it was a problem with transfer/read of the checksum
// file...we'll try again with the MD5 checksum.
try
{
verifyChecksum( md5ChecksumObserver, destination, temp, remotePath, ".md5", wagon );
}
catch ( ChecksumFailedException e )
{
// if we also fail to verify based on the MD5 checksum, and the checksum transfer/read
// succeeded, then we need to determine whether to retry or handle it as a failure.
if ( firstRun )
{
retry = true;
}
else
{
handleChecksumFailure( checksumPolicy, e.getMessage(), e.getCause() );
}
}
catch ( ResourceDoesNotExistException md5TryException )
{
// this was a failed transfer, and we don't want to retry.
handleChecksumFailure( checksumPolicy, "Error retrieving checksum file for " + remotePath,
md5TryException );
}
}
// reinstate the download monitor...
if ( downloadMonitor != null )
{
wagon.addTransferListener( downloadMonitor );
}
}
// unset the firstRun flag, so we don't get caught in an infinite loop...
firstRun = false;
}
}
catch ( ConnectionException e )
{
throw new TransferFailedException( "Connection failed: " + e.getMessage(), e );
}
catch ( AuthenticationException e )
{
throw new TransferFailedException( "Authentication failed: " + e.getMessage(), e );
}
catch ( AuthorizationException e )
{
throw new TransferFailedException( "Authorization failed: " + e.getMessage(), e );
}
finally
{
// Remove remaining TransferListener instances (checksum handlers removed in above finally clause)
if ( downloadMonitor != null )
{
wagon.removeTransferListener( downloadMonitor );
}
disconnectWagon( wagon );
releaseWagon( protocol, wagon );