View Javadoc
1   package org.apache.maven.shared.dependency.graph.internal;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Map;
26  
27  import javax.inject.Inject;
28  import javax.inject.Named;
29  
30  import org.apache.maven.RepositoryUtils;
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.maven.artifact.repository.ArtifactRepository;
33  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
34  import org.apache.maven.model.Dependency;
35  import org.apache.maven.project.MavenProject;
36  import org.apache.maven.project.ProjectBuildingRequest;
37  import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilder;
38  import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilderException;
39  import org.apache.maven.shared.dependency.graph.DependencyCollectorRequest;
40  import org.apache.maven.shared.dependency.graph.DependencyNode;
41  import org.eclipse.aether.DefaultRepositorySystemSession;
42  import org.eclipse.aether.RepositorySystem;
43  import org.eclipse.aether.RepositorySystemSession;
44  import org.eclipse.aether.artifact.ArtifactTypeRegistry;
45  import org.eclipse.aether.collection.CollectRequest;
46  import org.eclipse.aether.collection.CollectResult;
47  import org.eclipse.aether.collection.DependencyCollectionException;
48  import org.eclipse.aether.graph.DependencyVisitor;
49  import org.eclipse.aether.graph.Exclusion;
50  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
51  import org.eclipse.aether.util.graph.transformer.ConflictResolver;
52  import org.eclipse.aether.util.graph.visitor.TreeDependencyVisitor;
53  import org.eclipse.aether.version.VersionConstraint;
54  import org.slf4j.Logger;
55  import org.slf4j.LoggerFactory;
56  
57  /**
58   * Project dependency raw dependency collector API, abstracting Maven 3.1+'s Aether implementation.
59   * 
60   * @author Gabriel Belingueres
61   * @since 3.1.0
62   */
63  @Named
64  public class DefaultDependencyCollectorBuilder
65      implements DependencyCollectorBuilder
66  {
67      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultDependencyCollectorBuilder.class );
68  
69      private final RepositorySystem repositorySystem;
70  
71      @Inject
72      public DefaultDependencyCollectorBuilder( RepositorySystem repositorySystem )
73      {
74          this.repositorySystem = repositorySystem;
75      }
76  
77      @Override
78      public DependencyNode collectDependencyGraph( DependencyCollectorRequest dependencyCollectorRequest )
79          throws DependencyCollectorBuilderException
80      {
81          DefaultRepositorySystemSession session = null;
82          try
83          {
84              ProjectBuildingRequest buildingRequest = dependencyCollectorRequest.getBuildingRequest();
85              MavenProject project = buildingRequest.getProject();
86  
87              Artifact projectArtifact = project.getArtifact();
88              List<ArtifactRepository> remoteArtifactRepositories = project.getRemoteArtifactRepositories();
89  
90              RepositorySystemSession repositorySession = buildingRequest.getRepositorySession();
91  
92              session = new DefaultRepositorySystemSession( repositorySession );
93  
94              session.setDependencyGraphTransformer( dependencyCollectorRequest.getDependencyGraphTransformer() );
95  
96              session.setDependencySelector( dependencyCollectorRequest.getDependencySelector() );
97  
98              for ( Map.Entry<String, Object> entry : dependencyCollectorRequest.getConfigProperties().entrySet() )
99              {
100                 session.setConfigProperty( entry.getKey(), entry.getValue() );
101             }
102 
103             org.eclipse.aether.artifact.Artifact aetherArtifact = RepositoryUtils.toArtifact( projectArtifact );
104 
105             List<org.eclipse.aether.repository.RemoteRepository> aetherRepos =
106                 RepositoryUtils.toRepos( remoteArtifactRepositories );
107 
108             CollectRequest collectRequest = new CollectRequest();
109             collectRequest.setRootArtifact( aetherArtifact );
110             collectRequest.setRepositories( aetherRepos );
111 
112             org.eclipse.aether.artifact.ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
113             collectDependencyList( collectRequest, project, stereotypes );
114             collectManagedDependencyList( collectRequest, project, stereotypes );
115 
116             CollectResult collectResult = repositorySystem.collectDependencies( session, collectRequest );
117 
118             org.eclipse.aether.graph.DependencyNode rootNode = collectResult.getRoot();
119 
120             if ( LOGGER.isDebugEnabled() )
121             {
122                 logTree( rootNode );
123             }
124 
125             return buildDependencyNode( null, rootNode, projectArtifact, dependencyCollectorRequest.getFilter() );
126         }
127         catch ( DependencyCollectionException e )
128         {
129             throw new DependencyCollectorBuilderException( "Could not collect dependencies: " + e.getResult(), e );
130         }
131         finally
132         {
133             if ( session != null )
134             {
135                 session.setReadOnly();
136             }
137         }
138     }
139 
140     private void logTree( org.eclipse.aether.graph.DependencyNode rootNode )
141     {
142         // print the node tree with its associated data Map
143         rootNode.accept( new TreeDependencyVisitor( new DependencyVisitor()
144         {
145             String indent = "";
146 
147             @Override
148             public boolean visitEnter( org.eclipse.aether.graph.DependencyNode dependencyNode )
149             {
150                 LOGGER.debug( "{}Aether node: {} data map: {}", indent, dependencyNode, dependencyNode.getData() );
151                 indent += "    ";
152                 return true;
153             }
154 
155             @Override
156             public boolean visitLeave( org.eclipse.aether.graph.DependencyNode dependencyNode )
157             {
158                 indent = indent.substring( 0, indent.length() - 4 );
159                 return true;
160             }
161         } ) );
162     }
163 
164     private void collectManagedDependencyList( CollectRequest collectRequest, MavenProject project,
165                                                ArtifactTypeRegistry stereotypes )
166     {
167         if ( project.getDependencyManagement() != null )
168         {
169             for ( Dependency dependency : project.getDependencyManagement().getDependencies() )
170             {
171                 org.eclipse.aether.graph.Dependency aetherDep = RepositoryUtils.toDependency( dependency, stereotypes );
172                 collectRequest.addManagedDependency( aetherDep );
173             }
174         }
175     }
176 
177     private void collectDependencyList( CollectRequest collectRequest, MavenProject project,
178                                         org.eclipse.aether.artifact.ArtifactTypeRegistry stereotypes )
179     {
180         for ( Dependency dependency : project.getDependencies() )
181         {
182             org.eclipse.aether.graph.Dependency aetherDep = RepositoryUtils.toDependency( dependency, stereotypes );
183             collectRequest.addDependency( aetherDep );
184         }
185     }
186 
187     private Artifact getDependencyArtifact( org.eclipse.aether.graph.Dependency dep )
188     {
189         org.eclipse.aether.artifact.Artifact artifact = dep.getArtifact();
190 
191         Artifact mavenArtifact = RepositoryUtils.toArtifact( artifact );
192         mavenArtifact.setScope( dep.getScope() );
193         mavenArtifact.setOptional( dep.isOptional() );
194 
195         return mavenArtifact;
196     }
197 
198     private DependencyNode buildDependencyNode( DependencyNode parent, org.eclipse.aether.graph.DependencyNode node,
199                                                 Artifact artifact, ArtifactFilter filter )
200     {
201         String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node );
202         String premanagedScope = DependencyManagerUtils.getPremanagedScope( node );
203 
204         Boolean optional = null;
205         if ( node.getDependency() != null )
206         {
207             optional = node.getDependency().isOptional();
208         }
209         
210         List<org.apache.maven.model.Exclusion> exclusions = null;
211         if ( node.getDependency() != null )
212         {
213             exclusions = new ArrayList<>( node.getDependency().getExclusions().size() );
214             for ( Exclusion exclusion : node.getDependency().getExclusions() )
215             {
216                 org.apache.maven.model.Exclusion modelExclusion = new org.apache.maven.model.Exclusion();
217                 modelExclusion.setGroupId( exclusion.getGroupId() );
218                 modelExclusion.setArtifactId( exclusion.getArtifactId() );
219                 exclusions.add( modelExclusion );
220             }
221         }
222 
223         org.eclipse.aether.graph.DependencyNode winner =
224             (org.eclipse.aether.graph.DependencyNode) node.getData().get( ConflictResolver.NODE_DATA_WINNER );
225         String winnerVersion = null;
226         String ignoredScope = null;
227         if ( winner != null )
228         {
229             winnerVersion = winner.getArtifact().getBaseVersion();
230         }
231         else
232         {
233             ignoredScope = (String) node.getData().get( VerboseJavaScopeSelector.REDUCED_SCOPE );
234         }
235         
236         ConflictData data = new ConflictData( winnerVersion, ignoredScope );
237         
238         VerboseDependencyNode current =
239             new VerboseDependencyNode( parent, artifact, premanagedVersion, premanagedScope,
240                                        getVersionSelectedFromRange( node.getVersionConstraint() ), optional,
241                                        exclusions, data );
242 
243         List<DependencyNode> nodes = new ArrayList<>( node.getChildren().size() );
244         for ( org.eclipse.aether.graph.DependencyNode child : node.getChildren() )
245         {
246             Artifact childArtifact = getDependencyArtifact( child.getDependency() );
247 
248             if ( ( filter == null ) || filter.include( childArtifact ) )
249             {
250                 nodes.add( buildDependencyNode( current, child, childArtifact, filter ) );
251             }
252         }
253 
254         current.setChildren( Collections.unmodifiableList( nodes ) );
255 
256         return current;
257     }
258 
259     private String getVersionSelectedFromRange( VersionConstraint constraint )
260     {
261         if ( ( constraint == null ) || ( constraint.getVersion() != null ) )
262         {
263             return null;
264         }
265 
266         return constraint.getRange().toString();
267     }
268 }