1 package org.apache.maven.shared.dependency.graph.internal;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25
26 import org.apache.maven.RepositoryUtils;
27 import org.apache.maven.artifact.Artifact;
28 import org.apache.maven.artifact.repository.ArtifactRepository;
29 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
30 import org.apache.maven.model.Dependency;
31 import org.apache.maven.project.MavenProject;
32 import org.apache.maven.project.ProjectBuildingRequest;
33 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilder;
34 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilderException;
35 import org.apache.maven.shared.dependency.graph.DependencyNode;
36 import org.apache.maven.shared.dependency.graph.internal.maven30.ConflictResolver;
37 import org.apache.maven.shared.dependency.graph.internal.maven30.JavaScopeDeriver;
38 import org.apache.maven.shared.dependency.graph.internal.maven30.Maven3DirectScopeDependencySelector;
39 import org.apache.maven.shared.dependency.graph.internal.maven30.NearestVersionSelector;
40 import org.apache.maven.shared.dependency.graph.internal.maven30.SimpleOptionalitySelector;
41 import org.apache.maven.shared.dependency.graph.internal.maven30.VerboseJavaScopeSelector;
42 import org.codehaus.plexus.component.annotations.Component;
43 import org.codehaus.plexus.component.annotations.Requirement;
44 import org.codehaus.plexus.logging.AbstractLogEnabled;
45 import org.sonatype.aether.RepositorySystem;
46 import org.sonatype.aether.RepositorySystemSession;
47 import org.sonatype.aether.artifact.ArtifactTypeRegistry;
48 import org.sonatype.aether.collection.CollectRequest;
49 import org.sonatype.aether.collection.CollectResult;
50 import org.sonatype.aether.collection.DependencyCollectionException;
51 import org.sonatype.aether.collection.DependencyGraphTransformer;
52 import org.sonatype.aether.collection.DependencySelector;
53 import org.sonatype.aether.graph.DependencyVisitor;
54 import org.sonatype.aether.graph.Exclusion;
55 import org.sonatype.aether.util.DefaultRepositorySystemSession;
56 import org.sonatype.aether.util.artifact.JavaScopes;
57 import org.sonatype.aether.util.graph.TreeDependencyVisitor;
58 import org.sonatype.aether.util.graph.selector.AndDependencySelector;
59 import org.sonatype.aether.util.graph.selector.ExclusionDependencySelector;
60 import org.sonatype.aether.util.graph.selector.OptionalDependencySelector;
61 import org.sonatype.aether.version.VersionConstraint;
62
63
64
65
66
67
68
69 @Component( role = DependencyCollectorBuilder.class, hint = "maven3" )
70 public class Maven3DependencyCollectorBuilder
71 extends AbstractLogEnabled
72 implements DependencyCollectorBuilder
73 {
74 @Requirement
75 private RepositorySystem repositorySystem;
76
77 private final ExceptionHandler<DependencyCollectorBuilderException> exceptionHandler;
78
79 public Maven3DependencyCollectorBuilder()
80 {
81 this.exceptionHandler = new ExceptionHandler<DependencyCollectorBuilderException>()
82 {
83 @Override
84 public DependencyCollectorBuilderException create( String message, Exception exception )
85 {
86 return new DependencyCollectorBuilderException( message, exception );
87 }
88 };
89 }
90
91 @Override
92 public DependencyNode collectDependencyGraph( ProjectBuildingRequest buildingRequest, ArtifactFilter filter )
93 throws DependencyCollectorBuilderException
94 {
95 try
96 {
97 MavenProject project = buildingRequest.getProject();
98
99 Artifact projectArtifact = project.getArtifact();
100 List<ArtifactRepository> remoteArtifactRepositories = project.getRemoteArtifactRepositories();
101
102
103
104
105 RepositorySystemSession repositorySystemSession = buildingRequest.getRepositorySession();
106
107 DefaultRepositorySystemSession session = new DefaultRepositorySystemSession( repositorySystemSession );
108
109 DependencyGraphTransformer transformer =
110 new ConflictResolver( new NearestVersionSelector(), new VerboseJavaScopeSelector(),
111 new SimpleOptionalitySelector(), new JavaScopeDeriver() );
112 session.setDependencyGraphTransformer( transformer );
113
114 DependencySelector depFilter =
115 new AndDependencySelector( new Maven3DirectScopeDependencySelector( JavaScopes.TEST ),
116 new OptionalDependencySelector(),
117 new ExclusionDependencySelector() );
118 session.setDependencySelector( depFilter );
119
120 session.setConfigProperty( ConflictResolver.CONFIG_PROP_VERBOSE, true );
121 session.setConfigProperty( "aether.dependencyManager.verbose", true );
122
123 org.sonatype.aether.artifact.Artifact aetherArtifact =
124 (org.sonatype.aether.artifact.Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
125 Artifact.class, projectArtifact,
126 exceptionHandler );
127
128 @SuppressWarnings( "unchecked" )
129 List<org.sonatype.aether.repository.RemoteRepository> aetherRepos =
130 (List<org.sonatype.aether.repository.RemoteRepository>) Invoker.invoke( RepositoryUtils.class,
131 "toRepos", List.class,
132 remoteArtifactRepositories,
133 exceptionHandler );
134
135 CollectRequest collectRequest = new CollectRequest();
136 collectRequest.setRoot( new org.sonatype.aether.graph.Dependency( aetherArtifact, "" ) );
137 collectRequest.setRepositories( aetherRepos );
138
139 org.sonatype.aether.artifact.ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
140 collectDependencyList( collectRequest, project, stereotypes );
141 collectManagedDependencyList( collectRequest, project, stereotypes );
142
143 CollectResult collectResult = repositorySystem.collectDependencies( session, collectRequest );
144
145 org.sonatype.aether.graph.DependencyNode rootNode = collectResult.getRoot();
146
147 if ( getLogger().isDebugEnabled() )
148 {
149 logTree( rootNode );
150 }
151
152 return buildDependencyNode( null, rootNode, projectArtifact, filter );
153 }
154 catch ( DependencyCollectionException e )
155 {
156 throw new DependencyCollectorBuilderException( "Could not collect dependencies: " + e.getResult(), e );
157 }
158 }
159
160 private void logTree( org.sonatype.aether.graph.DependencyNode rootNode )
161 {
162
163 rootNode.accept( new TreeDependencyVisitor( new DependencyVisitor()
164 {
165 String indent = "";
166
167 @Override
168 public boolean visitEnter( org.sonatype.aether.graph.DependencyNode dependencyNode )
169 {
170 StringBuilder sb = new StringBuilder();
171 sb.append( indent ).append( "Aether node: " ).append( dependencyNode );
172 if ( !dependencyNode.getData().isEmpty() )
173 {
174 sb.append( "data map: " ).append( dependencyNode.getData() );
175 }
176 if ( dependencyNode.getPremanagedVersion() != null && !dependencyNode.getPremanagedVersion().isEmpty() )
177 {
178 sb.append( "Premanaged.version: " ).append( dependencyNode.getPremanagedVersion() );
179 }
180 if ( dependencyNode.getPremanagedScope() != null && !dependencyNode.getPremanagedScope().isEmpty() )
181 {
182 sb.append( "Premanaged.scope: " ).append( dependencyNode.getPremanagedScope() );
183 }
184 getLogger().debug( sb.toString() );
185 indent += " ";
186 return true;
187 }
188
189 @Override
190 public boolean visitLeave( org.sonatype.aether.graph.DependencyNode dependencyNode )
191 {
192 indent = indent.substring( 0, indent.length() - 4 );
193 return true;
194 }
195 } ) );
196 }
197
198 private void collectManagedDependencyList( CollectRequest collectRequest, MavenProject project,
199 ArtifactTypeRegistry stereotypes )
200 throws DependencyCollectorBuilderException
201 {
202 if ( project.getDependencyManagement() != null )
203 {
204 for ( Dependency dependency : project.getDependencyManagement().getDependencies() )
205 {
206 org.sonatype.aether.graph.Dependency aetherDep = toAetherDependency( stereotypes, dependency );
207 collectRequest.addManagedDependency( aetherDep );
208 }
209 }
210 }
211
212 private void collectDependencyList( CollectRequest collectRequest, MavenProject project,
213 org.sonatype.aether.artifact.ArtifactTypeRegistry stereotypes )
214 throws DependencyCollectorBuilderException
215 {
216 for ( Dependency dependency : project.getDependencies() )
217 {
218 org.sonatype.aether.graph.Dependency aetherDep = toAetherDependency( stereotypes, dependency );
219 collectRequest.addDependency( aetherDep );
220 }
221 }
222
223
224 private org.sonatype.aether.graph.Dependency toAetherDependency( org.sonatype.aether.artifact.ArtifactTypeRegistry stereotypes,
225 Dependency dependency )
226 throws DependencyCollectorBuilderException
227 {
228 org.sonatype.aether.graph.Dependency aetherDep =
229 (org.sonatype.aether.graph.Dependency) Invoker.invoke( RepositoryUtils.class, "toDependency",
230 Dependency.class,
231 org.sonatype.aether.artifact.ArtifactTypeRegistry.class,
232 dependency, stereotypes, exceptionHandler );
233 return aetherDep;
234 }
235
236
237 private Artifact getDependencyArtifact( org.sonatype.aether.graph.Dependency dep )
238 {
239 org.sonatype.aether.artifact.Artifact artifact = dep.getArtifact();
240
241 try
242 {
243 Artifact mavenArtifact =
244 (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
245 org.sonatype.aether.artifact.Artifact.class, artifact, exceptionHandler );
246
247 mavenArtifact.setScope( dep.getScope() );
248 mavenArtifact.setOptional( dep.isOptional() );
249
250 return mavenArtifact;
251 }
252 catch ( DependencyCollectorBuilderException e )
253 {
254
255 throw new RuntimeException( e.getMessage(), e );
256 }
257 }
258
259 private DependencyNode buildDependencyNode( DependencyNode parent, org.sonatype.aether.graph.DependencyNode node,
260 Artifact artifact, ArtifactFilter filter )
261 {
262 String premanagedVersion = node.getPremanagedVersion();
263 String premanagedScope = node.getPremanagedScope();
264
265 Boolean optional = null;
266 if ( node.getDependency() != null )
267 {
268 optional = node.getDependency().isOptional();
269 }
270
271 List<org.apache.maven.model.Exclusion> exclusions = null;
272 if ( node.getDependency() != null )
273 {
274 exclusions = new ArrayList<>( node.getDependency().getExclusions().size() );
275 for ( Exclusion exclusion : node.getDependency().getExclusions() )
276 {
277 org.apache.maven.model.Exclusion modelExclusion = new org.apache.maven.model.Exclusion();
278 modelExclusion.setGroupId( exclusion.getGroupId() );
279 modelExclusion.setArtifactId( exclusion.getArtifactId() );
280 exclusions.add( modelExclusion );
281 }
282 }
283
284 org.sonatype.aether.graph.DependencyNode winner =
285 (org.sonatype.aether.graph.DependencyNode) node.getData().get( ConflictResolver.NODE_DATA_WINNER );
286 String winnerVersion = null;
287 String ignoredScope = null;
288 if ( winner != null )
289 {
290 winnerVersion = winner.getVersion().toString();
291 }
292 else
293 {
294 ignoredScope = (String) node.getData().get( VerboseJavaScopeSelector.REDUCED_SCOPE );
295 }
296
297 ConflictData data = new ConflictData( winnerVersion, ignoredScope );
298
299 VerboseDependencyNode current =
300 new VerboseDependencyNode( parent, artifact, premanagedVersion, premanagedScope,
301 getVersionSelectedFromRange( node.getVersionConstraint() ), optional, exclusions,
302 data );
303
304 List<DependencyNode> nodes = new ArrayList<DependencyNode>( node.getChildren().size() );
305 for ( org.sonatype.aether.graph.DependencyNode child : node.getChildren() )
306 {
307 Artifact childArtifact = getDependencyArtifact( child.getDependency() );
308
309 if ( ( filter == null ) || filter.include( childArtifact ) )
310 {
311 nodes.add( buildDependencyNode( current, child, childArtifact, filter ) );
312 }
313 }
314
315 current.setChildren( Collections.unmodifiableList( nodes ) );
316
317 return current;
318 }
319
320 private String getVersionSelectedFromRange( VersionConstraint constraint )
321 {
322 if ( ( constraint == null ) || ( constraint.getVersion() != null ) || ( constraint.getRanges().isEmpty() ) )
323 {
324 return null;
325 }
326
327 return constraint.getRanges().iterator().next().toString();
328 }
329
330 }