package org.apache.archiva.dependency.tree.maven2; /* * 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 org.apache.archiva.admin.model.RepositoryAdminException; import org.apache.archiva.admin.model.beans.NetworkProxy; import org.apache.archiva.admin.model.beans.ProxyConnector; import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin; import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin; import org.apache.archiva.common.plexusbridge.PlexusSisuBridge; import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException; import org.apache.archiva.common.utils.VersionUtil; import org.apache.archiva.maven2.metadata.MavenMetadataReader; import org.apache.archiva.maven2.model.TreeEntry; import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator; import org.apache.archiva.model.ArchivaRepositoryMetadata; import org.apache.archiva.repository.ManagedRepository; import org.apache.archiva.repository.RemoteRepository; import org.apache.archiva.repository.RepositoryRegistry; import org.apache.archiva.repository.maven2.MavenSystemManager; import org.apache.archiva.repository.metadata.base.MetadataTools; import org.apache.archiva.repository.storage.StorageAsset; import org.apache.archiva.xml.XMLException; import org.apache.commons.lang3.StringUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.bridge.MavenRepositorySystem; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.collection.CollectResult; import org.eclipse.aether.collection.DependencyCollectionException; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyVisitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Named; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author Olivier Lamy * @since 1.4-M3 */ @Service("dependencyTreeBuilder#maven3") public class Maven3DependencyTreeBuilder implements DependencyTreeBuilder { private Logger log = LoggerFactory.getLogger( Maven3DependencyTreeBuilder.class ); @Inject private PlexusSisuBridge plexusSisuBridge; private MavenRepositorySystem mavenRepositorySystem; @Inject @Named( "repositoryPathTranslator#maven2" ) private RepositoryPathTranslator pathTranslator; @Inject private ProxyConnectorAdmin proxyConnectorAdmin; @Inject private NetworkProxyAdmin networkProxyAdmin; @Inject RepositoryRegistry repositoryRegistry; @Inject MavenSystemManager mavenSystemManager; @PostConstruct public void initialize() throws PlexusSisuBridgeException { mavenRepositorySystem = plexusSisuBridge.lookup(MavenRepositorySystem.class); } public void buildDependencyTree( List repositoryIds, String groupId, String artifactId, String version, DependencyVisitor dependencyVisitor ) throws DependencyTreeBuilderException { Artifact projectArtifact = mavenRepositorySystem.createProjectArtifact(groupId, artifactId, version); ManagedRepository repository = findArtifactInRepositories( repositoryIds, projectArtifact ); if ( repository == null ) { // metadata could not be resolved log.info("Did not find repository with artifact {}/{}/{}", groupId, artifactId, version); return; } List remoteRepositories = new ArrayList<>(); Map networkProxies = new HashMap<>(); try { // MRM-1411 // TODO: this is a workaround for a lack of proxy capability in the resolvers - replace when it can all be // handled there. It doesn't cache anything locally! Map> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap(); List proxyConnectors = proxyConnectorsMap.get( repository.getId() ); if ( proxyConnectors != null ) { for ( ProxyConnector proxyConnector : proxyConnectors ) { remoteRepositories.add( repositoryRegistry.getRemoteRepository( proxyConnector.getTargetRepoId() ) ); NetworkProxy networkProxyConfig = networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() ); if ( networkProxyConfig != null ) { // key/value: remote repo ID/proxy info networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig ); } } } } catch ( RepositoryAdminException e ) { throw new DependencyTreeBuilderException( e.getMessage(), e ); } // FIXME take care of relative path ResolveRequest resolveRequest = new ResolveRequest(); resolveRequest.dependencyVisitor = dependencyVisitor; resolveRequest.localRepoDir = repository.getContent().getRepoRoot(); resolveRequest.groupId = groupId; resolveRequest.artifactId = artifactId; resolveRequest.version = version; resolveRequest.remoteRepositories = remoteRepositories; resolveRequest.networkProxies = networkProxies; resolve( resolveRequest ); } @Override public List buildDependencyTree( List repositoryIds, String groupId, String artifactId, String version ) throws DependencyTreeBuilderException { List treeEntries = new ArrayList<>(); TreeDependencyNodeVisitor treeDependencyNodeVisitor = new TreeDependencyNodeVisitor( treeEntries ); buildDependencyTree( repositoryIds, groupId, artifactId, version, treeDependencyNodeVisitor ); log.debug( "treeEntries: {}", treeEntries ); return treeEntries; } private static class ResolveRequest { String localRepoDir, groupId, artifactId, version; DependencyVisitor dependencyVisitor; List remoteRepositories; Map networkProxies; } private void resolve( ResolveRequest resolveRequest ) { RepositorySystem system = mavenSystemManager.getRepositorySystem(); RepositorySystemSession session = MavenSystemManager.newRepositorySystemSession( resolveRequest.localRepoDir ); org.eclipse.aether.artifact.Artifact artifact = new DefaultArtifact( resolveRequest.groupId + ":" + resolveRequest.artifactId + ":" + resolveRequest.version ); CollectRequest collectRequest = new CollectRequest(); collectRequest.setRoot( new Dependency( artifact, "" ) ); // add remote repositories for ( RemoteRepository remoteRepository : resolveRequest.remoteRepositories ) { org.eclipse.aether.repository.RemoteRepository repo = new org.eclipse.aether.repository.RemoteRepository.Builder( remoteRepository.getId( ), "default", remoteRepository.getLocation( ).toString() ).build( ); collectRequest.addRepository(repo); } collectRequest.setRequestContext( "project" ); //collectRequest.addRepository( repo ); try { CollectResult collectResult = system.collectDependencies( session, collectRequest ); collectResult.getRoot().accept( resolveRequest.dependencyVisitor ); log.debug("Collected dependency results for resolve"); } catch ( DependencyCollectionException e ) { log.error( "Error while collecting dependencies (resolve): {}", e.getMessage(), e ); } } private ManagedRepository findArtifactInRepositories( List repositoryIds, Artifact projectArtifact ) { for ( String repoId : repositoryIds ) { ManagedRepository managedRepo = repositoryRegistry.getManagedRepository(repoId); StorageAsset repoDir = managedRepo.getAsset(""); StorageAsset file = pathTranslator.toFile( repoDir, projectArtifact.getGroupId(), projectArtifact.getArtifactId(), projectArtifact.getBaseVersion(), projectArtifact.getArtifactId() + "-" + projectArtifact.getVersion() + ".pom" ); if ( file.exists() ) { return managedRepo; } // try with snapshot version if ( StringUtils.endsWith( projectArtifact.getBaseVersion(), VersionUtil.SNAPSHOT ) ) { StorageAsset metadataFile = file.getParent().resolve( MetadataTools.MAVEN_METADATA ); if ( metadataFile.exists() ) { try { ArchivaRepositoryMetadata archivaRepositoryMetadata = MavenMetadataReader.read( metadataFile); int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber(); String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp(); // rebuild file name with timestamped version and build number String timeStampFileName = new StringBuilder( projectArtifact.getArtifactId() ).append( '-' ).append( StringUtils.remove( projectArtifact.getBaseVersion(), "-" + VersionUtil.SNAPSHOT ) ).append( '-' ).append( timeStamp ).append( '-' ).append( Integer.toString( buildNumber ) ).append( ".pom" ).toString(); StorageAsset timeStampFile = file.getParent().resolve( timeStampFileName ); log.debug( "try to find timestamped snapshot version file: {}", timeStampFile); if ( timeStampFile.exists() ) { return managedRepo; } } catch (XMLException | IOException e ) { log.warn( "skip fail to find timestamped snapshot pom: {}", e.getMessage() ); } } } } return null; } }