/** * Copyright (c) 2008-2011 Sonatype, Inc. * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions. * * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General * Public License Version 3 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License Version 3 * for more details. * * You should have received a copy of the GNU Affero General Public License Version 3 along with this program. If not, see * http://www.gnu.org/licenses. * * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation. * All other trademarks are the property of their respective owners. */ package org.sonatype.nexus.proxy.maven; import java.io.IOException; import java.util.List; import org.apache.maven.artifact.repository.metadata.Metadata; import org.apache.maven.artifact.repository.metadata.Snapshot; import org.apache.maven.artifact.repository.metadata.Versioning; import org.apache.maven.index.artifact.Gav; import org.apache.maven.index.artifact.VersionUtils; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.logging.AbstractLogEnabled; import org.codehaus.plexus.util.StringUtils; /** * Component responsible for metadata maintenance. * * @author cstamas */ @Component( role = MetadataManager.class ) public class DefaultMetadataManager extends AbstractLogEnabled implements MetadataManager { static final String LATEST_VERSION = "LATEST"; static final String SNAPSHOT_VERSION = "SNAPSHOT"; static final String RELEASE_VERSION = "RELEASE"; @Requirement private MetadataUpdater metadataUpdater; @Requirement private MetadataLocator metadataLocator; public void deployArtifact( ArtifactStoreRequest request ) throws IOException { metadataUpdater.deployArtifact( request ); } public void undeployArtifact( ArtifactStoreRequest request ) throws IOException { metadataUpdater.undeployArtifact( request ); } public Gav resolveArtifact( ArtifactStoreRequest gavRequest ) throws IOException { MavenRepository repository = gavRequest.getMavenRepository(); String version = gavRequest.getVersion(); Gav gav = null; if ( LATEST_VERSION.equals( gavRequest.getVersion() ) ) { // TODO: a workaround, adding dummy versions, only to make Gav happy gav = new Gav( gavRequest.getGroupId(), gavRequest.getArtifactId(), RepositoryPolicy.SNAPSHOT.equals( repository.getRepositoryPolicy() ) ? "1-SNAPSHOT" : "1", gavRequest.getClassifier(), gavRequest.getExtension(), null, null, null, false, null, false, null ); version = resolveLatest( gavRequest, gav ); } else if ( RELEASE_VERSION.equals( gavRequest.getVersion() ) ) { // TODO: a workaround, adding dummy versions, only to make Gav happy gav = new Gav( gavRequest.getGroupId(), gavRequest.getArtifactId(), RepositoryPolicy.SNAPSHOT.equals( repository.getRepositoryPolicy() ) ? "1-SNAPSHOT" : "1", gavRequest.getClassifier(), gavRequest.getExtension(), null, null, null, false, null, false, null ); version = resolveRelease( gavRequest, gav ); } if ( LATEST_VERSION.equals( version ) || RELEASE_VERSION.equals( version ) ) { // Nexus was not able to resolve those return null; } else { gav = new Gav( gavRequest.getGroupId(), gavRequest.getArtifactId(), version, gavRequest.getClassifier(), gavRequest.getExtension(), null, null, null, false, null, false, null ); // if it is not "timestamped" version, try to get it if ( gav.isSnapshot() && gav.getVersion().equals( gav.getBaseVersion() ) ) { gav = resolveSnapshot( gavRequest, gav ); } return gav; } } protected String resolveLatest( ArtifactStoreRequest gavRequest, Gav gav ) throws IOException { MavenRepository repository = gavRequest.getMavenRepository(); if ( RepositoryPolicy.SNAPSHOT.equals( repository.getRepositoryPolicy() ) ) { Metadata gaMd = metadataLocator.retrieveGAMetadata( new ArtifactStoreRequest( gavRequest.getMavenRepository(), gav, gavRequest.isRequestLocalOnly(), gavRequest.isRequestRemoteOnly() ) ); if ( gaMd.getVersioning() == null ) { gaMd.setVersioning( new Versioning() ); } String latest = gaMd.getVersioning().getLatest(); if ( StringUtils.isEmpty( latest ) && gaMd.getVersioning().getVersions() != null ) { List<String> versions = gaMd.getVersioning().getVersions(); // iterate over versions for the end, and grab the first snap found for ( int i = versions.size() - 1; i >= 0; i-- ) { if ( VersionUtils.isSnapshot( versions.get( i ) ) ) { latest = versions.get( i ); break; } } } if ( !StringUtils.isEmpty( latest ) ) { return latest; } else { return gavRequest.getVersion(); } } else { return resolveRelease( gavRequest, gav ); } } @SuppressWarnings( "unchecked" ) protected String resolveRelease( ArtifactStoreRequest gavRequest, Gav gav ) throws IOException { MavenRepository repository = gavRequest.getMavenRepository(); if ( RepositoryPolicy.SNAPSHOT.equals( repository.getRepositoryPolicy() ) ) { if ( getLogger().isDebugEnabled() ) { getLogger().debug( "Not a RELEASE repository for resolving GAV: " + gav.getGroupId() + " : " + gav.getArtifactId() + " : " + gav.getVersion() + " in repository " + repository.getId() ); } return gavRequest.getVersion(); } if ( getLogger().isDebugEnabled() ) { getLogger().debug( "Resolving snapshot version for GAV: " + gavRequest.getGroupId() + " : " + gavRequest.getArtifactId() + " : " + gavRequest.getVersion() + " in repository " + repository.getId() ); } Metadata gaMd = metadataLocator.retrieveGAMetadata( new ArtifactStoreRequest( gavRequest.getMavenRepository(), gav, gavRequest.isRequestLocalOnly(), gavRequest.isRequestRemoteOnly() ) ); if ( gaMd.getVersioning() == null ) { gaMd.setVersioning( new Versioning() ); } String release = gaMd.getVersioning().getRelease(); if ( StringUtils.isEmpty( release ) && gaMd.getVersioning().getVersions() != null ) { List<String> versions = gaMd.getVersioning().getVersions(); // iterate over versions for the end, and grab the first snap found for ( int i = versions.size() - 1; i >= 0; i-- ) { if ( !VersionUtils.isSnapshot( versions.get( i ) ) ) { release = versions.get( i ); break; } } } if ( !StringUtils.isEmpty( release ) ) { if ( getLogger().isDebugEnabled() ) { getLogger().debug( "Resolved gav version from '" + gav.getVersion() + "' to '" + release + "'" ); } return release; } else { return gavRequest.getVersion(); } } public Gav resolveSnapshot( ArtifactStoreRequest gavRequest, Gav gav ) throws IOException { MavenRepository repository = gavRequest.getMavenRepository(); if ( gav.isSnapshot() && ( !gav.getVersion().equals( gav.getBaseVersion() ) ) ) { // it is already a timestamped version, return it unmodified return gav; } if ( getLogger().isDebugEnabled() ) { getLogger().debug( "Resolving snapshot version for GAV: " + gav.getGroupId() + " : " + gav.getArtifactId() + " : " + gav.getVersion() + " in repository " + repository.getId() ); } Metadata gavMd = metadataLocator.retrieveGAVMetadata( new ArtifactStoreRequest( gavRequest.getMavenRepository(), gav, gavRequest.isRequestLocalOnly(), gavRequest.isRequestRemoteOnly() ) ); if ( gavMd.getVersioning() == null ) { gavMd.setVersioning( new Versioning() ); } String latest = null; Snapshot current = gavMd.getVersioning().getSnapshot(); if ( current != null ) { latest = gav.getBaseVersion(); latest = latest.replace( SNAPSHOT_VERSION, current.getTimestamp() + "-" + current.getBuildNumber() ); } if ( !StringUtils.isEmpty( latest ) && VersionUtils.isSnapshot( latest ) ) { if ( getLogger().isDebugEnabled() ) { getLogger().debug( "Resolved gav version from '" + gav.getVersion() + "' to '" + latest + "'" ); } Gav result = new Gav( gav.getGroupId(), gav.getArtifactId(), latest, gav.getClassifier(), gav.getExtension(), gav.getSnapshotBuildNumber(), gav.getSnapshotTimeStamp(), gav.getName(), gav.isHash(), gav.getHashType(), gav.isSignature(), gav.getSignatureType() ); return result; } else { return gav; } } }