configureWagon( wagon, repository );
}
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
{
getLogger().debug( "Connecting to repository: \'" + repository.getId() + "\' with url: \'" + repository.getUrl() + "\'." );
wagon.connect( new Repository( repository.getId(), repository.getUrl() ),
getAuthenticationInfo( repository.getId() ), new ProxyInfoProvider()
{
public ProxyInfo getProxyInfo( String protocol )
{
return getProxy( protocol );
}
});
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 )
{
// reset the retry flag.
retry = false;
// TODO: configure on repository
ChecksumObserver md5ChecksumObserver = null;
ChecksumObserver sha1ChecksumObserver = null;
try
{
md5ChecksumObserver = new ChecksumObserver( "MD5" );
wagon.addTransferListener( md5ChecksumObserver );
sha1ChecksumObserver = new ChecksumObserver( "SHA-1" );
wagon.addTransferListener( sha1ChecksumObserver );
// 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;
}
}
catch ( NoSuchAlgorithmException e )
{
throw new TransferFailedException( "Unable to add checksum methods: " + e.getMessage(), e );
}
finally
{
if ( md5ChecksumObserver != null )
{
wagon.removeTransferListener( md5ChecksumObserver );
}
if ( sha1ChecksumObserver != null )
{
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 )
{
getLogger().warn( "*** CHECKSUM FAILED - " + e.getMessage() + " - RETRYING" );
retry = true;
}
else
{
handleChecksumFailure( checksumPolicy, e.getMessage(), e.getCause() );
}
}
catch ( ResourceDoesNotExistException sha1TryException )
{
getLogger().debug( "SHA1 not found, trying MD5", sha1TryException );
// 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
{
disconnectWagon( wagon );
releaseWagon( protocol, wagon );
}
if ( downloaded )
{
if ( !temp.exists() )
{
throw new ResourceDoesNotExistException( "Downloaded file does not exist: " + temp );
}
// The temporary file is named destination + ".tmp" and is done this way to ensure
// that the temporary file is in the same file system as the destination because the
// File.renameTo operation doesn't really work across file systems.
// So we will attempt to do a File.renameTo for efficiency and atomicity, if this fails
// then we will use a brute force copy and delete the temporary file.
if ( !temp.renameTo( destination ) )
{
try
{
FileUtils.copyFile( temp, destination );
temp.delete();
}
catch ( IOException e )
{
throw new TransferFailedException(
"Error copying temporary file to the final destination: " + e.getMessage(), e );
}
}
}
}