]> source.dussan.org Git - archiva.git/blob
30822d2446e430d702f2674ca9361580226e1a76
[archiva.git] /
1 package org.apache.archiva.dependency.tree.maven2;
2 /*
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
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
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
18  * under the License.
19  */
20
21
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;
74
75 import javax.annotation.PostConstruct;
76 import javax.inject.Inject;
77 import javax.inject.Named;
78 import java.io.File;
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;
85 import java.util.Map;
86
87 /**
88  * @author Olivier Lamy
89  */
90 @Service( "dependencyTreeBuilder#maven3" )
91 public class Maven3DependencyTreeBuilder
92 {
93     private Logger log = LoggerFactory.getLogger( getClass() );
94
95     @Inject
96     private PlexusSisuBridge plexusSisuBridge;
97
98     @Inject
99     @Named( value = "repositoryPathTranslator#maven2" )
100     private RepositoryPathTranslator pathTranslator;
101
102     @Inject
103     private WagonFactory wagonFactory;
104
105     @Inject
106     private ManagedRepositoryAdmin managedRepositoryAdmin;
107
108     @Inject
109     private ProxyConnectorAdmin proxyConnectorAdmin;
110
111     @Inject
112     private NetworkProxyAdmin networkProxyAdmin;
113
114     @Inject
115     private RemoteRepositoryAdmin remoteRepositoryAdmin;
116
117     private ArtifactFactory factory;
118
119     private ModelBuilder builder;
120
121
122     private RepositorySystem repoSystem;
123
124     @PostConstruct
125     public void initialize()
126         throws PlexusSisuBridgeException
127     {
128         factory = plexusSisuBridge.lookup( ArtifactFactory.class, "default" );
129
130         repoSystem = plexusSisuBridge.lookup( RepositorySystem.class );
131         DefaultModelBuilderFactory defaultModelBuilderFactory = new DefaultModelBuilderFactory();
132         builder = defaultModelBuilderFactory.newInstance();
133     }
134
135     public DependencyResolutionResult buildDependencyTree( List<String> repositoryIds, String groupId,
136                                                            String artifactId, String version )
137         throws Exception
138     {
139         Artifact projectArtifact = factory.createProjectArtifact( groupId, artifactId, version );
140         ManagedRepository repository = null;
141         try
142         {
143             repository = findArtifactInRepositories( repositoryIds, projectArtifact );
144         }
145         catch ( RepositoryAdminException e )
146         {
147             // FIXME better exception
148             throw new Exception( "Cannot build project dependency tree " + e.getMessage(), e );
149         }
150
151         if ( repository == null )
152         {
153             // metadata could not be resolved
154             return new DefaultDependencyResolutionResult();
155         }
156
157         // MRM-1411
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>();
162
163         Map<String, List<ProxyConnector>> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap();
164         List<ProxyConnector> proxyConnectors = proxyConnectorsMap.get( repository.getId() );
165         if ( proxyConnectors != null )
166         {
167             for ( ProxyConnector proxyConnector : proxyConnectors )
168             {
169                 remoteRepositories.add( remoteRepositoryAdmin.getRemoteRepository( proxyConnector.getTargetRepoId() ) );
170
171                 NetworkProxy networkProxyConfig = networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() );
172
173                 if ( networkProxyConfig != null )
174                 {
175                     // key/value: remote repo ID/proxy info
176                     networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig );
177                 }
178             }
179         }
180
181         Model model = buildProject(
182             new RepositoryModelResolver( repository, pathTranslator, wagonFactory, remoteRepositories, networkProxies,
183                                          repository ), groupId, artifactId, version );
184
185         MavenProject project = new MavenProject( model );
186
187         DefaultRepositorySystemSession repositorySystemSession = new DefaultRepositorySystemSession();
188
189         // FIXME take care of relative path for getLocation
190         repositorySystemSession.setLocalRepositoryManager(
191             new SimpleLocalRepositoryManager( new File( repository.getLocation() ) ) );
192
193         DefaultProjectBuildingRequest projectBuildingRequest = new DefaultProjectBuildingRequest();
194
195         project.setProjectBuildingRequest( projectBuildingRequest );
196
197         projectBuildingRequest.setRepositorySession( repositorySystemSession );
198
199         DefaultDependencyResolutionRequest request =
200             new DefaultDependencyResolutionRequest( project, projectBuildingRequest.getRepositorySession() );
201
202         //DependencyFilter dependencyFilter
203         //request.setResolutionFilter(  )
204
205         //DependencyResolutionResult result = projectDependenciesResolver.resolve( request );
206
207         //DependencyNode dependencyNode = buildDependencyNode( null, result.getDependencyGraph(), projectArtifact, null );
208         /*DependencyNode dependencyNode = dependencyGraphBuilder.buildDependencyGraph( project, new ArtifactFilter()
209         {
210             public boolean include( Artifact artifact )
211             {
212                 return true;
213             }
214         } );*/
215
216         DependencyResolutionResult resolutionResult = resolve( request );
217
218         log.debug( "dependency graph build" );
219
220         return resolutionResult;
221     }
222
223     private DependencyResolutionResult resolve( DefaultDependencyResolutionRequest request )
224         throws DependencyResolutionException
225     {
226
227         RequestTrace trace = DefaultRequestTrace.newChild( null, request );
228
229         DefaultDependencyResolutionResult result = new DefaultDependencyResolutionResult();
230
231         MavenProject project = request.getMavenProject();
232         RepositorySystemSession session = request.getRepositorySession();
233         DependencyFilter filter = request.getResolutionFilter();
234
235         ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
236
237         CollectRequest collect = new CollectRequest();
238         collect.setRequestContext( "project" );
239         collect.setRepositories( project.getRemoteProjectRepositories() );
240
241         if ( project.getDependencyArtifacts() == null )
242         {
243             for ( org.apache.maven.model.Dependency dependency : project.getDependencies() )
244             {
245                 if ( StringUtils.isEmpty( dependency.getGroupId() ) || StringUtils.isEmpty( dependency.getArtifactId() )
246                     || StringUtils.isEmpty( dependency.getVersion() ) )
247                 {
248                     // guard against case where best-effort resolution for invalid models is requested
249                     continue;
250                 }
251                 collect.addDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
252             }
253         }
254         else
255         {
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() )
259             {
260                 String classifier = dependency.getClassifier();
261                 if ( classifier == null )
262                 {
263                     ArtifactType type = stereotypes.get( dependency.getType() );
264                     if ( type != null )
265                     {
266                         classifier = type.getClassifier();
267                     }
268                 }
269                 String key = ArtifacIdUtils.toVersionlessId( dependency.getGroupId(), dependency.getArtifactId(),
270                                                              dependency.getType(), classifier );
271                 dependencies.put( key, dependency );
272             }
273             for ( Artifact artifact : project.getDependencyArtifacts() )
274             {
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 )
280                 {
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 );
285                 }
286                 collect.addDependency( dep );
287             }
288         }
289
290         DependencyManagement depMngt = project.getDependencyManagement();
291         if ( depMngt != null )
292         {
293             for ( org.apache.maven.model.Dependency dependency : depMngt.getDependencies() )
294             {
295                 collect.addManagedDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
296             }
297         }
298
299         DependencyRequest depRequest = new DependencyRequest( collect, filter );
300         depRequest.setTrace( trace );
301
302         org.sonatype.aether.graph.DependencyNode node;
303         try
304         {
305             collect.setTrace( DefaultRequestTrace.newChild( trace, depRequest ) );
306             node = repoSystem.collectDependencies( session, collect ).getRoot();
307             result.setDependencyGraph( node );
308         }
309         catch ( DependencyCollectionException e )
310         {
311             result.setDependencyGraph( e.getResult().getRoot() );
312             result.setCollectionErrors( e.getResult().getExceptions() );
313
314             throw new DependencyResolutionException( result,
315                                                      "Could not resolve dependencies for project " + project.getId()
316                                                          + ": " + e.getMessage(), e );
317         }
318
319         depRequest.setRoot( node );
320
321         return result;
322     }
323
324     private String getVersionSelectedFromRange( VersionConstraint constraint )
325     {
326         if ( ( constraint == null ) || ( constraint.getVersion() != null ) )
327         {
328             return null;
329         }
330
331         StringBuilder sb = new StringBuilder();
332         for ( org.sonatype.aether.version.VersionRange range : constraint.getRanges() )
333         {
334             if ( sb.length() > 0 )
335             {
336                 sb.append( ',' );
337             }
338             sb.append( range );
339         }
340
341         return sb.toString();
342     }
343
344     private Artifact getDependencyArtifact( Dependency dep )
345     {
346         org.sonatype.aether.artifact.Artifact artifact = dep.getArtifact();
347
348         return factory.createDependencyArtifact( artifact.getGroupId(), artifact.getArtifactId(),
349                                                  VersionRange.createFromVersion( artifact.getVersion() ),
350                                                  artifact.getExtension(), artifact.getClassifier(), dep.getScope(),
351                                                  dep.isOptional() );
352     }
353
354     private Model buildProject( RepositoryModelResolver modelResolver, String groupId, String artifactId,
355                                 String version )
356         throws ModelBuildingException, UnresolvableModelException
357     {
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() );
365
366         return builder.build( req ).getEffectiveModel();
367     }
368
369     private ManagedRepository findArtifactInRepositories( List<String> repositoryIds, Artifact projectArtifact )
370         throws RepositoryAdminException
371     {
372         for ( String repoId : repositoryIds )
373         {
374             ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
375
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()
380                                                    + ".pom" );
381
382             if ( file.exists() )
383             {
384                 return managedRepository;
385             }
386         }
387         return null;
388     }
389
390     public static class DefaultDependencyResolutionResult
391         implements DependencyResolutionResult
392     {
393
394         private org.sonatype.aether.graph.DependencyNode root;
395
396         private List<Dependency> dependencies = new ArrayList<Dependency>();
397
398         private List<Dependency> resolvedDependencies = new ArrayList<Dependency>();
399
400         private List<Dependency> unresolvedDependencies = new ArrayList<Dependency>();
401
402         private List<Exception> collectionErrors = new ArrayList<Exception>();
403
404         private Map<Dependency, List<Exception>> resolutionErrors = new IdentityHashMap<Dependency, List<Exception>>();
405
406         public org.sonatype.aether.graph.DependencyNode getDependencyGraph()
407         {
408             return root;
409         }
410
411         public void setDependencyGraph( org.sonatype.aether.graph.DependencyNode root )
412         {
413             this.root = root;
414         }
415
416         public List<Dependency> getDependencies()
417         {
418             return dependencies;
419         }
420
421         public List<Dependency> getResolvedDependencies()
422         {
423             return resolvedDependencies;
424         }
425
426         public void addResolvedDependency( Dependency dependency )
427         {
428             dependencies.add( dependency );
429             resolvedDependencies.add( dependency );
430         }
431
432         public List<Dependency> getUnresolvedDependencies()
433         {
434             return unresolvedDependencies;
435         }
436
437         public List<Exception> getCollectionErrors()
438         {
439             return collectionErrors;
440         }
441
442         public void setCollectionErrors( List<Exception> exceptions )
443         {
444             if ( exceptions != null )
445             {
446                 this.collectionErrors = exceptions;
447             }
448             else
449             {
450                 this.collectionErrors = new ArrayList<Exception>();
451             }
452         }
453
454         public List<Exception> getResolutionErrors( Dependency dependency )
455         {
456             List<Exception> errors = resolutionErrors.get( dependency );
457             return ( errors != null ) ? errors : Collections.<Exception>emptyList();
458         }
459
460         public void setResolutionErrors( Dependency dependency, List<Exception> errors )
461         {
462             dependencies.add( dependency );
463             unresolvedDependencies.add( dependency );
464             resolutionErrors.put( dependency, errors );
465         }
466
467     }
468 }