1 package org.eclipse.aether.internal.impl.collect;
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.Collection;
24 import java.util.Collections;
25 import java.util.HashSet;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import org.eclipse.aether.DefaultRepositorySystemSession;
31 import org.eclipse.aether.RepositoryException;
32 import org.eclipse.aether.RepositorySystemSession;
33 import org.eclipse.aether.RequestTrace;
34 import org.eclipse.aether.artifact.Artifact;
35 import org.eclipse.aether.artifact.ArtifactProperties;
36 import org.eclipse.aether.collection.CollectRequest;
37 import org.eclipse.aether.collection.CollectResult;
38 import org.eclipse.aether.collection.DependencyCollectionException;
39 import org.eclipse.aether.collection.DependencyGraphTransformer;
40 import org.eclipse.aether.collection.DependencyTraverser;
41 import org.eclipse.aether.collection.VersionFilter;
42 import org.eclipse.aether.graph.DefaultDependencyNode;
43 import org.eclipse.aether.graph.Dependency;
44 import org.eclipse.aether.graph.DependencyNode;
45 import org.eclipse.aether.impl.ArtifactDescriptorReader;
46 import org.eclipse.aether.impl.DependencyCollector;
47 import org.eclipse.aether.impl.RemoteRepositoryManager;
48 import org.eclipse.aether.impl.VersionRangeResolver;
49 import org.eclipse.aether.repository.ArtifactRepository;
50 import org.eclipse.aether.repository.RemoteRepository;
51 import org.eclipse.aether.resolution.ArtifactDescriptorException;
52 import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
53 import org.eclipse.aether.resolution.ArtifactDescriptorResult;
54 import org.eclipse.aether.resolution.VersionRangeRequest;
55 import org.eclipse.aether.resolution.VersionRangeResolutionException;
56 import org.eclipse.aether.resolution.VersionRangeResult;
57 import org.eclipse.aether.spi.locator.ServiceLocator;
58 import org.eclipse.aether.util.ConfigUtils;
59 import org.eclipse.aether.util.graph.transformer.TransformationContextKeys;
60 import org.eclipse.aether.version.Version;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import static java.util.Objects.requireNonNull;
65
66
67
68
69
70
71 public abstract class DependencyCollectorDelegate implements DependencyCollector
72 {
73 protected static final String CONFIG_PROP_MAX_EXCEPTIONS = "aether.dependencyCollector.maxExceptions";
74
75 protected static final int CONFIG_PROP_MAX_EXCEPTIONS_DEFAULT = 50;
76
77 protected static final String CONFIG_PROP_MAX_CYCLES = "aether.dependencyCollector.maxCycles";
78
79 protected static final int CONFIG_PROP_MAX_CYCLES_DEFAULT = 10;
80
81 protected final Logger logger = LoggerFactory.getLogger( getClass() );
82
83 protected RemoteRepositoryManager remoteRepositoryManager;
84
85 protected ArtifactDescriptorReader descriptorReader;
86
87 protected VersionRangeResolver versionRangeResolver;
88
89
90
91
92
93
94 @Deprecated
95 protected DependencyCollectorDelegate()
96 {
97
98 }
99
100 protected DependencyCollectorDelegate( RemoteRepositoryManager remoteRepositoryManager,
101 ArtifactDescriptorReader artifactDescriptorReader,
102 VersionRangeResolver versionRangeResolver )
103 {
104 setRemoteRepositoryManager( remoteRepositoryManager );
105 setArtifactDescriptorReader( artifactDescriptorReader );
106 setVersionRangeResolver( versionRangeResolver );
107 }
108
109 public void initService( ServiceLocator locator )
110 {
111 setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
112 setArtifactDescriptorReader( locator.getService( ArtifactDescriptorReader.class ) );
113 setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) );
114 }
115
116 public DependencyCollector setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
117 {
118 this.remoteRepositoryManager =
119 requireNonNull( remoteRepositoryManager, "remote repository manager cannot be null" );
120 return this;
121 }
122
123 public DependencyCollector setArtifactDescriptorReader( ArtifactDescriptorReader artifactDescriptorReader )
124 {
125 descriptorReader = requireNonNull( artifactDescriptorReader, "artifact descriptor reader cannot be null" );
126 return this;
127 }
128
129 public DependencyCollector setVersionRangeResolver( VersionRangeResolver versionRangeResolver )
130 {
131 this.versionRangeResolver =
132 requireNonNull( versionRangeResolver, "version range resolver cannot be null" );
133 return this;
134 }
135
136 @SuppressWarnings( "checkstyle:methodlength" )
137 @Override
138 public final CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request )
139 throws DependencyCollectionException
140 {
141 requireNonNull( session, "session cannot be null" );
142 requireNonNull( request, "request cannot be null" );
143 session = optimizeSession( session );
144
145 RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
146
147 CollectResult result = new CollectResult( request );
148
149 DependencyTraverser depTraverser = session.getDependencyTraverser();
150 VersionFilter verFilter = session.getVersionFilter();
151
152 Dependency root = request.getRoot();
153 List<RemoteRepository> repositories = request.getRepositories();
154 List<Dependency> dependencies = request.getDependencies();
155 List<Dependency> managedDependencies = request.getManagedDependencies();
156
157 Map<String, Object> stats = new LinkedHashMap<>();
158 long time1 = System.nanoTime();
159
160 DefaultDependencyNode node;
161 if ( root != null )
162 {
163 List<? extends Version> versions;
164 VersionRangeResult rangeResult;
165 try
166 {
167 VersionRangeRequest rangeRequest =
168 new VersionRangeRequest( root.getArtifact(), request.getRepositories(),
169 request.getRequestContext() );
170 rangeRequest.setTrace( trace );
171 rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest );
172 versions = filterVersions( root, rangeResult, verFilter, new DefaultVersionFilterContext( session ) );
173 }
174 catch ( VersionRangeResolutionException e )
175 {
176 result.addException( e );
177 throw new DependencyCollectionException( result, e.getMessage() );
178 }
179
180 Version version = versions.get( versions.size() - 1 );
181 root = root.setArtifact( root.getArtifact().setVersion( version.toString() ) );
182
183 ArtifactDescriptorResult descriptorResult;
184 try
185 {
186 ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
187 descriptorRequest.setArtifact( root.getArtifact() );
188 descriptorRequest.setRepositories( request.getRepositories() );
189 descriptorRequest.setRequestContext( request.getRequestContext() );
190 descriptorRequest.setTrace( trace );
191 if ( isLackingDescriptor( root.getArtifact() ) )
192 {
193 descriptorResult = new ArtifactDescriptorResult( descriptorRequest );
194 }
195 else
196 {
197 descriptorResult = descriptorReader.readArtifactDescriptor( session, descriptorRequest );
198 }
199 }
200 catch ( ArtifactDescriptorException e )
201 {
202 result.addException( e );
203 throw new DependencyCollectionException( result, e.getMessage() );
204 }
205
206 root = root.setArtifact( descriptorResult.getArtifact() );
207
208 if ( !session.isIgnoreArtifactDescriptorRepositories() )
209 {
210 repositories = remoteRepositoryManager.aggregateRepositories( session, repositories,
211 descriptorResult.getRepositories(),
212 true );
213 }
214 dependencies = mergeDeps( dependencies, descriptorResult.getDependencies() );
215 managedDependencies = mergeDeps( managedDependencies, descriptorResult.getManagedDependencies() );
216
217 node = new DefaultDependencyNode( root );
218 node.setRequestContext( request.getRequestContext() );
219 node.setRelocations( descriptorResult.getRelocations() );
220 node.setVersionConstraint( rangeResult.getVersionConstraint() );
221 node.setVersion( version );
222 node.setAliases( descriptorResult.getAliases() );
223 node.setRepositories( request.getRepositories() );
224 }
225 else
226 {
227 node = new DefaultDependencyNode( request.getRootArtifact() );
228 node.setRequestContext( request.getRequestContext() );
229 node.setRepositories( request.getRepositories() );
230 }
231
232 result.setRoot( node );
233
234 boolean traverse = root == null || depTraverser == null || depTraverser.traverseDependency( root );
235 String errorPath = null;
236 if ( traverse && !dependencies.isEmpty() )
237 {
238 DataPool pool = new DataPool( session );
239
240 DefaultDependencyCollectionContext context = new DefaultDependencyCollectionContext(
241 session, request.getRootArtifact(), root, managedDependencies );
242
243 DefaultVersionFilterContext versionContext = new DefaultVersionFilterContext( session );
244
245 Results results = new Results( result, session );
246
247 doCollectDependencies(
248 session, trace, pool, context, versionContext, request, node, repositories, dependencies,
249 managedDependencies, results
250 );
251
252 errorPath = results.getErrorPath();
253 }
254
255 long time2 = System.nanoTime();
256
257 DependencyGraphTransformer transformer = session.getDependencyGraphTransformer();
258 if ( transformer != null )
259 {
260 try
261 {
262 DefaultDependencyGraphTransformationContext context =
263 new DefaultDependencyGraphTransformationContext( session );
264 context.put( TransformationContextKeys.STATS, stats );
265 result.setRoot( transformer.transformGraph( node, context ) );
266 }
267 catch ( RepositoryException e )
268 {
269 result.addException( e );
270 }
271 }
272
273 long time3 = System.nanoTime();
274 if ( logger.isDebugEnabled() )
275 {
276 stats.put( getClass().getSimpleName() + ".collectTime", time2 - time1 );
277 stats.put( getClass().getSimpleName() + ".transformTime", time3 - time2 );
278 logger.debug( "Dependency collection stats {}", stats );
279 }
280
281 if ( errorPath != null )
282 {
283 throw new DependencyCollectionException( result, "Failed to collect dependencies at " + errorPath );
284 }
285 if ( !result.getExceptions().isEmpty() )
286 {
287 throw new DependencyCollectionException( result );
288 }
289
290 return result;
291 }
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 protected RequestTrace collectStepTrace( RequestTrace trace, String context, List<DependencyNode> path,
308 Dependency node )
309 {
310 return RequestTrace.newChild(
311 trace,
312 new CollectStepDataImpl(
313 context,
314 path,
315 node
316 )
317 );
318 }
319
320 @SuppressWarnings( "checkstyle:parameternumber" )
321 protected abstract void doCollectDependencies( RepositorySystemSession session, RequestTrace trace, DataPool pool,
322 DefaultDependencyCollectionContext context,
323 DefaultVersionFilterContext versionContext,
324 CollectRequest request, DependencyNode node,
325 List<RemoteRepository> repositories, List<Dependency> dependencies,
326 List<Dependency> managedDependencies, Results results );
327
328 protected RepositorySystemSession optimizeSession( RepositorySystemSession session )
329 {
330 DefaultRepositorySystemSession optimized = new DefaultRepositorySystemSession( session );
331 optimized.setArtifactTypeRegistry( CachingArtifactTypeRegistry.newInstance( session ) );
332 return optimized;
333 }
334
335 protected List<Dependency> mergeDeps( List<Dependency> dominant, List<Dependency> recessive )
336 {
337 List<Dependency> result;
338 if ( dominant == null || dominant.isEmpty() )
339 {
340 result = recessive;
341 }
342 else if ( recessive == null || recessive.isEmpty() )
343 {
344 result = dominant;
345 }
346 else
347 {
348 int initialCapacity = dominant.size() + recessive.size();
349 result = new ArrayList<>( initialCapacity );
350 Collection<String> ids = new HashSet<>( initialCapacity, 1.0f );
351 for ( Dependency dependency : dominant )
352 {
353 ids.add( getId( dependency.getArtifact() ) );
354 result.add( dependency );
355 }
356 for ( Dependency dependency : recessive )
357 {
358 if ( !ids.contains( getId( dependency.getArtifact() ) ) )
359 {
360 result.add( dependency );
361 }
362 }
363 }
364 return result;
365 }
366
367 protected static String getId( Artifact a )
368 {
369 return a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getClassifier() + ':' + a.getExtension();
370 }
371
372 @SuppressWarnings( "checkstyle:parameternumber" )
373 protected static DefaultDependencyNode createDependencyNode( List<Artifact> relocations,
374 PremanagedDependency preManaged,
375 VersionRangeResult rangeResult, Version version,
376 Dependency d, Collection<Artifact> aliases,
377 List<RemoteRepository> repos, String requestContext )
378 {
379 DefaultDependencyNode child = new DefaultDependencyNode( d );
380 preManaged.applyTo( child );
381 child.setRelocations( relocations );
382 child.setVersionConstraint( rangeResult.getVersionConstraint() );
383 child.setVersion( version );
384 child.setAliases( aliases );
385 child.setRepositories( repos );
386 child.setRequestContext( requestContext );
387 return child;
388 }
389
390 protected static DefaultDependencyNode createDependencyNode( List<Artifact> relocations,
391 PremanagedDependency preManaged,
392 VersionRangeResult rangeResult, Version version,
393 Dependency d,
394 ArtifactDescriptorResult descriptorResult,
395 DependencyNode cycleNode )
396 {
397 DefaultDependencyNode child =
398 createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult.getAliases(),
399 cycleNode.getRepositories(), cycleNode.getRequestContext() );
400 child.setChildren( cycleNode.getChildren() );
401 return child;
402 }
403
404 protected static ArtifactDescriptorRequest createArtifactDescriptorRequest( String requestContext,
405 RequestTrace requestTrace,
406 List<RemoteRepository> repositories,
407 Dependency d )
408 {
409 ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
410 descriptorRequest.setArtifact( d.getArtifact() );
411 descriptorRequest.setRepositories( repositories );
412 descriptorRequest.setRequestContext( requestContext );
413 descriptorRequest.setTrace( requestTrace );
414 return descriptorRequest;
415 }
416
417 protected static VersionRangeRequest createVersionRangeRequest( String requestContext,
418 RequestTrace requestTrace,
419 List<RemoteRepository> repositories,
420 Dependency dependency )
421 {
422 VersionRangeRequest rangeRequest = new VersionRangeRequest();
423 rangeRequest.setArtifact( dependency.getArtifact() );
424 rangeRequest.setRepositories( repositories );
425 rangeRequest.setRequestContext( requestContext );
426 rangeRequest.setTrace( requestTrace );
427 return rangeRequest;
428 }
429
430 protected VersionRangeResult cachedResolveRangeResult( VersionRangeRequest rangeRequest, DataPool pool,
431 RepositorySystemSession session )
432 throws VersionRangeResolutionException
433 {
434 Object key = pool.toKey( rangeRequest );
435 VersionRangeResult rangeResult = pool.getConstraint( key, rangeRequest );
436 if ( rangeResult == null )
437 {
438 rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest );
439 pool.putConstraint( key, rangeResult );
440 }
441 return rangeResult;
442 }
443
444 protected static boolean isLackingDescriptor( Artifact artifact )
445 {
446 return artifact.getProperty( ArtifactProperties.LOCAL_PATH, null ) != null;
447 }
448
449 protected static List<RemoteRepository> getRemoteRepositories( ArtifactRepository repository,
450 List<RemoteRepository> repositories )
451 {
452 if ( repository instanceof RemoteRepository )
453 {
454 return Collections.singletonList( (RemoteRepository) repository );
455 }
456 if ( repository != null )
457 {
458 return Collections.emptyList();
459 }
460 return repositories;
461 }
462
463 protected static List<? extends Version> filterVersions( Dependency dependency, VersionRangeResult rangeResult,
464 VersionFilter verFilter,
465 DefaultVersionFilterContext verContext )
466 throws VersionRangeResolutionException
467 {
468 if ( rangeResult.getVersions().isEmpty() )
469 {
470 throw new VersionRangeResolutionException( rangeResult,
471 "No versions available for " + dependency.getArtifact()
472 + " within specified range" );
473 }
474
475 List<? extends Version> versions;
476 if ( verFilter != null && rangeResult.getVersionConstraint().getRange() != null )
477 {
478 verContext.set( dependency, rangeResult );
479 try
480 {
481 verFilter.filterVersions( verContext );
482 }
483 catch ( RepositoryException e )
484 {
485 throw new VersionRangeResolutionException( rangeResult,
486 "Failed to filter versions for " + dependency.getArtifact(), e );
487 }
488 versions = verContext.get();
489 if ( versions.isEmpty() )
490 {
491 throw new VersionRangeResolutionException( rangeResult,
492 "No acceptable versions for " + dependency.getArtifact() + ": " + rangeResult.getVersions() );
493 }
494 }
495 else
496 {
497 versions = rangeResult.getVersions();
498 }
499 return versions;
500 }
501
502
503
504
505 protected static class Results
506 {
507
508 private final CollectResult result;
509
510 final int maxExceptions;
511
512 final int maxCycles;
513
514 String errorPath;
515
516 public Results( CollectResult result, RepositorySystemSession session )
517 {
518 this.result = result;
519
520 maxExceptions =
521 ConfigUtils.getInteger( session, CONFIG_PROP_MAX_EXCEPTIONS_DEFAULT, CONFIG_PROP_MAX_EXCEPTIONS );
522
523 maxCycles = ConfigUtils.getInteger( session, CONFIG_PROP_MAX_CYCLES_DEFAULT, CONFIG_PROP_MAX_CYCLES );
524 }
525
526 public String getErrorPath()
527 {
528 return errorPath;
529 }
530
531 public void addException( Dependency dependency, Exception e, List<DependencyNode> nodes )
532 {
533 if ( maxExceptions < 0 || result.getExceptions().size() < maxExceptions )
534 {
535 result.addException( e );
536 if ( errorPath == null )
537 {
538 StringBuilder buffer = new StringBuilder( 256 );
539 for ( DependencyNode node : nodes )
540 {
541 if ( buffer.length() > 0 )
542 {
543 buffer.append( " -> " );
544 }
545 Dependency dep = node.getDependency();
546 if ( dep != null )
547 {
548 buffer.append( dep.getArtifact() );
549 }
550 }
551 if ( buffer.length() > 0 )
552 {
553 buffer.append( " -> " );
554 }
555 buffer.append( dependency.getArtifact() );
556 errorPath = buffer.toString();
557 }
558 }
559 }
560
561 public void addCycle( List<DependencyNode> nodes, int cycleEntry, Dependency dependency )
562 {
563 if ( maxCycles < 0 || result.getCycles().size() < maxCycles )
564 {
565 result.addCycle( new DefaultDependencyCycle( nodes, cycleEntry, dependency ) );
566 }
567 }
568 }
569
570 }