1 package org.apache.maven.project;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.Collection;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Objects;
27
28 import javax.inject.Inject;
29 import javax.inject.Named;
30 import javax.inject.Singleton;
31
32 import org.apache.maven.RepositoryUtils;
33 import org.apache.maven.artifact.Artifact;
34 import org.apache.maven.model.Dependency;
35 import org.apache.maven.model.DependencyManagement;
36 import org.apache.maven.model.Exclusion;
37 import org.codehaus.plexus.util.StringUtils;
38 import org.eclipse.aether.DefaultRepositorySystemSession;
39 import org.eclipse.aether.RepositorySystem;
40 import org.eclipse.aether.RepositorySystemSession;
41 import org.eclipse.aether.RequestTrace;
42 import org.eclipse.aether.artifact.ArtifactType;
43 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
44 import org.eclipse.aether.collection.CollectRequest;
45 import org.eclipse.aether.collection.DependencyCollectionException;
46 import org.eclipse.aether.graph.DependencyFilter;
47 import org.eclipse.aether.graph.DependencyNode;
48 import org.eclipse.aether.graph.DependencyVisitor;
49 import org.eclipse.aether.resolution.ArtifactResult;
50 import org.eclipse.aether.resolution.DependencyRequest;
51 import org.eclipse.aether.util.artifact.ArtifactIdUtils;
52 import org.eclipse.aether.util.artifact.JavaScopes;
53 import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57
58
59
60 @Named
61 @Singleton
62 public class DefaultProjectDependenciesResolver
63 implements ProjectDependenciesResolver
64 {
65 private final Logger logger = LoggerFactory.getLogger( getClass() );
66 private final RepositorySystem repoSystem;
67 private final List<RepositorySessionDecorator> decorators;
68
69 @Inject
70 public DefaultProjectDependenciesResolver(
71 RepositorySystem repoSystem,
72 List<RepositorySessionDecorator> decorators )
73 {
74 this.repoSystem = repoSystem;
75 this.decorators = decorators;
76 }
77
78 public DependencyResolutionResult resolve( DependencyResolutionRequest request )
79 throws DependencyResolutionException
80 {
81 final RequestTrace trace = RequestTrace.newChild( null, request );
82
83 final DefaultDependencyResolutionResult result = new DefaultDependencyResolutionResult();
84
85 final MavenProject project = request.getMavenProject();
86 final DependencyFilter filter = request.getResolutionFilter();
87 RepositorySystemSession session = request.getRepositorySession();
88 ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
89
90 if ( logger.isDebugEnabled()
91 && session.getConfigProperties().get( DependencyManagerUtils.CONFIG_PROP_VERBOSE ) == null )
92 {
93 DefaultRepositorySystemSession verbose = new DefaultRepositorySystemSession( session );
94 verbose.setConfigProperty( DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE );
95 session = verbose;
96 }
97
98 for ( RepositorySessionDecorator decorator : decorators )
99 {
100 RepositorySystemSession decorated = decorator.decorate( project, session );
101 if ( decorated != null )
102 {
103 session = decorated;
104 }
105 }
106
107 CollectRequest collect = new CollectRequest();
108 collect.setRootArtifact( RepositoryUtils.toArtifact( project.getArtifact() ) );
109 collect.setRequestContext( "project" );
110 collect.setRepositories( project.getRemoteProjectRepositories() );
111
112 if ( project.getDependencyArtifacts() == null )
113 {
114 for ( Dependency dependency : project.getDependencies() )
115 {
116 if ( StringUtils.isEmpty( dependency.getGroupId() ) || StringUtils.isEmpty( dependency.getArtifactId() )
117 || StringUtils.isEmpty( dependency.getVersion() ) )
118 {
119
120 continue;
121 }
122 collect.addDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
123 }
124 }
125 else
126 {
127 Map<String, Dependency> dependencies = new HashMap<>();
128 for ( Dependency dependency : project.getDependencies() )
129 {
130 String classifier = dependency.getClassifier();
131 if ( classifier == null )
132 {
133 ArtifactType type = stereotypes.get( dependency.getType() );
134 if ( type != null )
135 {
136 classifier = type.getClassifier();
137 }
138 }
139 String key =
140 ArtifactIdUtils.toVersionlessId( dependency.getGroupId(), dependency.getArtifactId(),
141 dependency.getType(), classifier );
142 dependencies.put( key, dependency );
143 }
144 for ( Artifact artifact : project.getDependencyArtifacts() )
145 {
146 String key = artifact.getDependencyConflictId();
147 Dependency dependency = dependencies.get( key );
148 Collection<Exclusion> exclusions = dependency != null ? dependency.getExclusions() : null;
149 org.eclipse.aether.graph.Dependency dep = RepositoryUtils.toDependency( artifact, exclusions );
150 if ( !JavaScopes.SYSTEM.equals( dep.getScope() ) && dep.getArtifact().getFile() != null )
151 {
152
153 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
154 art = art.setFile( null ).setVersion( art.getBaseVersion() );
155 dep = dep.setArtifact( art );
156 }
157 collect.addDependency( dep );
158 }
159 }
160
161 DependencyManagement depMgmt = project.getDependencyManagement();
162 if ( depMgmt != null )
163 {
164 for ( Dependency dependency : depMgmt.getDependencies() )
165 {
166 collect.addManagedDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
167 }
168 }
169
170 DependencyRequest depRequest = new DependencyRequest( collect, filter );
171 depRequest.setTrace( trace );
172
173 DependencyNode node;
174 try
175 {
176 collect.setTrace( RequestTrace.newChild( trace, depRequest ) );
177 node = repoSystem.collectDependencies( session, collect ).getRoot();
178 result.setDependencyGraph( node );
179 }
180 catch ( DependencyCollectionException e )
181 {
182 result.setDependencyGraph( e.getResult().getRoot() );
183 result.setCollectionErrors( e.getResult().getExceptions() );
184
185 throw new DependencyResolutionException( result, "Could not resolve dependencies for project "
186 + project.getId() + ": " + e.getMessage(), e );
187 }
188
189 depRequest.setRoot( node );
190
191 if ( logger.isWarnEnabled() )
192 {
193 for ( DependencyNode child : node.getChildren() )
194 {
195 if ( !child.getRelocations().isEmpty() )
196 {
197 org.eclipse.aether.artifact.Artifact relocated = child.getDependency().getArtifact();
198 String message = relocated instanceof org.apache.maven.repository.internal.RelocatedArtifact
199 ? ( ( org.apache.maven.repository.internal.RelocatedArtifact ) relocated ).getMessage()
200 : null;
201 logger.warn( "The artifact " + child.getRelocations().get( 0 ) + " has been relocated to "
202 + relocated + ( message != null ? ": " + message : "" ) );
203 }
204 }
205 }
206
207 if ( logger.isDebugEnabled() )
208 {
209 node.accept( new GraphLogger( project ) );
210 }
211
212 try
213 {
214 process( result, repoSystem.resolveDependencies( session, depRequest ).getArtifactResults() );
215 }
216 catch ( org.eclipse.aether.resolution.DependencyResolutionException e )
217 {
218 process( result, e.getResult().getArtifactResults() );
219
220 throw new DependencyResolutionException( result, "Could not resolve dependencies for project "
221 + project.getId() + ": " + e.getMessage(), e );
222 }
223
224 return result;
225 }
226
227 private void process( DefaultDependencyResolutionResult result, Collection<ArtifactResult> results )
228 {
229 for ( ArtifactResult ar : results )
230 {
231 DependencyNode node = ar.getRequest().getDependencyNode();
232 if ( ar.isResolved() )
233 {
234 result.addResolvedDependency( node.getDependency() );
235 }
236 else
237 {
238 result.setResolutionErrors( node.getDependency(), ar.getExceptions() );
239 }
240 }
241 }
242
243
244 class GraphLogger
245 implements DependencyVisitor
246 {
247
248 private final MavenProject project;
249
250 private String indent = "";
251
252 GraphLogger( MavenProject project )
253 {
254 this.project = project;
255 }
256
257 public boolean visitEnter( DependencyNode node )
258 {
259 StringBuilder buffer = new StringBuilder( 128 );
260 buffer.append( indent );
261 org.eclipse.aether.graph.Dependency dep = node.getDependency();
262 if ( dep != null )
263 {
264 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
265
266 buffer.append( art );
267 if ( StringUtils.isNotEmpty( dep.getScope() ) )
268 {
269 buffer.append( ':' ).append( dep.getScope() );
270 }
271
272 if ( dep.isOptional() )
273 {
274 buffer.append( " (optional)" );
275 }
276
277
278
279
280 if ( ( node.getManagedBits() & DependencyNode.MANAGED_SCOPE ) == DependencyNode.MANAGED_SCOPE )
281 {
282 final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node );
283 buffer.append( " (scope managed from " );
284 buffer.append( Objects.toString( premanagedScope, "default" ) );
285 buffer.append( ')' );
286 }
287
288 if ( ( node.getManagedBits() & DependencyNode.MANAGED_VERSION ) == DependencyNode.MANAGED_VERSION )
289 {
290 final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node );
291 buffer.append( " (version managed from " );
292 buffer.append( Objects.toString( premanagedVersion, "default" ) );
293 buffer.append( ')' );
294 }
295
296 if ( ( node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL ) == DependencyNode.MANAGED_OPTIONAL )
297 {
298 final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node );
299 buffer.append( " (optionality managed from " );
300 buffer.append( Objects.toString( premanagedOptional, "default" ) );
301 buffer.append( ')' );
302 }
303
304 if ( ( node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS )
305 == DependencyNode.MANAGED_EXCLUSIONS )
306 {
307 final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions =
308 DependencyManagerUtils.getPremanagedExclusions( node );
309
310 buffer.append( " (exclusions managed from " );
311 buffer.append( Objects.toString( premanagedExclusions, "default" ) );
312 buffer.append( ')' );
313 }
314
315 if ( ( node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES )
316 == DependencyNode.MANAGED_PROPERTIES )
317 {
318 final Map<String, String> premanagedProperties =
319 DependencyManagerUtils.getPremanagedProperties( node );
320
321 buffer.append( " (properties managed from " );
322 buffer.append( Objects.toString( premanagedProperties, "default" ) );
323 buffer.append( ')' );
324 }
325 }
326 else
327 {
328 buffer.append( project.getGroupId() );
329 buffer.append( ':' ).append( project.getArtifactId() );
330 buffer.append( ':' ).append( project.getPackaging() );
331 buffer.append( ':' ).append( project.getVersion() );
332 }
333
334 logger.debug( buffer.toString() );
335 indent += " ";
336 return true;
337 }
338
339 public boolean visitLeave( DependencyNode node )
340 {
341 indent = indent.substring( 0, indent.length() - 3 );
342 return true;
343 }
344
345 }
346
347 }