Index: src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java =================================================================== --- src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java (revision 386674) +++ src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java (working copy) @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -50,6 +51,8 @@ private WagonManager wagonManager; private ArtifactTransformationManager transformationManager; + + private HashMap updatedArtifacts = new HashMap(); protected ArtifactFactory artifactFactory; @@ -88,7 +91,7 @@ } else { - artifact.setResolved( true ); + artifact.setResolved( true ); } } else if ( !artifact.isResolved() ) @@ -172,7 +175,61 @@ } else if ( destination.exists() ) { - // locally resolved...no need to hit the remote repo. + // artifact is locally resolved...but need to ensure up to date with repo + + // check if we have already updated this artifact from repo + // in the current build (may need a better way of doing this) + if ( updatedArtifacts.get(artifact.getId() + ":" + artifact.getType()) == null ) + { + //check with repo and see if artifact is current + if ( isArtifactCurrent(artifact, repositories) ) + { + //mark the is artifact as having been updated + this.getLogger().debug("Artifact " + artifact.getId() + ":" + artifact.getType() + + " is up to date with repository"); + updatedArtifacts.put(artifact.getId() + ":" + artifact.getType(), artifact); + } + else + { + this.getLogger().error("Artifact " + artifact.getGroupId() + ":" + + artifact.getArtifactId() + ":" + artifact.getType() + ":" + + artifact.getVersion() + " does not have same hash value" + + "as remote repository version"); + this.getLogger().error("Retrieving updated version"); + + try + { + if ( artifact.getRepository() != null ) + { + // the transformations discovered the artifact - so use it exclusively + wagonManager.getArtifact( artifact, artifact.getRepository() ); + } + else + { + wagonManager.getArtifact( artifact, repositories ); + } + + if ( !artifact.isResolved() && !destination.exists() ) + { + throw new ArtifactResolutionException( + "Failed to resolve artifact, possibly due to a repository list that is not appropriately equipped for this artifact's metadata.", + artifact, remoteRepositories ); + } + } + catch ( ResourceDoesNotExistException e ) + { + throw new ArtifactNotFoundException( e.getMessage(), artifact, remoteRepositories, e ); + } + catch ( TransferFailedException e ) + { + throw new ArtifactResolutionException( e.getMessage(), artifact, remoteRepositories, e ); + } + + //mark the is artifact as having been updated + updatedArtifacts.put(artifact.getId() + ":" + artifact.getType(), artifact); + } + } + artifact.setResolved( true ); } @@ -201,7 +258,35 @@ } } } + + public boolean isArtifactCurrent(Artifact artifact, List repositories) + { + //assume the artifact is current until proven otherwise + boolean current=true; + + //reference the local hash file file for artifact + File localHash = new File (artifact.getFile() + ".sha1"); + + if (localHash.exists()) + { + String remoteSH1Sum = wagonManager.getArtifactHash(artifact, repositories, "sha1"); + if ( (remoteSH1Sum != null) && (!wagonManager.getHashValueFromFile(localHash).equals(remoteSH1Sum)) ) + current=false; + } + + localHash = new File (artifact.getFile() + ".md5"); + + if (localHash.exists()) + { + String remoteMD5Sum = wagonManager.getArtifactHash(artifact, repositories, "md5"); + if ( (remoteMD5Sum != null) && (!wagonManager.getHashValueFromFile(localHash).equals(remoteMD5Sum)) ) + current=false; + } + + return current; + } + public ArtifactResolutionResult resolveTransitively( Set artifacts, Artifact originatingArtifact, ArtifactRepository localRepository, List remoteRepositories, ArtifactMetadataSource source, ArtifactFilter filter ) Index: src/main/java/org/apache/maven/artifact/manager/WagonManager.java =================================================================== --- src/main/java/org/apache/maven/artifact/manager/WagonManager.java (revision 386674) +++ src/main/java/org/apache/maven/artifact/manager/WagonManager.java (working copy) @@ -44,9 +44,15 @@ void getArtifact( Artifact artifact, List remoteRepositories ) throws TransferFailedException, ResourceDoesNotExistException; + + String getArtifactHash( Artifact artifact, List remoteRepositories, String alg ); + void getArtifact( Artifact artifact, ArtifactRepository repository ) throws TransferFailedException, ResourceDoesNotExistException; + + String getArtifactHash( Artifact artifact, ArtifactRepository repository, String alg ) + throws TransferFailedException, ResourceDoesNotExistException; void putArtifact( File source, Artifact artifact, ArtifactRepository deploymentRepository ) throws TransferFailedException; @@ -60,6 +66,8 @@ void setOnline( boolean online ); + String getHashValueFromFile(File temp); + boolean isOnline(); void addProxy( String protocol, String host, int port, String username, String password, String nonProxyHosts ); Index: src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java =================================================================== --- src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java (revision 386674) +++ src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java (working copy) @@ -16,6 +16,14 @@ * limitations under the License. */ +import java.io.File; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.metadata.ArtifactMetadata; import org.apache.maven.artifact.repository.ArtifactRepository; @@ -50,737 +58,887 @@ import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.xml.Xpp3Dom; -import java.io.File; -import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class DefaultWagonManager - extends AbstractLogEnabled - implements WagonManager, Contextualizable +public class DefaultWagonManager extends AbstractLogEnabled implements WagonManager, Contextualizable { - private PlexusContainer container; + private PlexusContainer container; - // TODO: proxies, authentication and mirrors are via settings, and should come in via an alternate method - perhaps - // attached to ArtifactRepository before the method is called (so AR would be composed of WR, not inherit it) - private Map proxies = new HashMap(); + // TODO: proxies, authentication and mirrors are via settings, and should come in via an alternate method - perhaps + // attached to ArtifactRepository before the method is called (so AR would be composed of WR, not inherit it) + private Map proxies = new HashMap(); - private Map authenticationInfoMap = new HashMap(); + private Map authenticationInfoMap = new HashMap(); - private Map serverPermissionsMap = new HashMap(); + private Map serverPermissionsMap = new HashMap(); - private Map mirrors = new HashMap(); + private Map mirrors = new HashMap(); - private Map serverConfigurationMap = new HashMap(); + private Map serverConfigurationMap = new HashMap(); - private TransferListener downloadMonitor; + private TransferListener downloadMonitor; - private boolean online = true; + private boolean online = true; - private ArtifactRepositoryFactory repositoryFactory; + private ArtifactRepositoryFactory repositoryFactory; - private boolean interactive = true; + private boolean interactive = true; public Wagon getWagon( String protocol ) throws UnsupportedProtocolException - { - Wagon wagon; + { + Wagon wagon; - try - { - wagon = (Wagon) container.lookup( Wagon.ROLE, protocol ); - wagon.setInteractive( interactive ); - } - catch ( ComponentLookupException e ) - { + try + { + wagon = (Wagon) container.lookup(Wagon.ROLE, protocol); + wagon.setInteractive(interactive); + } + catch (ComponentLookupException e) + { throw new UnsupportedProtocolException( "Cannot find wagon which supports the requested protocol: " + protocol, e ); - } + } - return wagon; - } + return wagon; + } - public void putArtifact( File source, Artifact artifact, ArtifactRepository repository ) - throws TransferFailedException - { - putRemoteFile( repository, source, repository.pathOf( artifact ), downloadMonitor ); - } + public void putArtifact(File source, Artifact artifact, ArtifactRepository repository) + throws TransferFailedException + { + putRemoteFile(repository, source, repository.pathOf(artifact), downloadMonitor); + } - public void putArtifactMetadata( File source, ArtifactMetadata artifactMetadata, ArtifactRepository repository ) - throws TransferFailedException - { - getLogger().info( "Uploading " + artifactMetadata ); - putRemoteFile( repository, source, repository.pathOfRemoteRepositoryMetadata( artifactMetadata ), null ); - } + public void putArtifactMetadata(File source, ArtifactMetadata artifactMetadata, ArtifactRepository repository) + throws TransferFailedException + { + getLogger().info("Uploading " + artifactMetadata); + putRemoteFile(repository, source, repository.pathOfRemoteRepositoryMetadata(artifactMetadata), null); + } - private void putRemoteFile( ArtifactRepository repository, File source, String remotePath, + private void putRemoteFile(ArtifactRepository repository, File source, String remotePath, TransferListener downloadMonitor ) throws TransferFailedException - { - failIfNotOnline(); + { + failIfNotOnline(); - String protocol = repository.getProtocol(); + String protocol = repository.getProtocol(); - Wagon wagon; - try - { - wagon = getWagon( protocol ); + Wagon wagon; + try + { + wagon = getWagon(protocol); - configureWagon( wagon, repository ); - } - catch ( UnsupportedProtocolException e ) - { - throw new TransferFailedException( "Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e ); - } + configureWagon(wagon, repository); + } + catch (UnsupportedProtocolException e) + { + throw new TransferFailedException("Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e); + } - if ( downloadMonitor != null ) - { - wagon.addTransferListener( downloadMonitor ); - } + if (downloadMonitor != null) + { + wagon.addTransferListener(downloadMonitor); + } - Map checksums = new HashMap( 2 ); - Map sums = new HashMap( 2 ); + Map checksums = new HashMap(2); + Map sums = new HashMap(2); - // TODO: configure these on the repository - try - { - ChecksumObserver checksumObserver = new ChecksumObserver( "MD5" ); - wagon.addTransferListener( checksumObserver ); - checksums.put( "md5", checksumObserver ); - checksumObserver = new ChecksumObserver( "SHA-1" ); - wagon.addTransferListener( checksumObserver ); - checksums.put( "sha1", checksumObserver ); - } - catch ( NoSuchAlgorithmException e ) - { - throw new TransferFailedException( "Unable to add checksum methods: " + e.getMessage(), e ); - } + // TODO: configure these on the repository + try + { + ChecksumObserver checksumObserver = new ChecksumObserver("MD5"); + wagon.addTransferListener(checksumObserver); + checksums.put("md5", checksumObserver); + checksumObserver = new ChecksumObserver("SHA-1"); + wagon.addTransferListener(checksumObserver); + checksums.put("sha1", checksumObserver); + } + catch (NoSuchAlgorithmException e) + { + throw new TransferFailedException("Unable to add checksum methods: " + e.getMessage(), e); + } - try - { - Repository artifactRepository = new Repository( repository.getId(), repository.getUrl() ); + try + { + Repository artifactRepository = new Repository(repository.getId(), repository.getUrl()); - if ( serverPermissionsMap.containsKey( repository.getId() ) ) - { - RepositoryPermissions perms = (RepositoryPermissions) serverPermissionsMap.get( repository.getId() ); - getLogger().debug( - "adding permissions to wagon connection: " + perms.getFileMode() + " " + perms.getDirectoryMode() ); - artifactRepository.setPermissions( perms ); - } - else - { - getLogger().debug( "not adding permissions to wagon connection" ); - } + if (serverPermissionsMap.containsKey(repository.getId())) + { + RepositoryPermissions perms = (RepositoryPermissions) serverPermissionsMap.get(repository.getId()); + getLogger().debug( + "adding permissions to wagon connection: " + perms.getFileMode() + " " + perms.getDirectoryMode()); + artifactRepository.setPermissions(perms); + } + else + { + getLogger().debug("not adding permissions to wagon connection"); + } - wagon.connect( artifactRepository, getAuthenticationInfo( repository.getId() ), getProxy( protocol ) ); + wagon.connect(artifactRepository, getAuthenticationInfo(repository.getId()), getProxy(protocol)); - wagon.put( source, remotePath ); + wagon.put(source, remotePath); - wagon.removeTransferListener( downloadMonitor ); + wagon.removeTransferListener(downloadMonitor); - // Pre-store the checksums as any future puts will overwrite them - for ( Iterator i = checksums.keySet().iterator(); i.hasNext(); ) - { - String extension = (String) i.next(); - ChecksumObserver observer = (ChecksumObserver) checksums.get( extension ); - sums.put( extension, observer.getActualChecksum() ); - } + // Pre-store the checksums as any future puts will overwrite them + for (Iterator i = checksums.keySet().iterator(); i.hasNext();) + { + String extension = (String) i.next(); + ChecksumObserver observer = (ChecksumObserver) checksums.get(extension); + sums.put(extension, observer.getActualChecksum()); + } - // We do this in here so we can checksum the artifact metadata too, otherwise it could be metadata itself - for ( Iterator i = checksums.keySet().iterator(); i.hasNext(); ) - { - String extension = (String) i.next(); + // We do this in here so we can checksum the artifact metadata too, otherwise it could be metadata itself + for (Iterator i = checksums.keySet().iterator(); i.hasNext();) + { + String extension = (String) i.next(); - // TODO: shouldn't need a file intermediatary - improve wagon to take a stream - File temp = File.createTempFile( "maven-artifact", null ); - temp.deleteOnExit(); - FileUtils.fileWrite( temp.getAbsolutePath(), (String) sums.get( extension ) ); + // TODO: shouldn't need a file intermediatary - improve wagon to take a stream + File temp = File.createTempFile("maven-artifact", null); + temp.deleteOnExit(); + FileUtils.fileWrite(temp.getAbsolutePath(), (String) sums.get(extension)); - wagon.put( temp, remotePath + "." + extension ); - } - } - 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 ); - } - catch ( ResourceDoesNotExistException e ) - { - throw new TransferFailedException( "Resource to deploy not found: " + e.getMessage(), e ); - } - catch ( IOException e ) - { - throw new TransferFailedException( "Error creating temporary file for deployment: " + e.getMessage(), e ); - } - finally - { - disconnectWagon( wagon ); + wagon.put(temp, remotePath + "." + extension); + } + } + 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); + } + catch (ResourceDoesNotExistException e) + { + throw new TransferFailedException("Resource to deploy not found: " + e.getMessage(), e); + } + catch (IOException e) + { + throw new TransferFailedException("Error creating temporary file for deployment: " + e.getMessage(), e); + } + finally + { + disconnectWagon(wagon); - releaseWagon( wagon ); - } - } + releaseWagon(wagon); + } + } public void getArtifact( Artifact artifact, List remoteRepositories ) throws TransferFailedException, ResourceDoesNotExistException - { - // TODO [BP]: The exception handling here needs some work - boolean successful = false; - for ( Iterator iter = remoteRepositories.iterator(); iter.hasNext() && !successful; ) - { - ArtifactRepository repository = (ArtifactRepository) iter.next(); + { + // TODO [BP]: The exception handling here needs some work + boolean successful = false; + for (Iterator iter = remoteRepositories.iterator(); iter.hasNext() && !successful;) + { + ArtifactRepository repository = (ArtifactRepository) iter.next(); - try - { - getArtifact( artifact, repository ); + try + { + getArtifact(artifact, repository); - successful = artifact.isResolved(); - } - catch ( ResourceDoesNotExistException e ) - { - // This one we will eat when looking through remote repositories - // because we want to cycle through them all before squawking. + successful = artifact.isResolved(); + } + catch (ResourceDoesNotExistException e) + { + // This one we will eat when looking through remote repositories + // because we want to cycle through them all before squawking. - getLogger().warn( - "Unable to get resource from repository " + repository.getId() + " (" + repository.getUrl() + ")" ); - } - } + getLogger().warn( + "Unable to get resource from repository " + repository.getId() + " (" + repository.getUrl() + ")"); + } + } - // if it already exists locally we were just trying to force it - ignore the update - if ( !successful && !artifact.getFile().exists() ) - { - throw new ResourceDoesNotExistException( "Unable to download the artifact from any repository" ); - } - } + // if it already exists locally we were just trying to force it - ignore the update + if (!successful && !artifact.getFile().exists()) + { + throw new ResourceDoesNotExistException("Unable to download the artifact from any repository"); + } + } - public void getArtifact( Artifact artifact, ArtifactRepository repository ) - throws TransferFailedException, ResourceDoesNotExistException - { - String remotePath = repository.pathOf( artifact ); + public String getArtifactHash(Artifact artifact, List remoteRepositories, String alg) + { + String hash=null; + // TODO [BP]: The exception handling here needs some work + boolean successful = false; + + //try to get the hash from each repository until you find one that it exists in + for (Iterator iter = remoteRepositories.iterator(); iter.hasNext() && !successful;) + { + ArtifactRepository repository = (ArtifactRepository) iter.next(); - ArtifactRepositoryPolicy policy = artifact.isSnapshot() ? repository.getSnapshots() : repository.getReleases(); + hash=getArtifactHash(artifact, repository, alg); - if ( !policy.isEnabled() ) - { - getLogger().debug( "Skipping disabled repository " + repository.getId() ); - } - else if ( repository.isBlacklisted() ) - { - getLogger().debug( "Skipping blacklisted repository " + repository.getId() ); - } - else - { - getLogger().debug( "Trying repository " + repository.getId() ); - getRemoteFile( repository, artifact.getFile(), remotePath, downloadMonitor, policy.getChecksumPolicy() ); - getLogger().debug( " Artifact resolved" ); + successful = artifact.isResolved(); + + } + + return(hash); + } - artifact.setResolved( true ); - } - } + public String getArtifactHash(Artifact artifact, ArtifactRepository repository, String alg) + { + String hash=null; + String remotePath = repository.pathOf(artifact) + "." + alg; + + //do this for each md5 and sh1 + ArtifactRepositoryPolicy policy = artifact.isSnapshot() ? repository.getSnapshots() : repository.getReleases(); - public void getArtifactMetadata( ArtifactMetadata metadata, ArtifactRepository repository, File destination, + try + { + hash = getRemoteFileHash(repository, artifact.getFile(), remotePath, downloadMonitor, policy.getChecksumPolicy()); + } + catch (TransferFailedException e) + { + return(null); + } + catch (ResourceDoesNotExistException e) + { + return(null); + } + + artifact.setResolved(true); + + return(hash); + } + + public void getArtifact(Artifact artifact, ArtifactRepository repository) throws TransferFailedException, + ResourceDoesNotExistException + { + String remotePath = repository.pathOf(artifact); + + ArtifactRepositoryPolicy policy = artifact.isSnapshot() ? repository.getSnapshots() : repository.getReleases(); + + if (!policy.isEnabled()) + { + getLogger().debug("Skipping disabled repository " + repository.getId()); + } + else if (repository.isBlacklisted()) + { + getLogger().debug("Skipping blacklisted repository " + repository.getId()); + } + else + { + getLogger().debug("Trying repository " + repository.getId()); + getRemoteFile(repository, artifact.getFile(), remotePath, downloadMonitor, policy.getChecksumPolicy()); + getLogger().debug(" Artifact resolved"); + + artifact.setResolved(true); + } + } + + public void getArtifactMetadata(ArtifactMetadata metadata, ArtifactRepository repository, File destination, String checksumPolicy ) throws TransferFailedException, ResourceDoesNotExistException - { - String remotePath = repository.pathOfRemoteRepositoryMetadata( metadata ); + { + String remotePath = repository.pathOfRemoteRepositoryMetadata(metadata); - getRemoteFile( repository, destination, remotePath, null, checksumPolicy ); - } + getRemoteFile(repository, destination, remotePath, null, checksumPolicy); + } - private void getRemoteFile( ArtifactRepository repository, File destination, String remotePath, + private String getRemoteFileHash(ArtifactRepository repository, File destination, String remotePath, + TransferListener downloadMonitor, String checksumPolicy) throws TransferFailedException, ResourceDoesNotExistException + { + // TODO: better excetpions - transfer failed is not enough? + String hash=null; + failIfNotOnline(); + + Wagon wagon; + + ArtifactRepository mirror = getMirror(repository.getId()); + if (mirror != null) + { + repository = repositoryFactory.createArtifactRepository(mirror.getId(), mirror.getUrl(), repository + .getLayout(), repository.getSnapshots(), repository.getReleases()); + } + + String protocol = repository.getProtocol(); + try + { + wagon = getWagon(protocol); + + configureWagon(wagon, repository); + } + catch (UnsupportedProtocolException e) + { + throw new TransferFailedException("Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e); + } + + + if (downloadMonitor != null) + { + wagon.removeTransferListener(downloadMonitor); + } + + File temp = new File(destination + ".md5.tmp"); + temp.deleteOnExit(); + + try + { + wagon.connect(new Repository(repository.getId(), repository.getUrl()), getAuthenticationInfo(repository + .getId()), getProxy(protocol)); + + wagon.get(remotePath, temp); + } + catch (ConnectionException e1) + { + getLogger().error("An error occurred retrieve the hash file from the remote repository"); + } + catch (AuthenticationException e1) + { + getLogger().error("An error occurred authenticating with the remote repository"); + } + catch (TransferFailedException e1) + { + getLogger().error("An error occurred transferring a file from the remote repository"); + } + + catch (AuthorizationException e1) + { + getLogger().error("An error occurred authorizing with the remote repository"); + } + + // reinstate the download monitor... + if (downloadMonitor != null) + { + wagon.addTransferListener(downloadMonitor); + } + + disconnectWagon(wagon); + + releaseWagon(wagon); + + + String expectedChecksum = getHashValueFromFile(temp); + + + + return(expectedChecksum); + + } + + + public String getHashValueFromFile(File temp) + { + String expectedChecksum=null; + try + { + expectedChecksum = FileUtils.fileRead(temp); + } + catch (IOException e2) + { + // FIXME + this.getLogger().warn("Error"); + } + // remove whitespaces at the end + expectedChecksum = expectedChecksum.trim(); + + // check for 'MD5 (name) = CHECKSUM' + if (expectedChecksum.startsWith("MD5")) + { + int lastSpacePos = expectedChecksum.lastIndexOf(' '); + expectedChecksum = expectedChecksum.substring(lastSpacePos + 1); + } + else + { + // remove everything after the first space (if available) + int spacePos = expectedChecksum.indexOf(' '); + + if (spacePos != -1) + { + expectedChecksum = expectedChecksum.substring(0, spacePos); + } + } + return expectedChecksum; + } + + private void getRemoteFile(ArtifactRepository repository, File destination, String remotePath, TransferListener downloadMonitor, String checksumPolicy ) throws TransferFailedException, ResourceDoesNotExistException, ChecksumFailedException - { - // TODO: better excetpions - transfer failed is not enough? + { + // TODO: better excetpions - transfer failed is not enough? - failIfNotOnline(); + failIfNotOnline(); - Wagon wagon; + Wagon wagon; - ArtifactRepository mirror = getMirror( repository.getId() ); - if ( mirror != null ) - { + ArtifactRepository mirror = getMirror(repository.getId()); + if (mirror != null) + { repository = repositoryFactory.createArtifactRepository( mirror.getId(), mirror.getUrl(), repository.getLayout(), repository.getSnapshots(), repository.getReleases() ); - } + } - String protocol = repository.getProtocol(); - try - { - wagon = getWagon( protocol ); + String protocol = repository.getProtocol(); + try + { + wagon = getWagon(protocol); - configureWagon( wagon, repository ); - } - catch ( UnsupportedProtocolException e ) - { - throw new TransferFailedException( "Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e ); - } + configureWagon(wagon, repository); + } + catch (UnsupportedProtocolException e) + { + throw new TransferFailedException("Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e); + } - if ( downloadMonitor != null ) - { - wagon.addTransferListener( downloadMonitor ); - } + if (downloadMonitor != null) + { + wagon.addTransferListener(downloadMonitor); + } - // TODO: configure on repository - ChecksumObserver md5ChecksumObserver; - ChecksumObserver sha1ChecksumObserver; - try - { - md5ChecksumObserver = new ChecksumObserver( "MD5" ); - wagon.addTransferListener( md5ChecksumObserver ); + // TODO: configure on repository + ChecksumObserver md5ChecksumObserver; + ChecksumObserver sha1ChecksumObserver; + try + { + md5ChecksumObserver = new ChecksumObserver("MD5"); + wagon.addTransferListener(md5ChecksumObserver); - sha1ChecksumObserver = new ChecksumObserver( "SHA-1" ); - wagon.addTransferListener( sha1ChecksumObserver ); - } - catch ( NoSuchAlgorithmException e ) - { - throw new TransferFailedException( "Unable to add checksum methods: " + e.getMessage(), e ); - } + sha1ChecksumObserver = new ChecksumObserver("SHA-1"); + wagon.addTransferListener(sha1ChecksumObserver); + } + catch (NoSuchAlgorithmException e) + { + throw new TransferFailedException("Unable to add checksum methods: " + e.getMessage(), e); + } - File temp = new File( destination + ".tmp" ); - temp.deleteOnExit(); + File temp = new File(destination + ".tmp"); + temp.deleteOnExit(); - boolean downloaded = false; + boolean downloaded = false; - try - { + try + { wagon.connect( new Repository( repository.getId(), repository.getUrl() ), getAuthenticationInfo( repository.getId() ), getProxy( protocol ) ); - boolean firstRun = true; - boolean retry = true; + 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 ) + // 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; + + // This should take care of creating destination directory now on + if (destination.exists()) { - // reset the retry flag. - retry = false; + downloaded = wagon.getIfNewer(remotePath, temp, destination.lastModified()); + } + else + { + wagon.get(remotePath, temp); + downloaded = true; + } - // This should take care of creating destination directory now on - if ( destination.exists() ) - { - downloaded = wagon.getIfNewer( remotePath, temp, destination.lastModified() ); - } - else - { - wagon.get( remotePath, temp ); - downloaded = true; - } + if (downloaded) + { + // keep the checksum files from showing up on the download monitor... + if (downloadMonitor != null) + { + wagon.removeTransferListener(downloadMonitor); + } - 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); - // 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); + } + } - // 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); + } + } - // 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); - // 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(wagon); + } - releaseWagon( wagon ); - } + if (downloaded) + { + if (!temp.exists()) + { + throw new ResourceDoesNotExistException("Downloaded file does not exist: " + temp); + } - if ( downloaded ) - { - if ( !temp.exists() ) + // 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 { - throw new ResourceDoesNotExistException( "Downloaded file does not exist: " + temp ); + FileUtils.copyFile(temp, destination); + + temp.delete(); } - - // 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 ) ) + catch (IOException e) { - try - { - FileUtils.copyFile( temp, destination ); - - temp.delete(); - } - catch ( IOException e ) - { throw new TransferFailedException( "Error copying temporary file to the final destination: " + e.getMessage(), e ); - } } - } - } + } + } + } private void failIfNotOnline() throws TransferFailedException - { - if ( !isOnline() ) - { - throw new TransferFailedException( "System is offline." ); - } - } + { + if (!isOnline()) + { + throw new TransferFailedException("System is offline."); + } + } - private void handleChecksumFailure( String checksumPolicy, String message, Throwable cause ) - throws ChecksumFailedException - { - if ( ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( checksumPolicy ) ) - { - throw new ChecksumFailedException( message, cause ); - } - else if ( !ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( checksumPolicy ) ) - { - // warn if it is set to anything other than ignore - getLogger().warn( "*** CHECKSUM FAILED - " + message + " - IGNORING" ); - } - // otherwise it is ignore - } + private void handleChecksumFailure(String checksumPolicy, String message, Throwable cause) + throws ChecksumFailedException + { + if (ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL.equals(checksumPolicy)) + { + throw new ChecksumFailedException(message, cause); + } + else if (!ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals(checksumPolicy)) + { + // warn if it is set to anything other than ignore + getLogger().warn("*** CHECKSUM FAILED - " + message + " - IGNORING"); + } + // otherwise it is ignore + } - private void verifyChecksum( ChecksumObserver checksumObserver, File destination, File tempDestination, + private void verifyChecksum(ChecksumObserver checksumObserver, File destination, File tempDestination, String remotePath, String checksumFileExtension, Wagon wagon ) throws ResourceDoesNotExistException, TransferFailedException, AuthorizationException - { - try - { - // grab it first, because it's about to change... - String actualChecksum = checksumObserver.getActualChecksum(); + { + try + { + // grab it first, because it's about to change... + String actualChecksum = checksumObserver.getActualChecksum(); - File tempChecksumFile = new File( tempDestination + checksumFileExtension + ".tmp" ); - tempChecksumFile.deleteOnExit(); - wagon.get( remotePath + checksumFileExtension, tempChecksumFile ); + File tempChecksumFile = new File(tempDestination + checksumFileExtension + ".tmp"); + tempChecksumFile.deleteOnExit(); + wagon.get(remotePath + checksumFileExtension, tempChecksumFile); - String expectedChecksum = FileUtils.fileRead( tempChecksumFile ); + String expectedChecksum = FileUtils.fileRead(tempChecksumFile); - // remove whitespaces at the end - expectedChecksum = expectedChecksum.trim(); + // remove whitespaces at the end + expectedChecksum = expectedChecksum.trim(); - // check for 'MD5 (name) = CHECKSUM' - if ( expectedChecksum.startsWith( "MD5" ) ) + // check for 'MD5 (name) = CHECKSUM' + if (expectedChecksum.startsWith("MD5")) + { + int lastSpacePos = expectedChecksum.lastIndexOf(' '); + expectedChecksum = expectedChecksum.substring(lastSpacePos + 1); + } + else + { + // remove everything after the first space (if available) + int spacePos = expectedChecksum.indexOf(' '); + + if (spacePos != -1) { - int lastSpacePos = expectedChecksum.lastIndexOf( ' ' ); - expectedChecksum = expectedChecksum.substring( lastSpacePos + 1 ); + expectedChecksum = expectedChecksum.substring(0, spacePos); } - else + } + if (expectedChecksum.equals(actualChecksum)) + { + File checksumFile = new File(destination + checksumFileExtension); + if (checksumFile.exists()) { - // remove everything after the first space (if available) - int spacePos = expectedChecksum.indexOf( ' ' ); - - if ( spacePos != -1 ) - { - expectedChecksum = expectedChecksum.substring( 0, spacePos ); - } + checksumFile.delete(); } - if ( expectedChecksum.equals( actualChecksum ) ) - { - File checksumFile = new File( destination + checksumFileExtension ); - if ( checksumFile.exists() ) - { - checksumFile.delete(); - } - FileUtils.copyFile( tempChecksumFile, checksumFile ); - } - else - { + FileUtils.copyFile(tempChecksumFile, checksumFile); + } + else + { throw new ChecksumFailedException( "Checksum failed on download: local = '" + actualChecksum + "'; remote = '" + expectedChecksum + "'" ); - } - } - catch ( IOException e ) - { - throw new ChecksumFailedException( "Invalid checksum file", e ); - } - } + } + } + catch (IOException e) + { + throw new ChecksumFailedException("Invalid checksum file", e); + } + } - private void disconnectWagon( Wagon wagon ) - { - try - { - wagon.disconnect(); - } - catch ( ConnectionException e ) - { - getLogger().error( "Problem disconnecting from wagon - ignoring: " + e.getMessage() ); - } - } + private void disconnectWagon(Wagon wagon) + { + try + { + wagon.disconnect(); + } + catch (ConnectionException e) + { + getLogger().error("Problem disconnecting from wagon - ignoring: " + e.getMessage()); + } + } - private void releaseWagon( Wagon wagon ) - { - try - { - container.release( wagon ); - } - catch ( ComponentLifecycleException e ) - { - getLogger().error( "Problem releasing wagon - ignoring: " + e.getMessage() ); - } - } + private void releaseWagon(Wagon wagon) + { + try + { + container.release(wagon); + } + catch (ComponentLifecycleException e) + { + getLogger().error("Problem releasing wagon - ignoring: " + e.getMessage()); + } + } - public ProxyInfo getProxy( String protocol ) - { - return (ProxyInfo) proxies.get( protocol ); - } + public ProxyInfo getProxy(String protocol) + { + return (ProxyInfo) proxies.get(protocol); + } - public AuthenticationInfo getAuthenticationInfo( String id ) - { - return (AuthenticationInfo) authenticationInfoMap.get( id ); - } + public AuthenticationInfo getAuthenticationInfo(String id) + { + return (AuthenticationInfo) authenticationInfoMap.get(id); + } - public ArtifactRepository getMirror( String mirrorOf ) - { - return (ArtifactRepository) mirrors.get( mirrorOf ); - } + public ArtifactRepository getMirror(String mirrorOf) + { + return (ArtifactRepository) mirrors.get(mirrorOf); + } - /** - * Set the proxy used for a particular protocol. - * - * @param protocol the protocol (required) - * @param host the proxy host name (required) - * @param port the proxy port (required) - * @param username the username for the proxy, or null if there is none - * @param password the password for the proxy, or null if there is none - * @param nonProxyHosts the set of hosts not to use the proxy for. Follows Java system - * property format: *.foo.com|localhost. - * @todo [BP] would be nice to configure this via plexus in some way - */ + /** + * Set the proxy used for a particular protocol. + * + * @param protocol the protocol (required) + * @param host the proxy host name (required) + * @param port the proxy port (required) + * @param username the username for the proxy, or null if there is none + * @param password the password for the proxy, or null if there is none + * @param nonProxyHosts the set of hosts not to use the proxy for. Follows Java system + * property format: *.foo.com|localhost. + * @todo [BP] would be nice to configure this via plexus in some way + */ public void addProxy( String protocol, String host, int port, String username, String password, String nonProxyHosts ) - { - ProxyInfo proxyInfo = new ProxyInfo(); - proxyInfo.setHost( host ); - proxyInfo.setType( protocol ); - proxyInfo.setPort( port ); - proxyInfo.setNonProxyHosts( nonProxyHosts ); - proxyInfo.setUserName( username ); - proxyInfo.setPassword( password ); + { + ProxyInfo proxyInfo = new ProxyInfo(); + proxyInfo.setHost(host); + proxyInfo.setType(protocol); + proxyInfo.setPort(port); + proxyInfo.setNonProxyHosts(nonProxyHosts); + proxyInfo.setUserName(username); + proxyInfo.setPassword(password); - proxies.put( protocol, proxyInfo ); - } + proxies.put(protocol, proxyInfo); + } public void contextualize( Context context ) throws ContextException - { - container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY ); - } + { + container = (PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY); + } - /** - * @todo I'd rather not be setting this explicitly. - */ - public void setDownloadMonitor( TransferListener downloadMonitor ) - { - this.downloadMonitor = downloadMonitor; - } + /** + * @todo I'd rather not be setting this explicitly. + */ + public void setDownloadMonitor(TransferListener downloadMonitor) + { + this.downloadMonitor = downloadMonitor; + } - public void addAuthenticationInfo( String repositoryId, String username, String password, String privateKey, - String passphrase ) - { - AuthenticationInfo authInfo = new AuthenticationInfo(); + public void addAuthenticationInfo(String repositoryId, String username, String password, String privateKey, + String passphrase) + { + AuthenticationInfo authInfo = new AuthenticationInfo(); - authInfo.setUserName( username ); + authInfo.setUserName(username); - authInfo.setPassword( password ); + authInfo.setPassword(password); - authInfo.setPrivateKey( privateKey ); + authInfo.setPrivateKey(privateKey); - authInfo.setPassphrase( passphrase ); + authInfo.setPassphrase(passphrase); - authenticationInfoMap.put( repositoryId, authInfo ); - } + authenticationInfoMap.put(repositoryId, authInfo); + } - public void addPermissionInfo( String repositoryId, String filePermissions, String directoryPermissions ) - { + public void addPermissionInfo(String repositoryId, String filePermissions, String directoryPermissions) + { - RepositoryPermissions permissions = new RepositoryPermissions(); - boolean addPermissions = false; + RepositoryPermissions permissions = new RepositoryPermissions(); + boolean addPermissions = false; - if ( filePermissions != null ) - { - permissions.setFileMode( filePermissions ); - addPermissions = true; - } + if (filePermissions != null) + { + permissions.setFileMode(filePermissions); + addPermissions = true; + } - if ( directoryPermissions != null ) - { - permissions.setDirectoryMode( directoryPermissions ); - addPermissions = true; - } + if (directoryPermissions != null) + { + permissions.setDirectoryMode(directoryPermissions); + addPermissions = true; + } - if ( addPermissions ) - { - serverPermissionsMap.put( repositoryId, permissions ); - } - } + if (addPermissions) + { + serverPermissionsMap.put(repositoryId, permissions); + } + } - public void addMirror( String id, String mirrorOf, String url ) - { - ArtifactRepository mirror = new DefaultArtifactRepository( id, url, null ); + public void addMirror(String id, String mirrorOf, String url) + { + ArtifactRepository mirror = new DefaultArtifactRepository(id, url, null); - mirrors.put( mirrorOf, mirror ); - } + mirrors.put(mirrorOf, mirror); + } - public void setOnline( boolean online ) - { - this.online = online; - } + public void setOnline(boolean online) + { + this.online = online; + } - public boolean isOnline() - { - return online; - } + public boolean isOnline() + { + return online; + } - public void setInteractive( boolean interactive ) - { - this.interactive = interactive; - } + public void setInteractive(boolean interactive) + { + this.interactive = interactive; + } - - /** - * Applies the server configuration to the wagon - * - * @param wagon the wagon to configure - * @param repository the repository that has the configuration - * @throws WagonConfigurationException wraps any error given during configuration of the wagon instance - */ + /** + * Applies the server configuration to the wagon + * + * @param wagon the wagon to configure + * @param repository the repository that has the configuration + * @throws WagonConfigurationException wraps any error given during configuration of the wagon instance + */ private void configureWagon( Wagon wagon, ArtifactRepository repository ) throws WagonConfigurationException - { + { - final String repositoryId = repository.getId(); + final String repositoryId = repository.getId(); - if ( serverConfigurationMap.containsKey( repositoryId ) ) - { - ComponentConfigurator componentConfigurator = null; - try - { - componentConfigurator = (ComponentConfigurator) container.lookup( ComponentConfigurator.ROLE ); - componentConfigurator.configureComponent( wagon, (PlexusConfiguration) serverConfigurationMap - .get( repositoryId ), container.getContainerRealm() ); - } - catch ( final ComponentLookupException e ) - { - throw new WagonConfigurationException( repositoryId, + if (serverConfigurationMap.containsKey(repositoryId)) + { + ComponentConfigurator componentConfigurator = null; + try + { + componentConfigurator = (ComponentConfigurator) container.lookup(ComponentConfigurator.ROLE); + componentConfigurator.configureComponent(wagon, (PlexusConfiguration) serverConfigurationMap + .get(repositoryId), container.getContainerRealm()); + } + catch (final ComponentLookupException e) + { + throw new WagonConfigurationException(repositoryId, "Unable to lookup wagon configurator. Wagon configuration cannot be applied.", e ); - } - catch ( ComponentConfigurationException e ) + } + catch (ComponentConfigurationException e) + { + throw new WagonConfigurationException(repositoryId, "Unable to apply wagon configuration.", e); + } + finally + { + if (componentConfigurator != null) { - throw new WagonConfigurationException( repositoryId, "Unable to apply wagon configuration.", e ); + try + { + container.release(componentConfigurator); + } + catch (ComponentLifecycleException e) + { + getLogger().error("Problem releasing configurator - ignoring: " + e.getMessage()); + } } - finally - { - if ( componentConfigurator != null ) - { - try - { - container.release( componentConfigurator ); - } - catch ( ComponentLifecycleException e ) - { - getLogger().error( "Problem releasing configurator - ignoring: " + e.getMessage() ); - } - } - } - } - } + } + } + } + public void addConfiguration(String repositoryId, Xpp3Dom configuration) + { - public void addConfiguration( String repositoryId, Xpp3Dom configuration ) - { + if (repositoryId == null || configuration == null) + { + throw new IllegalArgumentException("arguments can't be null"); + } - if ( repositoryId == null || configuration == null ) - { - throw new IllegalArgumentException( "arguments can't be null" ); - } + final XmlPlexusConfiguration xmlConf = new XmlPlexusConfiguration(configuration); - final XmlPlexusConfiguration xmlConf = new XmlPlexusConfiguration( configuration ); - - serverConfigurationMap.put( repositoryId, xmlConf ); - } + serverConfigurationMap.put(repositoryId, xmlConf); + } }