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