diff options
Diffstat (limited to 'framework/src/maven/apache-maven-3.3.3/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java')
-rw-r--r-- | framework/src/maven/apache-maven-3.3.3/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/framework/src/maven/apache-maven-3.3.3/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java b/framework/src/maven/apache-maven-3.3.3/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java new file mode 100644 index 00000000..d722644e --- /dev/null +++ b/framework/src/maven/apache-maven-3.3.3/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java @@ -0,0 +1,636 @@ +package org.apache.maven.repository.internal; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.apache.maven.artifact.repository.metadata.Snapshot; +import org.apache.maven.artifact.repository.metadata.SnapshotVersion; +import org.apache.maven.artifact.repository.metadata.Versioning; +import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.StringUtils; +import org.eclipse.aether.RepositoryCache; +import org.eclipse.aether.RepositoryEvent.EventType; +import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.SyncContext; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.impl.MetadataResolver; +import org.eclipse.aether.impl.RepositoryEventDispatcher; +import org.eclipse.aether.impl.SyncContextFactory; +import org.eclipse.aether.impl.VersionResolver; +import org.eclipse.aether.internal.impl.CacheUtils; +import org.eclipse.aether.metadata.DefaultMetadata; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.ArtifactRepository; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.repository.WorkspaceRepository; +import org.eclipse.aether.resolution.MetadataRequest; +import org.eclipse.aether.resolution.MetadataResult; +import org.eclipse.aether.resolution.VersionRequest; +import org.eclipse.aether.resolution.VersionResolutionException; +import org.eclipse.aether.resolution.VersionResult; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.util.ConfigUtils; + +/** + * @author Benjamin Bentmann + */ +@Named +@Component( role = VersionResolver.class ) +public class DefaultVersionResolver + implements VersionResolver, Service +{ + + private static final String MAVEN_METADATA_XML = "maven-metadata.xml"; + + private static final String RELEASE = "RELEASE"; + + private static final String LATEST = "LATEST"; + + private static final String SNAPSHOT = "SNAPSHOT"; + + @SuppressWarnings( "unused" ) + @Requirement( role = LoggerFactory.class ) + private Logger logger = NullLoggerFactory.LOGGER; + + @Requirement + private MetadataResolver metadataResolver; + + @Requirement + private SyncContextFactory syncContextFactory; + + @Requirement + private RepositoryEventDispatcher repositoryEventDispatcher; + + public DefaultVersionResolver() + { + // enable no-arg constructor + } + + @Inject + DefaultVersionResolver( MetadataResolver metadataResolver, SyncContextFactory syncContextFactory, + RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory ) + { + setMetadataResolver( metadataResolver ); + setSyncContextFactory( syncContextFactory ); + setLoggerFactory( loggerFactory ); + setRepositoryEventDispatcher( repositoryEventDispatcher ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + setMetadataResolver( locator.getService( MetadataResolver.class ) ); + setSyncContextFactory( locator.getService( SyncContextFactory.class ) ); + setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) ); + } + + public DefaultVersionResolver setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); + return this; + } + + void setLogger( LoggerFactory loggerFactory ) + { + // plexus support + setLoggerFactory( loggerFactory ); + } + + public DefaultVersionResolver setMetadataResolver( MetadataResolver metadataResolver ) + { + if ( metadataResolver == null ) + { + throw new IllegalArgumentException( "metadata resolver has not been specified" ); + } + this.metadataResolver = metadataResolver; + return this; + } + + public DefaultVersionResolver setSyncContextFactory( SyncContextFactory syncContextFactory ) + { + if ( syncContextFactory == null ) + { + throw new IllegalArgumentException( "sync context factory has not been specified" ); + } + this.syncContextFactory = syncContextFactory; + return this; + } + + public DefaultVersionResolver setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher ) + { + if ( repositoryEventDispatcher == null ) + { + throw new IllegalArgumentException( "repository event dispatcher has not been specified" ); + } + this.repositoryEventDispatcher = repositoryEventDispatcher; + return this; + } + + public VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request ) + throws VersionResolutionException + { + RequestTrace trace = RequestTrace.newChild( request.getTrace(), request ); + + Artifact artifact = request.getArtifact(); + + String version = artifact.getVersion(); + + VersionResult result = new VersionResult( request ); + + Key cacheKey = null; + RepositoryCache cache = session.getCache(); + if ( cache != null && !ConfigUtils.getBoolean( session, false, "aether.versionResolver.noCache" ) ) + { + cacheKey = new Key( session, request ); + + Object obj = cache.get( session, cacheKey ); + if ( obj instanceof Record ) + { + Record record = (Record) obj; + result.setVersion( record.version ); + result.setRepository( CacheUtils.getRepository( session, request.getRepositories(), record.repoClass, + record.repoId ) ); + return result; + } + } + + Metadata metadata; + + if ( RELEASE.equals( version ) ) + { + metadata = + new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), MAVEN_METADATA_XML, + Metadata.Nature.RELEASE ); + } + else if ( LATEST.equals( version ) ) + { + metadata = + new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), MAVEN_METADATA_XML, + Metadata.Nature.RELEASE_OR_SNAPSHOT ); + } + else if ( version.endsWith( SNAPSHOT ) ) + { + WorkspaceReader workspace = session.getWorkspaceReader(); + if ( workspace != null && workspace.findVersions( artifact ).contains( version ) ) + { + metadata = null; + result.setRepository( workspace.getRepository() ); + } + else + { + metadata = + new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), version, MAVEN_METADATA_XML, + Metadata.Nature.SNAPSHOT ); + } + } + else + { + metadata = null; + } + + if ( metadata == null ) + { + result.setVersion( version ); + } + else + { + List<MetadataRequest> metadataReqs = new ArrayList<MetadataRequest>( request.getRepositories().size() ); + + metadataReqs.add( new MetadataRequest( metadata, null, request.getRequestContext() ) ); + + for ( RemoteRepository repository : request.getRepositories() ) + { + MetadataRequest metadataRequest = + new MetadataRequest( metadata, repository, request.getRequestContext() ); + metadataRequest.setDeleteLocalCopyIfMissing( true ); + metadataRequest.setFavorLocalRepository( true ); + metadataRequest.setTrace( trace ); + metadataReqs.add( metadataRequest ); + } + + List<MetadataResult> metadataResults = metadataResolver.resolveMetadata( session, metadataReqs ); + + Map<String, VersionInfo> infos = new HashMap<String, VersionInfo>(); + + for ( MetadataResult metadataResult : metadataResults ) + { + result.addException( metadataResult.getException() ); + + ArtifactRepository repository = metadataResult.getRequest().getRepository(); + if ( repository == null ) + { + repository = session.getLocalRepository(); + } + + Versioning v = readVersions( session, trace, metadataResult.getMetadata(), repository, result ); + merge( artifact, infos, v, repository ); + } + + if ( RELEASE.equals( version ) ) + { + resolve( result, infos, RELEASE ); + } + else if ( LATEST.equals( version ) ) + { + if ( !resolve( result, infos, LATEST ) ) + { + resolve( result, infos, RELEASE ); + } + + if ( result.getVersion() != null && result.getVersion().endsWith( SNAPSHOT ) ) + { + VersionRequest subRequest = new VersionRequest(); + subRequest.setArtifact( artifact.setVersion( result.getVersion() ) ); + if ( result.getRepository() instanceof RemoteRepository ) + { + RemoteRepository r = (RemoteRepository) result.getRepository(); + subRequest.setRepositories( Collections.singletonList( r ) ); + } + else + { + subRequest.setRepositories( request.getRepositories() ); + } + VersionResult subResult = resolveVersion( session, subRequest ); + result.setVersion( subResult.getVersion() ); + result.setRepository( subResult.getRepository() ); + for ( Exception exception : subResult.getExceptions() ) + { + result.addException( exception ); + } + } + } + else + { + String key = SNAPSHOT + getKey( artifact.getClassifier(), artifact.getExtension() ); + merge( infos, SNAPSHOT, key ); + if ( !resolve( result, infos, key ) ) + { + result.setVersion( version ); + } + } + + if ( StringUtils.isEmpty( result.getVersion() ) ) + { + throw new VersionResolutionException( result ); + } + } + + if ( cacheKey != null && metadata != null && isSafelyCacheable( session, artifact ) ) + { + cache.put( session, cacheKey, new Record( result.getVersion(), result.getRepository() ) ); + } + + return result; + } + + private boolean resolve( VersionResult result, Map<String, VersionInfo> infos, String key ) + { + VersionInfo info = infos.get( key ); + if ( info != null ) + { + result.setVersion( info.version ); + result.setRepository( info.repository ); + } + return info != null; + } + + private Versioning readVersions( RepositorySystemSession session, RequestTrace trace, Metadata metadata, + ArtifactRepository repository, VersionResult result ) + { + Versioning versioning = null; + + FileInputStream fis = null; + try + { + if ( metadata != null ) + { + SyncContext syncContext = syncContextFactory.newInstance( session, true ); + + try + { + syncContext.acquire( null, Collections.singleton( metadata ) ); + + if ( metadata.getFile() != null && metadata.getFile().exists() ) + { + fis = new FileInputStream( metadata.getFile() ); + org.apache.maven.artifact.repository.metadata.Metadata m = + new MetadataXpp3Reader().read( fis, false ); + versioning = m.getVersioning(); + + /* + * NOTE: Users occasionally misuse the id "local" for remote repos which screws up the metadata + * of the local repository. This is especially troublesome during snapshot resolution so we try + * to handle that gracefully. + */ + if ( versioning != null && repository instanceof LocalRepository ) + { + if ( versioning.getSnapshot() != null && versioning.getSnapshot().getBuildNumber() > 0 ) + { + Versioning repaired = new Versioning(); + repaired.setLastUpdated( versioning.getLastUpdated() ); + Snapshot snapshot = new Snapshot(); + snapshot.setLocalCopy( true ); + repaired.setSnapshot( snapshot ); + versioning = repaired; + + throw new IOException( "Snapshot information corrupted with remote repository data" + + ", please verify that no remote repository uses the id '" + repository.getId() + + "'" ); + } + } + } + } + finally + { + syncContext.close(); + } + } + } + catch ( Exception e ) + { + invalidMetadata( session, trace, metadata, repository, e ); + result.addException( e ); + } + finally + { + IOUtil.close( fis ); + } + + return ( versioning != null ) ? versioning : new Versioning(); + } + + private void invalidMetadata( RepositorySystemSession session, RequestTrace trace, Metadata metadata, + ArtifactRepository repository, Exception exception ) + { + RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INVALID ); + event.setTrace( trace ); + event.setMetadata( metadata ); + event.setException( exception ); + event.setRepository( repository ); + + repositoryEventDispatcher.dispatch( event.build() ); + } + + private void merge( Artifact artifact, Map<String, VersionInfo> infos, Versioning versioning, + ArtifactRepository repository ) + { + if ( StringUtils.isNotEmpty( versioning.getRelease() ) ) + { + merge( RELEASE, infos, versioning.getLastUpdated(), versioning.getRelease(), repository ); + } + + if ( StringUtils.isNotEmpty( versioning.getLatest() ) ) + { + merge( LATEST, infos, versioning.getLastUpdated(), versioning.getLatest(), repository ); + } + + for ( SnapshotVersion sv : versioning.getSnapshotVersions() ) + { + if ( StringUtils.isNotEmpty( sv.getVersion() ) ) + { + String key = getKey( sv.getClassifier(), sv.getExtension() ); + merge( SNAPSHOT + key, infos, sv.getUpdated(), sv.getVersion(), repository ); + } + } + + Snapshot snapshot = versioning.getSnapshot(); + if ( snapshot != null && versioning.getSnapshotVersions().isEmpty() ) + { + String version = artifact.getVersion(); + if ( snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0 ) + { + String qualifier = snapshot.getTimestamp() + '-' + snapshot.getBuildNumber(); + version = version.substring( 0, version.length() - SNAPSHOT.length() ) + qualifier; + } + merge( SNAPSHOT, infos, versioning.getLastUpdated(), version, repository ); + } + } + + private void merge( String key, Map<String, VersionInfo> infos, String timestamp, String version, + ArtifactRepository repository ) + { + VersionInfo info = infos.get( key ); + if ( info == null ) + { + info = new VersionInfo( timestamp, version, repository ); + infos.put( key, info ); + } + else if ( info.isOutdated( timestamp ) ) + { + info.version = version; + info.repository = repository; + info.timestamp = timestamp; + } + } + + private void merge( Map<String, VersionInfo> infos, String srcKey, String dstKey ) + { + VersionInfo srcInfo = infos.get( srcKey ); + VersionInfo dstInfo = infos.get( dstKey ); + + if ( dstInfo == null + || ( srcInfo != null && dstInfo.isOutdated( srcInfo.timestamp ) + && srcInfo.repository != dstInfo.repository ) ) + { + infos.put( dstKey, srcInfo ); + } + } + + private String getKey( String classifier, String extension ) + { + return StringUtils.clean( classifier ) + ':' + StringUtils.clean( extension ); + } + + private boolean isSafelyCacheable( RepositorySystemSession session, Artifact artifact ) + { + /* + * The workspace/reactor is in flux so we better not assume definitive information for any of its + * artifacts/projects. + */ + + WorkspaceReader workspace = session.getWorkspaceReader(); + if ( workspace == null ) + { + return true; + } + + Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact( artifact ); + + return workspace.findArtifact( pomArtifact ) == null; + } + + private static class VersionInfo + { + + String timestamp; + + String version; + + ArtifactRepository repository; + + public VersionInfo( String timestamp, String version, ArtifactRepository repository ) + { + this.timestamp = ( timestamp != null ) ? timestamp : ""; + this.version = version; + this.repository = repository; + } + + public boolean isOutdated( String timestamp ) + { + return timestamp != null && timestamp.compareTo( this.timestamp ) > 0; + } + + } + + private static class Key + { + + private final String groupId; + + private final String artifactId; + + private final String classifier; + + private final String extension; + + private final String version; + + private final String context; + + private final File localRepo; + + private final WorkspaceRepository workspace; + + private final List<RemoteRepository> repositories; + + private final int hashCode; + + public Key( RepositorySystemSession session, VersionRequest request ) + { + Artifact artifact = request.getArtifact(); + groupId = artifact.getGroupId(); + artifactId = artifact.getArtifactId(); + classifier = artifact.getClassifier(); + extension = artifact.getExtension(); + version = artifact.getVersion(); + localRepo = session.getLocalRepository().getBasedir(); + workspace = CacheUtils.getWorkspace( session ); + repositories = new ArrayList<RemoteRepository>( request.getRepositories().size() ); + boolean repoMan = false; + for ( RemoteRepository repository : request.getRepositories() ) + { + if ( repository.isRepositoryManager() ) + { + repoMan = true; + repositories.addAll( repository.getMirroredRepositories() ); + } + else + { + repositories.add( repository ); + } + } + context = repoMan ? request.getRequestContext() : ""; + + int hash = 17; + hash = hash * 31 + groupId.hashCode(); + hash = hash * 31 + artifactId.hashCode(); + hash = hash * 31 + classifier.hashCode(); + hash = hash * 31 + extension.hashCode(); + hash = hash * 31 + version.hashCode(); + hash = hash * 31 + localRepo.hashCode(); + hash = hash * 31 + CacheUtils.repositoriesHashCode( repositories ); + hashCode = hash; + } + + @Override + public boolean equals( Object obj ) + { + if ( obj == this ) + { + return true; + } + else if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + Key that = (Key) obj; + return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId ) + && classifier.equals( that.classifier ) && extension.equals( that.extension ) + && version.equals( that.version ) && context.equals( that.context ) + && localRepo.equals( that.localRepo ) && CacheUtils.eq( workspace, that.workspace ) + && CacheUtils.repositoriesEquals( repositories, that.repositories ); + } + + @Override + public int hashCode() + { + return hashCode; + } + + } + + private static class Record + { + final String version; + + final String repoId; + + final Class<?> repoClass; + + public Record( String version, ArtifactRepository repository ) + { + this.version = version; + if ( repository != null ) + { + repoId = repository.getId(); + repoClass = repository.getClass(); + } + else + { + repoId = null; + repoClass = null; + } + } + } + +}
\ No newline at end of file |