View Javadoc
1   package org.eclipse.aether.internal.impl.collect;
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.Collection;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.LinkedHashMap;
28  import java.util.List;
29  import java.util.Map;
30  import static java.util.Objects.requireNonNull;
31  
32  import javax.inject.Inject;
33  import javax.inject.Named;
34  import javax.inject.Singleton;
35  
36  import org.eclipse.aether.DefaultRepositorySystemSession;
37  import org.eclipse.aether.RepositoryException;
38  import org.eclipse.aether.RepositorySystemSession;
39  import org.eclipse.aether.RequestTrace;
40  import org.eclipse.aether.artifact.Artifact;
41  import org.eclipse.aether.artifact.ArtifactProperties;
42  import org.eclipse.aether.collection.CollectRequest;
43  import org.eclipse.aether.collection.CollectResult;
44  import org.eclipse.aether.collection.DependencyCollectionException;
45  import org.eclipse.aether.collection.DependencyGraphTransformer;
46  import org.eclipse.aether.collection.DependencyManagement;
47  import org.eclipse.aether.collection.DependencyManager;
48  import org.eclipse.aether.collection.DependencySelector;
49  import org.eclipse.aether.collection.DependencyTraverser;
50  import org.eclipse.aether.collection.VersionFilter;
51  import org.eclipse.aether.graph.DefaultDependencyNode;
52  import org.eclipse.aether.graph.Dependency;
53  import org.eclipse.aether.graph.DependencyNode;
54  import org.eclipse.aether.graph.Exclusion;
55  import org.eclipse.aether.impl.ArtifactDescriptorReader;
56  import org.eclipse.aether.impl.DependencyCollector;
57  import org.eclipse.aether.impl.RemoteRepositoryManager;
58  import org.eclipse.aether.impl.VersionRangeResolver;
59  import org.eclipse.aether.repository.ArtifactRepository;
60  import org.eclipse.aether.repository.RemoteRepository;
61  import org.eclipse.aether.resolution.ArtifactDescriptorException;
62  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
63  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
64  import org.eclipse.aether.resolution.VersionRangeRequest;
65  import org.eclipse.aether.resolution.VersionRangeResolutionException;
66  import org.eclipse.aether.resolution.VersionRangeResult;
67  import org.eclipse.aether.spi.locator.Service;
68  import org.eclipse.aether.spi.locator.ServiceLocator;
69  import org.eclipse.aether.util.ConfigUtils;
70  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
71  import org.eclipse.aether.util.graph.transformer.TransformationContextKeys;
72  import org.eclipse.aether.version.Version;
73  import org.slf4j.Logger;
74  import org.slf4j.LoggerFactory;
75  
76  /**
77   */
78  @Singleton
79  @Named
80  public class DefaultDependencyCollector
81      implements DependencyCollector, Service
82  {
83  
84      private static final String CONFIG_PROP_MAX_EXCEPTIONS = "aether.dependencyCollector.maxExceptions";
85  
86      private static final int CONFIG_PROP_MAX_EXCEPTIONS_DEFAULT = 50;
87  
88      private static final String CONFIG_PROP_MAX_CYCLES = "aether.dependencyCollector.maxCycles";
89  
90      private static final int CONFIG_PROP_MAX_CYCLES_DEFAULT = 10;
91  
92      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultDependencyCollector.class );
93  
94      private RemoteRepositoryManager remoteRepositoryManager;
95  
96      private ArtifactDescriptorReader descriptorReader;
97  
98      private VersionRangeResolver versionRangeResolver;
99  
100     public DefaultDependencyCollector()
101     {
102         // enables default constructor
103     }
104 
105     @Inject
106     DefaultDependencyCollector( RemoteRepositoryManager remoteRepositoryManager,
107                                 ArtifactDescriptorReader artifactDescriptorReader,
108                                 VersionRangeResolver versionRangeResolver )
109     {
110         setRemoteRepositoryManager( remoteRepositoryManager );
111         setArtifactDescriptorReader( artifactDescriptorReader );
112         setVersionRangeResolver( versionRangeResolver );
113     }
114 
115     public void initService( ServiceLocator locator )
116     {
117         setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
118         setArtifactDescriptorReader( locator.getService( ArtifactDescriptorReader.class ) );
119         setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) );
120     }
121 
122     public DefaultDependencyCollector setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
123     {
124         this.remoteRepositoryManager =
125                 requireNonNull( remoteRepositoryManager, "remote repository provider cannot be null" );
126         return this;
127     }
128 
129     public DefaultDependencyCollector setArtifactDescriptorReader( ArtifactDescriptorReader artifactDescriptorReader )
130     {
131         descriptorReader = requireNonNull( artifactDescriptorReader, "artifact descriptor reader cannot be null" );
132         return this;
133     }
134 
135     public DefaultDependencyCollector setVersionRangeResolver( VersionRangeResolver versionRangeResolver )
136     {
137         this.versionRangeResolver =
138                 requireNonNull( versionRangeResolver, "version range resolver cannot be null" );
139         return this;
140     }
141 
142     @SuppressWarnings( "checkstyle:methodlength" )
143     public CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request )
144         throws DependencyCollectionException
145     {
146         requireNonNull( session, "session cannot be null" );
147         requireNonNull( request, "request cannot be null" );
148         session = optimizeSession( session );
149 
150         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
151 
152         CollectResult result = new CollectResult( request );
153 
154         DependencySelector depSelector = session.getDependencySelector();
155         DependencyManager depManager = session.getDependencyManager();
156         DependencyTraverser depTraverser = session.getDependencyTraverser();
157         VersionFilter verFilter = session.getVersionFilter();
158 
159         Dependency root = request.getRoot();
160         List<RemoteRepository> repositories = request.getRepositories();
161         List<Dependency> dependencies = request.getDependencies();
162         List<Dependency> managedDependencies = request.getManagedDependencies();
163 
164         Map<String, Object> stats = new LinkedHashMap<>();
165         long time1 = System.nanoTime();
166 
167         DefaultDependencyNode node;
168         if ( root != null )
169         {
170             List<? extends Version> versions;
171             VersionRangeResult rangeResult;
172             try
173             {
174                 VersionRangeRequest rangeRequest =
175                     new VersionRangeRequest( root.getArtifact(), request.getRepositories(),
176                                              request.getRequestContext() );
177                 rangeRequest.setTrace( trace );
178                 rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest );
179                 versions = filterVersions( root, rangeResult, verFilter, new DefaultVersionFilterContext( session ) );
180             }
181             catch ( VersionRangeResolutionException e )
182             {
183                 result.addException( e );
184                 throw new DependencyCollectionException( result, e.getMessage() );
185             }
186 
187             Version version = versions.get( versions.size() - 1 );
188             root = root.setArtifact( root.getArtifact().setVersion( version.toString() ) );
189 
190             ArtifactDescriptorResult descriptorResult;
191             try
192             {
193                 ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
194                 descriptorRequest.setArtifact( root.getArtifact() );
195                 descriptorRequest.setRepositories( request.getRepositories() );
196                 descriptorRequest.setRequestContext( request.getRequestContext() );
197                 descriptorRequest.setTrace( trace );
198                 if ( isLackingDescriptor( root.getArtifact() ) )
199                 {
200                     descriptorResult = new ArtifactDescriptorResult( descriptorRequest );
201                 }
202                 else
203                 {
204                     descriptorResult = descriptorReader.readArtifactDescriptor( session, descriptorRequest );
205                 }
206             }
207             catch ( ArtifactDescriptorException e )
208             {
209                 result.addException( e );
210                 throw new DependencyCollectionException( result, e.getMessage() );
211             }
212 
213             root = root.setArtifact( descriptorResult.getArtifact() );
214 
215             if ( !session.isIgnoreArtifactDescriptorRepositories() )
216             {
217                 repositories = remoteRepositoryManager.aggregateRepositories( session, repositories,
218                                                                               descriptorResult.getRepositories(),
219                                                                               true );
220             }
221             dependencies = mergeDeps( dependencies, descriptorResult.getDependencies() );
222             managedDependencies = mergeDeps( managedDependencies, descriptorResult.getManagedDependencies() );
223 
224             node = new DefaultDependencyNode( root );
225             node.setRequestContext( request.getRequestContext() );
226             node.setRelocations( descriptorResult.getRelocations() );
227             node.setVersionConstraint( rangeResult.getVersionConstraint() );
228             node.setVersion( version );
229             node.setAliases( descriptorResult.getAliases() );
230             node.setRepositories( request.getRepositories() );
231         }
232         else
233         {
234             node = new DefaultDependencyNode( request.getRootArtifact() );
235             node.setRequestContext( request.getRequestContext() );
236             node.setRepositories( request.getRepositories() );
237         }
238 
239         result.setRoot( node );
240 
241         boolean traverse = root == null || depTraverser == null || depTraverser.traverseDependency( root );
242         String errorPath = null;
243         if ( traverse && !dependencies.isEmpty() )
244         {
245             DataPool pool = new DataPool( session );
246 
247             NodeStack nodes = new NodeStack();
248             nodes.push( node );
249 
250             DefaultDependencyCollectionContext context =
251                 new DefaultDependencyCollectionContext( session, request.getRootArtifact(), root, managedDependencies );
252 
253             DefaultVersionFilterContext versionContext = new DefaultVersionFilterContext( session );
254 
255             Args args = new Args( session, trace, pool, nodes, context, versionContext, request );
256             Results results = new Results( result, session );
257 
258             process( args, results, dependencies, repositories,
259                      depSelector != null ? depSelector.deriveChildSelector( context ) : null,
260                      depManager != null ? depManager.deriveChildManager( context ) : null,
261                      depTraverser != null ? depTraverser.deriveChildTraverser( context ) : null,
262                      verFilter != null ? verFilter.deriveChildFilter( context ) : null );
263 
264             errorPath = results.errorPath;
265         }
266 
267         long time2 = System.nanoTime();
268 
269         DependencyGraphTransformer transformer = session.getDependencyGraphTransformer();
270         if ( transformer != null )
271         {
272             try
273             {
274                 DefaultDependencyGraphTransformationContext context =
275                     new DefaultDependencyGraphTransformationContext( session );
276                 context.put( TransformationContextKeys.STATS, stats );
277                 result.setRoot( transformer.transformGraph( node, context ) );
278             }
279             catch ( RepositoryException e )
280             {
281                 result.addException( e );
282             }
283         }
284 
285         long time3 = System.nanoTime();
286         stats.put( "DefaultDependencyCollector.collectTime", time2 - time1 );
287         stats.put( "DefaultDependencyCollector.transformTime", time3 - time2 );
288         LOGGER.debug( "Dependency collection stats {}", stats );
289 
290         if ( errorPath != null )
291         {
292             throw new DependencyCollectionException( result, "Failed to collect dependencies at " + errorPath );
293         }
294         if ( !result.getExceptions().isEmpty() )
295         {
296             throw new DependencyCollectionException( result );
297         }
298 
299         return result;
300     }
301 
302     private static RepositorySystemSession optimizeSession( RepositorySystemSession session )
303     {
304         DefaultRepositorySystemSession optimized = new DefaultRepositorySystemSession( session );
305         optimized.setArtifactTypeRegistry( CachingArtifactTypeRegistry.newInstance( session ) );
306         return optimized;
307     }
308 
309     private List<Dependency> mergeDeps( List<Dependency> dominant, List<Dependency> recessive )
310     {
311         List<Dependency> result;
312         if ( dominant == null || dominant.isEmpty() )
313         {
314             result = recessive;
315         }
316         else if ( recessive == null || recessive.isEmpty() )
317         {
318             result = dominant;
319         }
320         else
321         {
322             int initialCapacity = dominant.size() + recessive.size();
323             result = new ArrayList<>( initialCapacity );
324             Collection<String> ids = new HashSet<>( initialCapacity, 1.0f );
325             for ( Dependency dependency : dominant )
326             {
327                 ids.add( getId( dependency.getArtifact() ) );
328                 result.add( dependency );
329             }
330             for ( Dependency dependency : recessive )
331             {
332                 if ( !ids.contains( getId( dependency.getArtifact() ) ) )
333                 {
334                     result.add( dependency );
335                 }
336             }
337         }
338         return result;
339     }
340 
341     private static String getId( Artifact a )
342     {
343         return a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getClassifier() + ':' + a.getExtension();
344     }
345 
346     @SuppressWarnings( "checkstyle:parameternumber" )
347     private void process( final Args args, Results results, List<Dependency> dependencies,
348                           List<RemoteRepository> repositories, DependencySelector depSelector,
349                           DependencyManager depManager, DependencyTraverser depTraverser, VersionFilter verFilter )
350     {
351         for ( Dependency dependency : dependencies )
352         {
353             processDependency( args, results, repositories, depSelector, depManager, depTraverser, verFilter,
354                                dependency );
355         }
356     }
357 
358     @SuppressWarnings( "checkstyle:parameternumber" )
359     private void processDependency( Args args, Results results, List<RemoteRepository> repositories,
360                                     DependencySelector depSelector, DependencyManager depManager,
361                                     DependencyTraverser depTraverser, VersionFilter verFilter, Dependency dependency )
362     {
363 
364         List<Artifact> relocations = Collections.emptyList();
365         processDependency( args, results, repositories, depSelector, depManager, depTraverser, verFilter, dependency,
366                            relocations, false );
367     }
368 
369     @SuppressWarnings( "checkstyle:parameternumber" )
370     private void processDependency( Args args, Results results, List<RemoteRepository> repositories,
371                                     DependencySelector depSelector, DependencyManager depManager,
372                                     DependencyTraverser depTraverser, VersionFilter verFilter, Dependency dependency,
373                                     List<Artifact> relocations, boolean disableVersionManagement )
374     {
375 
376         if ( depSelector != null && !depSelector.selectDependency( dependency ) )
377         {
378             return;
379         }
380 
381         PremanagedDependency preManaged =
382             PremanagedDependency.create( depManager, dependency, disableVersionManagement, args.premanagedState );
383         dependency = preManaged.managedDependency;
384 
385         boolean noDescriptor = isLackingDescriptor( dependency.getArtifact() );
386 
387         boolean traverse = !noDescriptor && ( depTraverser == null || depTraverser.traverseDependency( dependency ) );
388 
389         List<? extends Version> versions;
390         VersionRangeResult rangeResult;
391         try
392         {
393             VersionRangeRequest rangeRequest = createVersionRangeRequest( args, repositories, dependency );
394 
395             rangeResult = cachedResolveRangeResult( rangeRequest, args.pool, args.session );
396 
397             versions = filterVersions( dependency, rangeResult, verFilter, args.versionContext );
398         }
399         catch ( VersionRangeResolutionException e )
400         {
401             results.addException( dependency, e, args.nodes );
402             return;
403         }
404 
405         for ( Version version : versions )
406         {
407             Artifact originalArtifact = dependency.getArtifact().setVersion( version.toString() );
408             Dependency d = dependency.setArtifact( originalArtifact );
409 
410             ArtifactDescriptorRequest descriptorRequest = createArtifactDescriptorRequest( args, repositories, d );
411 
412             final ArtifactDescriptorResult descriptorResult =
413                 getArtifactDescriptorResult( args, results, noDescriptor, d, descriptorRequest );
414             if ( descriptorResult != null )
415             {
416                 d = d.setArtifact( descriptorResult.getArtifact() );
417 
418                 DependencyNode node = args.nodes.top();
419 
420                 int cycleEntry = args.nodes.find( d.getArtifact() );
421                 if ( cycleEntry >= 0 )
422                 {
423                     results.addCycle( args.nodes, cycleEntry, d );
424                     DependencyNode cycleNode = args.nodes.get( cycleEntry );
425                     if ( cycleNode.getDependency() != null )
426                     {
427                         DefaultDependencyNode child =
428                             createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult,
429                                                   cycleNode );
430                         node.getChildren().add( child );
431                         continue;
432                     }
433                 }
434 
435                 if ( !descriptorResult.getRelocations().isEmpty() )
436                 {
437                     boolean disableVersionManagementSubsequently =
438                         originalArtifact.getGroupId().equals( d.getArtifact().getGroupId() )
439                             && originalArtifact.getArtifactId().equals( d.getArtifact().getArtifactId() );
440 
441                     processDependency( args, results, repositories, depSelector, depManager, depTraverser, verFilter, d,
442                                        descriptorResult.getRelocations(), disableVersionManagementSubsequently );
443                     return;
444                 }
445                 else
446                 {
447                     d = args.pool.intern( d.setArtifact( args.pool.intern( d.getArtifact() ) ) );
448 
449                     List<RemoteRepository> repos =
450                         getRemoteRepositories( rangeResult.getRepository( version ), repositories );
451 
452                     DefaultDependencyNode child =
453                         createDependencyNode( relocations, preManaged, rangeResult, version, d,
454                                               descriptorResult.getAliases(), repos, args.request.getRequestContext() );
455 
456                     node.getChildren().add( child );
457 
458                     boolean recurse = traverse && !descriptorResult.getDependencies().isEmpty();
459                     if ( recurse )
460                     {
461                         doRecurse( args, results, repositories, depSelector, depManager, depTraverser, verFilter, d,
462                                    descriptorResult, child );
463                     }
464                 }
465             }
466             else
467             {
468                 DependencyNode node = args.nodes.top();
469                 List<RemoteRepository> repos =
470                     getRemoteRepositories( rangeResult.getRepository( version ), repositories );
471                 DefaultDependencyNode child =
472                     createDependencyNode( relocations, preManaged, rangeResult, version, d, null, repos,
473                                           args.request.getRequestContext() );
474                 node.getChildren().add( child );
475             }
476         }
477     }
478 
479     @SuppressWarnings( "checkstyle:parameternumber" )
480     private void doRecurse( Args args, Results results, List<RemoteRepository> repositories,
481                             DependencySelector depSelector, DependencyManager depManager,
482                             DependencyTraverser depTraverser, VersionFilter verFilter, Dependency d,
483                             ArtifactDescriptorResult descriptorResult, DefaultDependencyNode child )
484     {
485         DefaultDependencyCollectionContext context = args.collectionContext;
486         context.set( d, descriptorResult.getManagedDependencies() );
487 
488         DependencySelector childSelector = depSelector != null ? depSelector.deriveChildSelector( context ) : null;
489         DependencyManager childManager = depManager != null ? depManager.deriveChildManager( context ) : null;
490         DependencyTraverser childTraverser = depTraverser != null ? depTraverser.deriveChildTraverser( context ) : null;
491         VersionFilter childFilter = verFilter != null ? verFilter.deriveChildFilter( context ) : null;
492 
493         final List<RemoteRepository> childRepos =
494             args.ignoreRepos
495                 ? repositories
496                 : remoteRepositoryManager.aggregateRepositories( args.session, repositories,
497                                                                  descriptorResult.getRepositories(), true );
498 
499         Object key =
500             args.pool.toKey( d.getArtifact(), childRepos, childSelector, childManager, childTraverser, childFilter );
501 
502         List<DependencyNode> children = args.pool.getChildren( key );
503         if ( children == null )
504         {
505             args.pool.putChildren( key, child.getChildren() );
506 
507             args.nodes.push( child );
508 
509             process( args, results, descriptorResult.getDependencies(), childRepos, childSelector, childManager,
510                      childTraverser, childFilter );
511 
512             args.nodes.pop();
513         }
514         else
515         {
516             child.setChildren( children );
517         }
518     }
519 
520     private ArtifactDescriptorResult getArtifactDescriptorResult( Args args, Results results, boolean noDescriptor,
521                                                                   Dependency d,
522                                                                   ArtifactDescriptorRequest descriptorRequest )
523     {
524         return noDescriptor
525                    ? new ArtifactDescriptorResult( descriptorRequest )
526                    : resolveCachedArtifactDescriptor( args.pool, descriptorRequest, args.session, d, results, args );
527 
528     }
529 
530     private ArtifactDescriptorResult resolveCachedArtifactDescriptor( DataPool pool,
531                                                                       ArtifactDescriptorRequest descriptorRequest,
532                                                                       RepositorySystemSession session, Dependency d,
533                                                                       Results results, Args args )
534     {
535         Object key = pool.toKey( descriptorRequest );
536         ArtifactDescriptorResult descriptorResult = pool.getDescriptor( key, descriptorRequest );
537         if ( descriptorResult == null )
538         {
539             try
540             {
541                 descriptorResult = descriptorReader.readArtifactDescriptor( session, descriptorRequest );
542                 pool.putDescriptor( key, descriptorResult );
543             }
544             catch ( ArtifactDescriptorException e )
545             {
546                 results.addException( d, e, args.nodes );
547                 pool.putDescriptor( key, e );
548                 return null;
549             }
550 
551         }
552         else if ( descriptorResult == DataPool.NO_DESCRIPTOR )
553         {
554             return null;
555         }
556 
557         return descriptorResult;
558     }
559 
560     @SuppressWarnings( "checkstyle:parameternumber" )
561     private static DefaultDependencyNode createDependencyNode( List<Artifact> relocations,
562                                                                PremanagedDependency preManaged,
563                                                                VersionRangeResult rangeResult, Version version,
564                                                                Dependency d, Collection<Artifact> aliases,
565                                                                List<RemoteRepository> repos, String requestContext )
566     {
567         DefaultDependencyNode child = new DefaultDependencyNode( d );
568         preManaged.applyTo( child );
569         child.setRelocations( relocations );
570         child.setVersionConstraint( rangeResult.getVersionConstraint() );
571         child.setVersion( version );
572         child.setAliases( aliases );
573         child.setRepositories( repos );
574         child.setRequestContext( requestContext );
575         return child;
576     }
577 
578     private static DefaultDependencyNode createDependencyNode( List<Artifact> relocations,
579                                                                PremanagedDependency preManaged,
580                                                                VersionRangeResult rangeResult, Version version,
581                                                                Dependency d, ArtifactDescriptorResult descriptorResult,
582                                                                DependencyNode cycleNode )
583     {
584         DefaultDependencyNode child =
585             createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult.getAliases(),
586                                   cycleNode.getRepositories(), cycleNode.getRequestContext() );
587         child.setChildren( cycleNode.getChildren() );
588         return child;
589     }
590 
591     private static ArtifactDescriptorRequest createArtifactDescriptorRequest( Args args,
592                                                                               List<RemoteRepository> repositories,
593                                                                               Dependency d )
594     {
595         ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
596         descriptorRequest.setArtifact( d.getArtifact() );
597         descriptorRequest.setRepositories( repositories );
598         descriptorRequest.setRequestContext( args.request.getRequestContext() );
599         descriptorRequest.setTrace( args.trace );
600         return descriptorRequest;
601     }
602 
603     private static VersionRangeRequest createVersionRangeRequest( Args args, List<RemoteRepository> repositories,
604                                                                   Dependency dependency )
605     {
606         VersionRangeRequest rangeRequest = new VersionRangeRequest();
607         rangeRequest.setArtifact( dependency.getArtifact() );
608         rangeRequest.setRepositories( repositories );
609         rangeRequest.setRequestContext( args.request.getRequestContext() );
610         rangeRequest.setTrace( args.trace );
611         return rangeRequest;
612     }
613 
614     private VersionRangeResult cachedResolveRangeResult( VersionRangeRequest rangeRequest, DataPool pool,
615                                                          RepositorySystemSession session )
616         throws VersionRangeResolutionException
617     {
618         Object key = pool.toKey( rangeRequest );
619         VersionRangeResult rangeResult = pool.getConstraint( key, rangeRequest );
620         if ( rangeResult == null )
621         {
622             rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest );
623             pool.putConstraint( key, rangeResult );
624         }
625         return rangeResult;
626     }
627 
628     private static boolean isLackingDescriptor( Artifact artifact )
629     {
630         return artifact.getProperty( ArtifactProperties.LOCAL_PATH, null ) != null;
631     }
632 
633     private static List<RemoteRepository> getRemoteRepositories( ArtifactRepository repository,
634                                                                  List<RemoteRepository> repositories )
635     {
636         if ( repository instanceof RemoteRepository )
637         {
638             return Collections.singletonList( (RemoteRepository) repository );
639         }
640         if ( repository != null )
641         {
642             return Collections.emptyList();
643         }
644         return repositories;
645     }
646 
647     private static List<? extends Version> filterVersions( Dependency dependency, VersionRangeResult rangeResult,
648                                                            VersionFilter verFilter,
649                                                            DefaultVersionFilterContext verContext )
650         throws VersionRangeResolutionException
651     {
652         if ( rangeResult.getVersions().isEmpty() )
653         {
654             throw new VersionRangeResolutionException( rangeResult,
655                                                        "No versions available for " + dependency.getArtifact()
656                                                            + " within specified range" );
657         }
658 
659         List<? extends Version> versions;
660         if ( verFilter != null && rangeResult.getVersionConstraint().getRange() != null )
661         {
662             verContext.set( dependency, rangeResult );
663             try
664             {
665                 verFilter.filterVersions( verContext );
666             }
667             catch ( RepositoryException e )
668             {
669                 throw new VersionRangeResolutionException( rangeResult,
670                                                            "Failed to filter versions for " + dependency.getArtifact()
671                                                                + ": " + e.getMessage(), e );
672             }
673             versions = verContext.get();
674             if ( versions.isEmpty() )
675             {
676                 throw new VersionRangeResolutionException( rangeResult,
677                                                            "No acceptable versions for " + dependency.getArtifact()
678                                                                + ": " + rangeResult.getVersions() );
679             }
680         }
681         else
682         {
683             versions = rangeResult.getVersions();
684         }
685         return versions;
686     }
687 
688     static class Args
689     {
690 
691         final RepositorySystemSession session;
692 
693         final boolean ignoreRepos;
694 
695         final boolean premanagedState;
696 
697         final RequestTrace trace;
698 
699         final DataPool pool;
700 
701         final NodeStack nodes;
702 
703         final DefaultDependencyCollectionContext collectionContext;
704 
705         final DefaultVersionFilterContext versionContext;
706 
707         final CollectRequest request;
708 
709         Args( RepositorySystemSession session, RequestTrace trace, DataPool pool, NodeStack nodes,
710                      DefaultDependencyCollectionContext collectionContext, DefaultVersionFilterContext versionContext,
711                      CollectRequest request )
712         {
713             this.session = session;
714             this.request = request;
715             this.ignoreRepos = session.isIgnoreArtifactDescriptorRepositories();
716             this.premanagedState = ConfigUtils.getBoolean( session, false, DependencyManagerUtils.CONFIG_PROP_VERBOSE );
717             this.trace = trace;
718             this.pool = pool;
719             this.nodes = nodes;
720             this.collectionContext = collectionContext;
721             this.versionContext = versionContext;
722         }
723 
724     }
725 
726     static class Results
727     {
728 
729         private final CollectResult result;
730 
731         final int maxExceptions;
732 
733         final int maxCycles;
734 
735         String errorPath;
736 
737         Results( CollectResult result, RepositorySystemSession session )
738         {
739             this.result = result;
740 
741             maxExceptions =
742                     ConfigUtils.getInteger( session, CONFIG_PROP_MAX_EXCEPTIONS_DEFAULT, CONFIG_PROP_MAX_EXCEPTIONS );
743 
744             maxCycles = ConfigUtils.getInteger( session, CONFIG_PROP_MAX_CYCLES_DEFAULT, CONFIG_PROP_MAX_CYCLES );
745         }
746 
747         public void addException( Dependency dependency, Exception e, NodeStack nodes )
748         {
749             if ( maxExceptions < 0 || result.getExceptions().size() < maxExceptions )
750             {
751                 result.addException( e );
752                 if ( errorPath == null )
753                 {
754                     StringBuilder buffer = new StringBuilder( 256 );
755                     for ( int i = 0; i < nodes.size(); i++ )
756                     {
757                         if ( buffer.length() > 0 )
758                         {
759                             buffer.append( " -> " );
760                         }
761                         Dependency dep = nodes.get( i ).getDependency();
762                         if ( dep != null )
763                         {
764                             buffer.append( dep.getArtifact() );
765                         }
766                     }
767                     if ( buffer.length() > 0 )
768                     {
769                         buffer.append( " -> " );
770                     }
771                     buffer.append( dependency.getArtifact() );
772                     errorPath = buffer.toString();
773                 }
774             }
775         }
776 
777         public void addCycle( NodeStack nodes, int cycleEntry, Dependency dependency )
778         {
779             if ( maxCycles < 0 || result.getCycles().size() < maxCycles )
780             {
781                 result.addCycle( new DefaultDependencyCycle( nodes, cycleEntry, dependency ) );
782             }
783         }
784 
785     }
786 
787     static class PremanagedDependency
788     {
789 
790         final String premanagedVersion;
791 
792         final String premanagedScope;
793 
794         final Boolean premanagedOptional;
795 
796         /**
797          * @since 1.1.0
798          */
799         final Collection<Exclusion> premanagedExclusions;
800 
801         /**
802          * @since 1.1.0
803          */
804         final Map<String, String> premanagedProperties;
805 
806         final int managedBits;
807 
808         final Dependency managedDependency;
809 
810         final boolean premanagedState;
811 
812         @SuppressWarnings( "checkstyle:parameternumber" )
813         PremanagedDependency( String premanagedVersion, String premanagedScope, Boolean premanagedOptional,
814                               Collection<Exclusion> premanagedExclusions, Map<String, String> premanagedProperties,
815                               int managedBits, Dependency managedDependency, boolean premanagedState )
816         {
817             this.premanagedVersion = premanagedVersion;
818             this.premanagedScope = premanagedScope;
819             this.premanagedOptional = premanagedOptional;
820             this.premanagedExclusions =
821                 premanagedExclusions != null
822                     ? Collections.unmodifiableCollection( new ArrayList<>( premanagedExclusions ) )
823                     : null;
824 
825             this.premanagedProperties =
826                 premanagedProperties != null
827                     ? Collections.unmodifiableMap( new HashMap<>( premanagedProperties ) )
828                     : null;
829 
830             this.managedBits = managedBits;
831             this.managedDependency = managedDependency;
832             this.premanagedState = premanagedState;
833         }
834 
835         static PremanagedDependency create( DependencyManager depManager, Dependency dependency,
836                                             boolean disableVersionManagement, boolean premanagedState )
837         {
838             DependencyManagement depMngt = depManager != null ? depManager.manageDependency( dependency ) : null;
839 
840             int managedBits = 0;
841             String premanagedVersion = null;
842             String premanagedScope = null;
843             Boolean premanagedOptional = null;
844             Collection<Exclusion> premanagedExclusions = null;
845             Map<String, String> premanagedProperties = null;
846 
847             if ( depMngt != null )
848             {
849                 if ( depMngt.getVersion() != null && !disableVersionManagement )
850                 {
851                     Artifact artifact = dependency.getArtifact();
852                     premanagedVersion = artifact.getVersion();
853                     dependency = dependency.setArtifact( artifact.setVersion( depMngt.getVersion() ) );
854                     managedBits |= DependencyNode.MANAGED_VERSION;
855                 }
856                 if ( depMngt.getProperties() != null )
857                 {
858                     Artifact artifact = dependency.getArtifact();
859                     premanagedProperties = artifact.getProperties();
860                     dependency = dependency.setArtifact( artifact.setProperties( depMngt.getProperties() ) );
861                     managedBits |= DependencyNode.MANAGED_PROPERTIES;
862                 }
863                 if ( depMngt.getScope() != null )
864                 {
865                     premanagedScope = dependency.getScope();
866                     dependency = dependency.setScope( depMngt.getScope() );
867                     managedBits |= DependencyNode.MANAGED_SCOPE;
868                 }
869                 if ( depMngt.getOptional() != null )
870                 {
871                     premanagedOptional = dependency.isOptional();
872                     dependency = dependency.setOptional( depMngt.getOptional() );
873                     managedBits |= DependencyNode.MANAGED_OPTIONAL;
874                 }
875                 if ( depMngt.getExclusions() != null )
876                 {
877                     premanagedExclusions = dependency.getExclusions();
878                     dependency = dependency.setExclusions( depMngt.getExclusions() );
879                     managedBits |= DependencyNode.MANAGED_EXCLUSIONS;
880                 }
881             }
882             return new PremanagedDependency( premanagedVersion, premanagedScope, premanagedOptional,
883                                              premanagedExclusions, premanagedProperties, managedBits, dependency,
884                                              premanagedState );
885 
886         }
887 
888         public void applyTo( DefaultDependencyNode child )
889         {
890             child.setManagedBits( managedBits );
891             if ( premanagedState )
892             {
893                 child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_VERSION, premanagedVersion );
894                 child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_SCOPE, premanagedScope );
895                 child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_OPTIONAL, premanagedOptional );
896                 child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_EXCLUSIONS, premanagedExclusions );
897                 child.setData( DependencyManagerUtils.NODE_DATA_PREMANAGED_PROPERTIES, premanagedProperties );
898             }
899         }
900 
901     }
902 
903 }