001 package org.apache.archiva.dependency.tree.maven2; 002 /* 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 */ 020 021 022 import org.apache.archiva.admin.model.RepositoryAdminException; 023 import org.apache.archiva.admin.model.beans.ManagedRepository; 024 import org.apache.archiva.admin.model.beans.NetworkProxy; 025 import org.apache.archiva.admin.model.beans.ProxyConnector; 026 import org.apache.archiva.admin.model.beans.RemoteRepository; 027 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin; 028 import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin; 029 import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin; 030 import org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin; 031 import org.apache.archiva.common.plexusbridge.PlexusSisuBridge; 032 import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException; 033 import org.apache.archiva.common.utils.VersionUtil; 034 import org.apache.archiva.maven2.metadata.MavenMetadataReader; 035 import org.apache.archiva.maven2.model.TreeEntry; 036 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator; 037 import org.apache.archiva.model.ArchivaRepositoryMetadata; 038 import org.apache.archiva.proxy.common.WagonFactory; 039 import org.apache.archiva.repository.metadata.MetadataTools; 040 import org.apache.archiva.xml.XMLException; 041 import org.apache.commons.lang.StringUtils; 042 import org.apache.maven.artifact.Artifact; 043 import org.apache.maven.artifact.factory.ArtifactFactory; 044 import org.apache.maven.model.building.DefaultModelBuilderFactory; 045 import org.apache.maven.model.building.ModelBuilder; 046 import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader; 047 import org.apache.maven.repository.internal.DefaultVersionRangeResolver; 048 import org.apache.maven.repository.internal.DefaultVersionResolver; 049 import org.apache.maven.repository.internal.MavenRepositorySystemSession; 050 import org.slf4j.Logger; 051 import org.slf4j.LoggerFactory; 052 import org.sonatype.aether.RepositorySystem; 053 import org.sonatype.aether.RepositorySystemSession; 054 import org.sonatype.aether.collection.CollectRequest; 055 import org.sonatype.aether.collection.CollectResult; 056 import org.sonatype.aether.collection.DependencyCollectionException; 057 import org.sonatype.aether.collection.DependencySelector; 058 import org.sonatype.aether.graph.Dependency; 059 import org.sonatype.aether.graph.DependencyVisitor; 060 import org.sonatype.aether.impl.ArtifactDescriptorReader; 061 import org.sonatype.aether.impl.VersionRangeResolver; 062 import org.sonatype.aether.impl.VersionResolver; 063 import org.sonatype.aether.impl.internal.DefaultServiceLocator; 064 import org.sonatype.aether.impl.internal.SimpleLocalRepositoryManager; 065 import org.sonatype.aether.repository.LocalRepository; 066 import org.sonatype.aether.spi.connector.RepositoryConnectorFactory; 067 import org.sonatype.aether.util.artifact.DefaultArtifact; 068 import org.sonatype.aether.util.graph.selector.AndDependencySelector; 069 import org.sonatype.aether.util.graph.selector.ExclusionDependencySelector; 070 import org.springframework.stereotype.Service; 071 072 import javax.annotation.PostConstruct; 073 import javax.inject.Inject; 074 import javax.inject.Named; 075 import java.io.File; 076 import java.util.ArrayList; 077 import java.util.HashMap; 078 import java.util.List; 079 import java.util.Map; 080 081 /** 082 * @author Olivier Lamy 083 * @since 1.4-M3 084 */ 085 @Service("dependencyTreeBuilder#maven3") 086 public class Maven3DependencyTreeBuilder 087 implements DependencyTreeBuilder 088 { 089 private Logger log = LoggerFactory.getLogger( getClass() ); 090 091 @Inject 092 private PlexusSisuBridge plexusSisuBridge; 093 094 @Inject 095 @Named(value = "repositoryPathTranslator#maven2") 096 private RepositoryPathTranslator pathTranslator; 097 098 @Inject 099 private WagonFactory wagonFactory; 100 101 @Inject 102 private ManagedRepositoryAdmin managedRepositoryAdmin; 103 104 @Inject 105 private ProxyConnectorAdmin proxyConnectorAdmin; 106 107 @Inject 108 private NetworkProxyAdmin networkProxyAdmin; 109 110 @Inject 111 private RemoteRepositoryAdmin remoteRepositoryAdmin; 112 113 private ArtifactFactory factory; 114 115 private ModelBuilder builder; 116 117 @PostConstruct 118 public void initialize() 119 throws PlexusSisuBridgeException 120 { 121 factory = plexusSisuBridge.lookup( ArtifactFactory.class, "default" ); 122 123 DefaultModelBuilderFactory defaultModelBuilderFactory = new DefaultModelBuilderFactory(); 124 builder = defaultModelBuilderFactory.newInstance(); 125 } 126 127 public void buildDependencyTree( List<String> repositoryIds, String groupId, String artifactId, String version, 128 DependencyVisitor dependencyVisitor ) 129 throws DependencyTreeBuilderException 130 { 131 Artifact projectArtifact = factory.createProjectArtifact( groupId, artifactId, version ); 132 ManagedRepository repository = null; 133 try 134 { 135 repository = findArtifactInRepositories( repositoryIds, projectArtifact ); 136 } 137 catch ( RepositoryAdminException e ) 138 { 139 // FIXME better exception 140 throw new DependencyTreeBuilderException( "Cannot build project dependency tree " + e.getMessage(), e ); 141 } 142 143 if ( repository == null ) 144 { 145 // metadata could not be resolved 146 return; 147 } 148 149 try 150 { 151 // MRM-1411 152 // TODO: this is a workaround for a lack of proxy capability in the resolvers - replace when it can all be 153 // handled there. It doesn't cache anything locally! 154 List<RemoteRepository> remoteRepositories = new ArrayList<RemoteRepository>(); 155 Map<String, NetworkProxy> networkProxies = new HashMap<String, NetworkProxy>(); 156 157 Map<String, List<ProxyConnector>> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap(); 158 List<ProxyConnector> proxyConnectors = proxyConnectorsMap.get( repository.getId() ); 159 if ( proxyConnectors != null ) 160 { 161 for ( ProxyConnector proxyConnector : proxyConnectors ) 162 { 163 remoteRepositories.add( 164 remoteRepositoryAdmin.getRemoteRepository( proxyConnector.getTargetRepoId() ) ); 165 166 NetworkProxy networkProxyConfig = networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() ); 167 168 if ( networkProxyConfig != null ) 169 { 170 // key/value: remote repo ID/proxy info 171 networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig ); 172 } 173 } 174 } 175 } 176 catch ( RepositoryAdminException e ) 177 { 178 throw new DependencyTreeBuilderException( e.getMessage(), e ); 179 } 180 181 // FIXME take care of relative path 182 resolve( repository.getLocation(), groupId, artifactId, version, dependencyVisitor ); 183 } 184 185 186 public List<TreeEntry> buildDependencyTree( List<String> repositoryIds, String groupId, String artifactId, 187 String version ) 188 throws DependencyTreeBuilderException 189 { 190 191 List<TreeEntry> treeEntries = new ArrayList<TreeEntry>(); 192 TreeDependencyNodeVisitor treeDependencyNodeVisitor = new TreeDependencyNodeVisitor( treeEntries ); 193 194 buildDependencyTree( repositoryIds, groupId, artifactId, version, treeDependencyNodeVisitor ); 195 196 log.debug( "treeEntrie: {}", treeEntries ); 197 return treeEntries; 198 } 199 200 201 private void resolve( String localRepoDir, String groupId, String artifactId, String version, 202 DependencyVisitor dependencyVisitor ) 203 { 204 205 RepositorySystem system = newRepositorySystem(); 206 207 RepositorySystemSession session = newRepositorySystemSession( system, localRepoDir ); 208 209 org.sonatype.aether.artifact.Artifact artifact = 210 new DefaultArtifact( groupId + ":" + artifactId + ":" + version ); 211 212 CollectRequest collectRequest = new CollectRequest(); 213 collectRequest.setRoot( new Dependency( artifact, "" ) ); 214 215 // add remote repositories ? 216 //collectRequest.addRepository( ) 217 218 collectRequest.setRequestContext( "project" ); 219 220 //collectRequest.addRepository( repo ); 221 222 try 223 { 224 CollectResult collectResult = system.collectDependencies( session, collectRequest ); 225 collectResult.getRoot().accept( dependencyVisitor ); 226 log.debug( "test" ); 227 } 228 catch ( DependencyCollectionException e ) 229 { 230 log.error( e.getMessage(), e ); 231 } 232 233 234 } 235 236 public static RepositorySystem newRepositorySystem() 237 { 238 DefaultServiceLocator locator = new DefaultServiceLocator(); 239 locator.addService( RepositoryConnectorFactory.class, 240 ArchivaRepositoryConnectorFactory.class );// FileRepositoryConnectorFactory.class ); 241 locator.addService( VersionResolver.class, DefaultVersionResolver.class ); 242 locator.addService( VersionRangeResolver.class, DefaultVersionRangeResolver.class ); 243 locator.addService( ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class ); 244 //locator.addService( RepositoryConnectorFactory.class, WagonRepositoryConnectorFactory.class ); 245 //locator.setServices( WagonProvider.class, ); 246 247 return locator.getService( RepositorySystem.class ); 248 } 249 250 public static RepositorySystemSession newRepositorySystemSession( RepositorySystem system, String localRepoDir ) 251 { 252 MavenRepositorySystemSession session = new MavenRepositorySystemSession(); 253 254 DependencySelector depFilter = new AndDependencySelector( new ExclusionDependencySelector() ); 255 session.setDependencySelector( depFilter ); 256 257 LocalRepository localRepo = new LocalRepository( localRepoDir ); 258 session.setLocalRepositoryManager( 259 new SimpleLocalRepositoryManager( localRepoDir ) );// system.newLocalRepositoryManager( localRepo ) ); 260 261 //session.setTransferListener( ); 262 //session.setRepositoryListener( n ); 263 264 return session; 265 } 266 267 268 private ManagedRepository findArtifactInRepositories( List<String> repositoryIds, Artifact projectArtifact ) 269 throws RepositoryAdminException 270 { 271 for ( String repoId : repositoryIds ) 272 { 273 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId ); 274 275 File repoDir = new File( managedRepository.getLocation() ); 276 File file = pathTranslator.toFile( repoDir, projectArtifact.getGroupId(), projectArtifact.getArtifactId(), 277 projectArtifact.getBaseVersion(), 278 projectArtifact.getArtifactId() + "-" + projectArtifact.getVersion() 279 + ".pom" ); 280 281 if ( file.exists() ) 282 { 283 return managedRepository; 284 } 285 // try with snapshot version 286 if ( StringUtils.endsWith( projectArtifact.getBaseVersion(), VersionUtil.SNAPSHOT ) ) 287 { 288 File metadataFile = new File( file.getParent(), MetadataTools.MAVEN_METADATA ); 289 if ( metadataFile.exists() ) 290 { 291 try 292 { 293 ArchivaRepositoryMetadata archivaRepositoryMetadata = MavenMetadataReader.read( metadataFile ); 294 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber(); 295 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp(); 296 // rebuild file name with timestamped version and build number 297 String timeStampFileName = 298 new StringBuilder( projectArtifact.getArtifactId() ).append( '-' ).append( 299 StringUtils.remove( projectArtifact.getBaseVersion(), 300 "-" + VersionUtil.SNAPSHOT ) ).append( '-' ).append( 301 timeStamp ).append( '-' ).append( Integer.toString( buildNumber ) ).append( 302 ".pom" ).toString(); 303 File timeStampFile = new File( file.getParent(), timeStampFileName ); 304 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.getPath() ); 305 if ( timeStampFile.exists() ) 306 { 307 return managedRepository; 308 } 309 } 310 catch ( XMLException e ) 311 { 312 log.warn( "skip fail to find timestamped snapshot pom: {}", e.getMessage() ); 313 } 314 } 315 } 316 } 317 return null; 318 } 319 320 }