1 package org.apache.archiva.dependency.tree.maven2;
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
22 import org.apache.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.admin.model.beans.ManagedRepository;
24 import org.apache.archiva.admin.model.beans.NetworkProxy;
25 import org.apache.archiva.admin.model.beans.ProxyConnector;
26 import org.apache.archiva.admin.model.beans.RemoteRepository;
27 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
28 import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin;
29 import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin;
30 import org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin;
31 import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
32 import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException;
33 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
34 import org.apache.archiva.metadata.repository.storage.maven2.RepositoryModelResolver;
35 import org.apache.archiva.proxy.common.WagonFactory;
36 import org.apache.maven.RepositoryUtils;
37 import org.apache.maven.artifact.Artifact;
38 import org.apache.maven.artifact.factory.ArtifactFactory;
39 import org.apache.maven.artifact.versioning.VersionRange;
40 import org.apache.maven.model.DependencyManagement;
41 import org.apache.maven.model.Exclusion;
42 import org.apache.maven.model.Model;
43 import org.apache.maven.model.building.DefaultModelBuilderFactory;
44 import org.apache.maven.model.building.DefaultModelBuildingRequest;
45 import org.apache.maven.model.building.ModelBuilder;
46 import org.apache.maven.model.building.ModelBuildingException;
47 import org.apache.maven.model.building.ModelBuildingRequest;
48 import org.apache.maven.model.resolution.UnresolvableModelException;
49 import org.apache.maven.project.DefaultDependencyResolutionRequest;
50 import org.apache.maven.project.DefaultProjectBuildingRequest;
51 import org.apache.maven.project.DependencyResolutionException;
52 import org.apache.maven.project.DependencyResolutionResult;
53 import org.apache.maven.project.MavenProject;
54 import org.codehaus.plexus.util.StringUtils;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.sonatype.aether.RepositorySystem;
58 import org.sonatype.aether.RepositorySystemSession;
59 import org.sonatype.aether.RequestTrace;
60 import org.sonatype.aether.artifact.ArtifactType;
61 import org.sonatype.aether.artifact.ArtifactTypeRegistry;
62 import org.sonatype.aether.collection.CollectRequest;
63 import org.sonatype.aether.collection.DependencyCollectionException;
64 import org.sonatype.aether.graph.Dependency;
65 import org.sonatype.aether.graph.DependencyFilter;
66 import org.sonatype.aether.impl.internal.SimpleLocalRepositoryManager;
67 import org.sonatype.aether.resolution.DependencyRequest;
68 import org.sonatype.aether.util.DefaultRepositorySystemSession;
69 import org.sonatype.aether.util.DefaultRequestTrace;
70 import org.sonatype.aether.util.artifact.ArtifacIdUtils;
71 import org.sonatype.aether.util.artifact.JavaScopes;
72 import org.sonatype.aether.version.VersionConstraint;
73 import org.springframework.stereotype.Service;
75 import javax.annotation.PostConstruct;
76 import javax.inject.Inject;
77 import javax.inject.Named;
79 import java.util.ArrayList;
80 import java.util.Collection;
81 import java.util.Collections;
82 import java.util.HashMap;
83 import java.util.IdentityHashMap;
84 import java.util.List;
88 * @author Olivier Lamy
90 @Service( "dependencyTreeBuilder#maven3" )
91 public class Maven3DependencyTreeBuilder
93 private Logger log = LoggerFactory.getLogger( getClass() );
96 private PlexusSisuBridge plexusSisuBridge;
99 @Named( value = "repositoryPathTranslator#maven2" )
100 private RepositoryPathTranslator pathTranslator;
103 private WagonFactory wagonFactory;
106 private ManagedRepositoryAdmin managedRepositoryAdmin;
109 private ProxyConnectorAdmin proxyConnectorAdmin;
112 private NetworkProxyAdmin networkProxyAdmin;
115 private RemoteRepositoryAdmin remoteRepositoryAdmin;
117 private ArtifactFactory factory;
119 private ModelBuilder builder;
122 private RepositorySystem repoSystem;
125 public void initialize()
126 throws PlexusSisuBridgeException
128 factory = plexusSisuBridge.lookup( ArtifactFactory.class, "default" );
130 repoSystem = plexusSisuBridge.lookup( RepositorySystem.class );
131 DefaultModelBuilderFactory defaultModelBuilderFactory = new DefaultModelBuilderFactory();
132 builder = defaultModelBuilderFactory.newInstance();
135 public DependencyResolutionResult buildDependencyTree( List<String> repositoryIds, String groupId,
136 String artifactId, String version )
139 Artifact projectArtifact = factory.createProjectArtifact( groupId, artifactId, version );
140 ManagedRepository repository = null;
143 repository = findArtifactInRepositories( repositoryIds, projectArtifact );
145 catch ( RepositoryAdminException e )
147 // FIXME better exception
148 throw new Exception( "Cannot build project dependency tree " + e.getMessage(), e );
151 if ( repository == null )
153 // metadata could not be resolved
154 return new DefaultDependencyResolutionResult();
158 // TODO: this is a workaround for a lack of proxy capability in the resolvers - replace when it can all be
159 // handled there. It doesn't cache anything locally!
160 List<RemoteRepository> remoteRepositories = new ArrayList<RemoteRepository>();
161 Map<String, NetworkProxy> networkProxies = new HashMap<String, NetworkProxy>();
163 Map<String, List<ProxyConnector>> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap();
164 List<ProxyConnector> proxyConnectors = proxyConnectorsMap.get( repository.getId() );
165 if ( proxyConnectors != null )
167 for ( ProxyConnector proxyConnector : proxyConnectors )
169 remoteRepositories.add( remoteRepositoryAdmin.getRemoteRepository( proxyConnector.getTargetRepoId() ) );
171 NetworkProxy networkProxyConfig = networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() );
173 if ( networkProxyConfig != null )
175 // key/value: remote repo ID/proxy info
176 networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig );
181 Model model = buildProject(
182 new RepositoryModelResolver( repository, pathTranslator, wagonFactory, remoteRepositories, networkProxies,
183 repository ), groupId, artifactId, version );
185 MavenProject project = new MavenProject( model );
187 DefaultRepositorySystemSession repositorySystemSession = new DefaultRepositorySystemSession();
189 // FIXME take care of relative path for getLocation
190 repositorySystemSession.setLocalRepositoryManager(
191 new SimpleLocalRepositoryManager( new File( repository.getLocation() ) ) );
193 DefaultProjectBuildingRequest projectBuildingRequest = new DefaultProjectBuildingRequest();
195 project.setProjectBuildingRequest( projectBuildingRequest );
197 projectBuildingRequest.setRepositorySession( repositorySystemSession );
199 DefaultDependencyResolutionRequest request =
200 new DefaultDependencyResolutionRequest( project, projectBuildingRequest.getRepositorySession() );
202 //DependencyFilter dependencyFilter
203 //request.setResolutionFilter( )
205 //DependencyResolutionResult result = projectDependenciesResolver.resolve( request );
207 //DependencyNode dependencyNode = buildDependencyNode( null, result.getDependencyGraph(), projectArtifact, null );
208 /*DependencyNode dependencyNode = dependencyGraphBuilder.buildDependencyGraph( project, new ArtifactFilter()
210 public boolean include( Artifact artifact )
216 DependencyResolutionResult resolutionResult = resolve( request );
218 log.debug( "dependency graph build" );
220 return resolutionResult;
223 private DependencyResolutionResult resolve( DefaultDependencyResolutionRequest request )
224 throws DependencyResolutionException
227 RequestTrace trace = DefaultRequestTrace.newChild( null, request );
229 DefaultDependencyResolutionResult result = new DefaultDependencyResolutionResult();
231 MavenProject project = request.getMavenProject();
232 RepositorySystemSession session = request.getRepositorySession();
233 DependencyFilter filter = request.getResolutionFilter();
235 ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
237 CollectRequest collect = new CollectRequest();
238 collect.setRequestContext( "project" );
239 collect.setRepositories( project.getRemoteProjectRepositories() );
241 if ( project.getDependencyArtifacts() == null )
243 for ( org.apache.maven.model.Dependency dependency : project.getDependencies() )
245 if ( StringUtils.isEmpty( dependency.getGroupId() ) || StringUtils.isEmpty( dependency.getArtifactId() )
246 || StringUtils.isEmpty( dependency.getVersion() ) )
248 // guard against case where best-effort resolution for invalid models is requested
251 collect.addDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
256 Map<String, org.apache.maven.model.Dependency> dependencies =
257 new HashMap<String, org.apache.maven.model.Dependency>();
258 for ( org.apache.maven.model.Dependency dependency : project.getDependencies() )
260 String classifier = dependency.getClassifier();
261 if ( classifier == null )
263 ArtifactType type = stereotypes.get( dependency.getType() );
266 classifier = type.getClassifier();
269 String key = ArtifacIdUtils.toVersionlessId( dependency.getGroupId(), dependency.getArtifactId(),
270 dependency.getType(), classifier );
271 dependencies.put( key, dependency );
273 for ( Artifact artifact : project.getDependencyArtifacts() )
275 String key = artifact.getDependencyConflictId();
276 org.apache.maven.model.Dependency dependency = dependencies.get( key );
277 Collection<Exclusion> exclusions = dependency != null ? dependency.getExclusions() : null;
278 org.sonatype.aether.graph.Dependency dep = RepositoryUtils.toDependency( artifact, exclusions );
279 if ( !JavaScopes.SYSTEM.equals( dep.getScope() ) && dep.getArtifact().getFile() != null )
281 // enable re-resolution
282 org.sonatype.aether.artifact.Artifact art = dep.getArtifact();
283 art = art.setFile( null ).setVersion( art.getBaseVersion() );
284 dep = dep.setArtifact( art );
286 collect.addDependency( dep );
290 DependencyManagement depMngt = project.getDependencyManagement();
291 if ( depMngt != null )
293 for ( org.apache.maven.model.Dependency dependency : depMngt.getDependencies() )
295 collect.addManagedDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
299 DependencyRequest depRequest = new DependencyRequest( collect, filter );
300 depRequest.setTrace( trace );
302 org.sonatype.aether.graph.DependencyNode node;
305 collect.setTrace( DefaultRequestTrace.newChild( trace, depRequest ) );
306 node = repoSystem.collectDependencies( session, collect ).getRoot();
307 result.setDependencyGraph( node );
309 catch ( DependencyCollectionException e )
311 result.setDependencyGraph( e.getResult().getRoot() );
312 result.setCollectionErrors( e.getResult().getExceptions() );
314 throw new DependencyResolutionException( result,
315 "Could not resolve dependencies for project " + project.getId()
316 + ": " + e.getMessage(), e );
319 depRequest.setRoot( node );
324 private String getVersionSelectedFromRange( VersionConstraint constraint )
326 if ( ( constraint == null ) || ( constraint.getVersion() != null ) )
331 StringBuilder sb = new StringBuilder();
332 for ( org.sonatype.aether.version.VersionRange range : constraint.getRanges() )
334 if ( sb.length() > 0 )
341 return sb.toString();
344 private Artifact getDependencyArtifact( Dependency dep )
346 org.sonatype.aether.artifact.Artifact artifact = dep.getArtifact();
348 return factory.createDependencyArtifact( artifact.getGroupId(), artifact.getArtifactId(),
349 VersionRange.createFromVersion( artifact.getVersion() ),
350 artifact.getExtension(), artifact.getClassifier(), dep.getScope(),
354 private Model buildProject( RepositoryModelResolver modelResolver, String groupId, String artifactId,
356 throws ModelBuildingException, UnresolvableModelException
358 DefaultModelBuildingRequest req = new DefaultModelBuildingRequest();
359 req.setProcessPlugins( false );
360 req.setModelSource( modelResolver.resolveModel( groupId, artifactId, version ) );
361 req.setModelResolver( modelResolver );
362 req.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
363 //MRM-1607. olamy this will resolve jdk profiles on the current running archiva jvm
364 req.setSystemProperties( System.getProperties() );
366 return builder.build( req ).getEffectiveModel();
369 private ManagedRepository findArtifactInRepositories( List<String> repositoryIds, Artifact projectArtifact )
370 throws RepositoryAdminException
372 for ( String repoId : repositoryIds )
374 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
376 File repoDir = new File( managedRepository.getLocation() );
377 File file = pathTranslator.toFile( repoDir, projectArtifact.getGroupId(), projectArtifact.getArtifactId(),
378 projectArtifact.getBaseVersion(),
379 projectArtifact.getArtifactId() + "-" + projectArtifact.getVersion()
384 return managedRepository;
390 public static class DefaultDependencyResolutionResult
391 implements DependencyResolutionResult
394 private org.sonatype.aether.graph.DependencyNode root;
396 private List<Dependency> dependencies = new ArrayList<Dependency>();
398 private List<Dependency> resolvedDependencies = new ArrayList<Dependency>();
400 private List<Dependency> unresolvedDependencies = new ArrayList<Dependency>();
402 private List<Exception> collectionErrors = new ArrayList<Exception>();
404 private Map<Dependency, List<Exception>> resolutionErrors = new IdentityHashMap<Dependency, List<Exception>>();
406 public org.sonatype.aether.graph.DependencyNode getDependencyGraph()
411 public void setDependencyGraph( org.sonatype.aether.graph.DependencyNode root )
416 public List<Dependency> getDependencies()
421 public List<Dependency> getResolvedDependencies()
423 return resolvedDependencies;
426 public void addResolvedDependency( Dependency dependency )
428 dependencies.add( dependency );
429 resolvedDependencies.add( dependency );
432 public List<Dependency> getUnresolvedDependencies()
434 return unresolvedDependencies;
437 public List<Exception> getCollectionErrors()
439 return collectionErrors;
442 public void setCollectionErrors( List<Exception> exceptions )
444 if ( exceptions != null )
446 this.collectionErrors = exceptions;
450 this.collectionErrors = new ArrayList<Exception>();
454 public List<Exception> getResolutionErrors( Dependency dependency )
456 List<Exception> errors = resolutionErrors.get( dependency );
457 return ( errors != null ) ? errors : Collections.<Exception>emptyList();
460 public void setResolutionErrors( Dependency dependency, List<Exception> errors )
462 dependencies.add( dependency );
463 unresolvedDependencies.add( dependency );
464 resolutionErrors.put( dependency, errors );