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 static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.addDependencyNode;
23  import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.createArtifactDescriptorRequest;
24  import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.createDependencyNode;
25  import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.createVersionRangeRequest;
26  import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.filterVersions;
27  
28  import java.util.ArrayList;
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.HashSet;
32  import java.util.LinkedHashMap;
33  import java.util.List;
34  import java.util.Map;
35  import static java.util.Objects.requireNonNull;
36  import java.util.concurrent.Callable;
37  import java.util.concurrent.ExecutionException;
38  import java.util.concurrent.ExecutorService;
39  import java.util.concurrent.Future;
40  import java.util.concurrent.LinkedBlockingQueue;
41  import java.util.concurrent.ThreadPoolExecutor;
42  import java.util.concurrent.TimeUnit;
43  
44  import javax.inject.Inject;
45  import javax.inject.Named;
46  
47  import org.eclipse.aether.RepositoryException;
48  import org.eclipse.aether.RepositorySystemSession;
49  import org.eclipse.aether.RequestTrace;
50  import org.eclipse.aether.artifact.Artifact;
51  import org.eclipse.aether.artifact.ArtifactProperties;
52  import org.eclipse.aether.collection.CollectRequest;
53  import org.eclipse.aether.collection.CollectResult;
54  import org.eclipse.aether.collection.DependencyCollectionException;
55  import org.eclipse.aether.collection.DependencyGraphTransformer;
56  import org.eclipse.aether.collection.DependencyTraverser;
57  import org.eclipse.aether.graph.DefaultDependencyNode;
58  import org.eclipse.aether.graph.Dependency;
59  import org.eclipse.aether.graph.DependencyNode;
60  import org.eclipse.aether.impl.ArtifactDescriptorReader;
61  import org.eclipse.aether.impl.DependencyCollector;
62  import org.eclipse.aether.impl.RemoteRepositoryManager;
63  import org.eclipse.aether.impl.VersionRangeResolver;
64  import org.eclipse.aether.repository.ArtifactRepository;
65  import org.eclipse.aether.repository.RemoteRepository;
66  import org.eclipse.aether.resolution.ArtifactDescriptorException;
67  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
68  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
69  import org.eclipse.aether.resolution.VersionRangeRequest;
70  import org.eclipse.aether.resolution.VersionRangeResolutionException;
71  import org.eclipse.aether.resolution.VersionRangeResult;
72  import org.eclipse.aether.spi.locator.Service;
73  import org.eclipse.aether.spi.locator.ServiceLocator;
74  import org.eclipse.aether.util.ConfigUtils;
75  import org.eclipse.aether.util.concurrency.FutureResult;
76  import org.eclipse.aether.util.concurrency.WorkerThreadFactory;
77  import org.eclipse.aether.util.graph.transformer.TransformationContextKeys;
78  import org.eclipse.aether.version.Version;
79  import org.slf4j.Logger;
80  import org.slf4j.LoggerFactory;
81  
82  /**
83   */
84  @Named
85  public class DefaultDependencyCollector
86      implements DependencyCollector, Service
87  {
88  
89      static final String CONFIG_PROP_MAX_EXCEPTIONS = "aether.dependencyCollector.maxExceptions";
90  
91      static final String CONFIG_PROP_MAX_CYCLES = "aether.dependencyCollector.maxCycles";
92  
93      private static final String CONFIG_PROP_THREADS = "aether.artifactDescriptor.threads";
94      private static final int DEFAULT_THREADS = 5;
95  
96      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultDependencyCollector.class );
97  
98      private RemoteRepositoryManager remoteRepositoryManager;
99  
100     private ArtifactDescriptorReader descriptorReader;
101 
102     private VersionRangeResolver versionRangeResolver;
103 
104     public DefaultDependencyCollector()
105     {
106         // enables default constructor
107     }
108 
109     @Inject
110     DefaultDependencyCollector( RemoteRepositoryManager remoteRepositoryManager,
111                                 ArtifactDescriptorReader artifactDescriptorReader,
112                                 VersionRangeResolver versionRangeResolver )
113     {
114         setRemoteRepositoryManager( remoteRepositoryManager );
115         setArtifactDescriptorReader( artifactDescriptorReader );
116         setVersionRangeResolver( versionRangeResolver );
117     }
118 
119     public void initService( ServiceLocator locator )
120     {
121         setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
122         setArtifactDescriptorReader( locator.getService( ArtifactDescriptorReader.class ) );
123         setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) );
124     }
125 
126     public DefaultDependencyCollector setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
127     {
128         this.remoteRepositoryManager = requireNonNull(
129                 remoteRepositoryManager, "remote repository provider cannot be null" );
130         return this;
131     }
132 
133     public DefaultDependencyCollector setArtifactDescriptorReader( ArtifactDescriptorReader artifactDescriptorReader )
134     {
135         descriptorReader = requireNonNull( artifactDescriptorReader, "artifact descriptor reader cannot be null" );
136         return this;
137     }
138 
139     public DefaultDependencyCollector setVersionRangeResolver( VersionRangeResolver versionRangeResolver )
140     {
141         this.versionRangeResolver = requireNonNull( versionRangeResolver, "version range resolver cannot be null" );
142         return this;
143     }
144 
145     public CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request )
146         throws DependencyCollectionException
147     {
148         int numThreads = ConfigUtils.getInteger( session, DEFAULT_THREADS, CONFIG_PROP_THREADS );
149         LOGGER.debug( "{} = {} ", CONFIG_PROP_THREADS, numThreads );
150         ThreadPoolExecutor executor = new ThreadPoolExecutor(
151                 numThreads, numThreads, 3L, TimeUnit.SECONDS,
152                 new LinkedBlockingQueue<Runnable>(), new WorkerThreadFactory( "artifact-descriptor-resolver" ) );
153         try
154         {
155             return collectDependenciesWithExecutor( session, request, executor );
156         }
157         finally
158         {
159             executor.shutdown();
160         }
161     }
162 
163     private CollectResult collectDependenciesWithExecutor( RepositorySystemSession session, CollectRequest request,
164                                                            ExecutorService executor )
165         throws DependencyCollectionException
166     {
167         session = DependencyCollectionUtils.optimizeSession( session );
168 
169         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
170 
171         CollectResult result = new CollectResult( request );
172 
173         Dependency root = request.getRoot();
174         List<RemoteRepository> repositories = request.getRepositories();
175         List<Dependency> managedDependencies = request.getManagedDependencies();
176 
177         DefaultDependencyCollectionContext context =
178                 new DefaultDependencyCollectionContext( session, request.getRootArtifact(), root, managedDependencies );
179         context.setDependencies( request.getDependencies() );
180         context.setCollectResult( result );
181         context.setTrace( trace );
182 
183         Args args = new Args( session, trace, null, null, context, null, request, executor );
184         context.setArgs( args );
185 
186         Map<String, Object> stats = LOGGER.isDebugEnabled() ? new LinkedHashMap<String, Object>() : null;
187         long time1 = System.nanoTime();
188 
189         DefaultDependencyNode node;
190         if ( root != null )
191         {
192 
193             VersionRangeResult rangeResult = resolveRootVersionRange( context );
194             ArtifactDescriptorResult descriptorResult = readRootArtifactDescriptor( context );
195             root = root.setArtifact( descriptorResult.getArtifact() );
196 
197             if ( !session.isIgnoreArtifactDescriptorRepositories() )
198             {
199                 repositories = remoteRepositoryManager.aggregateRepositories( session, repositories,
200                                                                               descriptorResult.getRepositories(),
201                                                                               true );
202             }
203             context.setDependencies( mergeDeps( context.getDependencies(), descriptorResult.getDependencies() ) );
204             context.setManagedDependencies( mergeDeps( managedDependencies,
205                     descriptorResult.getManagedDependencies() ) );
206 
207             node = new DefaultDependencyNode( root );
208             node.setRequestContext( request.getRequestContext() );
209             node.setRelocations( descriptorResult.getRelocations() );
210             node.setVersionConstraint( rangeResult.getVersionConstraint() );
211             node.setVersion( context.getVersion() );
212             node.setAliases( descriptorResult.getAliases() );
213             node.setRepositories( request.getRepositories() );
214         }
215         else
216         {
217             node = new DefaultDependencyNode( request.getRootArtifact() );
218             node.setRequestContext( request.getRequestContext() );
219             node.setRepositories( request.getRepositories() );
220         }
221 
222         result.setRoot( node );
223 
224         DependencyTraverser depTraverser = session.getDependencyTraverser();
225         boolean traverse = root == null || depTraverser == null || depTraverser.traverseDependency( root );
226         String errorPath = null;
227         if ( traverse && !context.getDependencies().isEmpty() )
228         {
229             DataPool pool = new DataPool( session );
230 
231             NodeStack nodes = new NodeStack();
232             nodes.push( node );
233 
234             DefaultVersionFilterContext versionContext = new DefaultVersionFilterContext( session );
235 
236             args = new Args( session, trace, pool, nodes, context, versionContext, request, executor );
237             Results results = new Results( result, session );
238             context.setArgs( args );
239             context.setResults( results );
240             context.setRepositories( repositories );
241             context.setDepTraverser( depTraverser );
242             context.prepareDescent();
243 
244             process( context );
245 
246             errorPath = results.errorPath;
247         }
248 
249         long time2 = System.nanoTime();
250 
251         transformDependencyGraph( context, stats );
252 
253         if ( stats != null )
254         {
255             long time3 = System.nanoTime();
256             stats.put( "DefaultDependencyCollector.collectTime", time2 - time1 );
257             stats.put( "DefaultDependencyCollector.transformTime", time3 - time2 );
258             LOGGER.debug( "Dependency collection stats: {}", stats );
259         }
260 
261         if ( errorPath != null )
262         {
263             throw new DependencyCollectionException( result, "Failed to collect dependencies at " + errorPath );
264         }
265         if ( !result.getExceptions().isEmpty() )
266         {
267             throw new DependencyCollectionException( result );
268         }
269 
270         return result;
271     }
272 
273     private VersionRangeResult resolveRootVersionRange( DefaultDependencyCollectionContext context )
274         throws DependencyCollectionException
275     {
276         CollectRequest request = context.getArgs().request;
277         RepositorySystemSession session = context.getSession();
278         List<? extends Version> versions;
279         VersionRangeResult rangeResult;
280         Artifact artifact = request.getRoot().getArtifact();
281         try
282         {
283             VersionRangeRequest rangeRequest =
284                     new VersionRangeRequest( artifact, request.getRepositories(), request.getRequestContext() );
285             rangeRequest.setTrace( context.getTrace() );
286             rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest );
287             versions = filterVersions( context.getDependency(), rangeResult, context.getVerFilter(),
288                     new DefaultVersionFilterContext( session ) );
289         }
290         catch ( VersionRangeResolutionException e )
291         {
292             context.getCollectResult().addException( e );
293             throw new DependencyCollectionException( context.getCollectResult(), e.getMessage() );
294         }
295 
296         Version version = versions.get( versions.size() - 1 );
297         context.setVersion( version );
298         context.setDependency( request.getRoot().setArtifact( artifact.setVersion( version.toString() ) ) );
299         return rangeResult;
300     }
301 
302     private ArtifactDescriptorResult readRootArtifactDescriptor( DefaultDependencyCollectionContext context )
303         throws DependencyCollectionException
304     {
305         CollectRequest request = context.getArgs().request;
306         Artifact artifact = request.getRoot().getArtifact();
307         try
308         {
309             ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
310             descriptorRequest.setArtifact( artifact );
311             descriptorRequest.setRepositories( request.getRepositories() );
312             descriptorRequest.setRequestContext( request.getRequestContext() );
313             descriptorRequest.setTrace( context.getTrace() );
314 
315             ArtifactDescriptorResult descriptorResult =
316                     isLackingDescriptor( artifact ) ? new ArtifactDescriptorResult( descriptorRequest )
317                             : descriptorReader.readArtifactDescriptor( context.getSession(), descriptorRequest );
318             context.setDependency( request.getRoot().setArtifact( descriptorResult.getArtifact() ) );
319             return descriptorResult;
320         }
321         catch ( ArtifactDescriptorException e )
322         {
323             context.getCollectResult().addException( e );
324             throw new DependencyCollectionException( context.getCollectResult(), e.getMessage() );
325         }
326     }
327 
328     private void transformDependencyGraph( DefaultDependencyCollectionContext context, Map<String, Object> stats )
329     {
330         RepositorySystemSession session = context.getSession();
331         DependencyGraphTransformer transformer = session.getDependencyGraphTransformer();
332         if ( transformer != null )
333         {
334             try
335             {
336                 DefaultDependencyGraphTransformationContext tfContext =
337                         new DefaultDependencyGraphTransformationContext( session );
338                 tfContext.put( TransformationContextKeys.STATS, stats );
339                 context.getCollectResult().setRoot( transformer.transformGraph( context.getCollectResult().getRoot(),
340                         tfContext ) );
341             }
342             catch ( RepositoryException e )
343             {
344                 context.getCollectResult().addException( e );
345             }
346         }
347     }
348 
349     private List<Dependency> mergeDeps( List<Dependency> dominant, List<Dependency> recessive )
350     {
351         List<Dependency> result;
352         if ( dominant == null || dominant.isEmpty() )
353         {
354             result = recessive;
355         }
356         else if ( recessive == null || recessive.isEmpty() )
357         {
358             result = dominant;
359         }
360         else
361         {
362             int initialCapacity = dominant.size() + recessive.size();
363             result = new ArrayList<>( initialCapacity );
364             Collection<String> ids = new HashSet<>( initialCapacity, 1.0f );
365             for ( Dependency dependency : dominant )
366             {
367                 ids.add( getId( dependency.getArtifact() ) );
368                 result.add( dependency );
369             }
370             for ( Dependency dependency : recessive )
371             {
372                 if ( !ids.contains( getId( dependency.getArtifact() ) ) )
373                 {
374                     result.add( dependency );
375                 }
376             }
377         }
378         return result;
379     }
380 
381     private static String getId( Artifact a )
382     {
383         return a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getClassifier() + ':' + a.getExtension();
384     }
385 
386     private void process( DefaultDependencyCollectionContext context )
387     {
388         List<DependencyContext> depContexts = new ArrayList<>();
389         for ( Dependency d : context.getDependencies() )
390         {
391             depContexts.add( new DependencyContext( context, d ) );
392         }
393 
394         List<Future<DependencyContext>> futures = new ArrayList<>();
395         for ( DependencyContext dc : depContexts )
396         {
397             futures.add( asyncProcessDependency( dc ) );
398         }
399         int pos = 0;
400         for ( Future<DependencyContext> future : futures )
401         {
402             try
403             {
404                 processDependencyNode( future.get() );
405             }
406             catch ( ExecutionException e )
407             {
408                 context.getResults().addException( context.getDependencies().get( pos ), (Exception) e.getCause(),
409                         context.getArgs().nodes );
410             }
411             catch ( InterruptedException e )
412             {
413                 context.getResults().addException( context.getDependencies().get( pos ), e, context.getArgs().nodes );
414             }
415             pos++;
416         }
417     }
418 
419     private Future<DependencyContext> asyncProcessDependency( final DependencyContext dc )
420     {
421         return dc.args.executor.submit( new Callable<DependencyContext>()
422         {
423             public DependencyContext call()
424             {
425                 return processDependency( dc );
426             }
427         } );
428     }
429 
430     private DependencyContext processDependency( DependencyContext dc )
431     {
432         DefaultDependencyCollectionContext context = dc.context;
433         Args args = context.getArgs();
434         Results results = context.getResults();
435 
436         if ( context.getDepSelector() != null && !context.getDepSelector().selectDependency( dc.origDependency ) )
437         {
438             return null;
439         }
440 
441         PremanagedDependency preManaged =
442                 PremanagedDependency.create( context.getDepManager(), dc.origDependency, dc.disableVersionManagement,
443                                              args.premanagedState );
444         Dependency dependency = preManaged.managedDependency;
445 
446         boolean noDescriptor = isLackingDescriptor( dependency.getArtifact() );
447 
448         boolean traverse = !noDescriptor
449                 && ( context.getDepTraverser() == null || context.getDepTraverser().traverseDependency( dependency ) );
450 
451         try
452         {
453             VersionRangeRequest rangeRequest = createVersionRangeRequest( args, context.getRepositories(), dependency );
454             VersionRangeResult rangeResult = cachedResolveRangeResult( rangeRequest, args.pool, args.session );
455             for ( Version version : filterVersions( dependency, rangeResult, context.getVerFilter(),
456                                                     args.versionContext ) )
457             {
458 
459                 Artifact originalArtifact = dependency.getArtifact().setVersion( version.toString() );
460                 Dependency d = dependency.setArtifact( originalArtifact );
461 
462                 ArtifactDescriptorRequest descriptorRequest =
463                         createArtifactDescriptorRequest( args, context.getRepositories(), d );
464 
465                 dc.args = args;
466                 dc.preManaged = preManaged;
467                 dc.traverse = traverse;
468                 dc.rangeResult = rangeResult;
469                 dc.version = version;
470                 dc.originalArtifact = originalArtifact;
471                 dc.managedDependency = d;
472                 dc.futureDescriptorResult =
473                         getArtifactDescriptorResult( args, results, noDescriptor, d, descriptorRequest );
474             }
475         }
476         catch ( VersionRangeResolutionException e )
477         {
478             results.addException( dependency, e, args.nodes );
479         }
480         return dc;
481     }
482 
483     private void processDependencyNode( DependencyContext dc )
484     {
485         if ( dc == null )
486         {
487             return;
488         }
489         try
490         {
491             boolean noResult = dc.futureDescriptorResult == null;
492             if ( !noResult )
493             {
494                 dc.descriptorResult = dc.futureDescriptorResult.get();
495                 noResult = dc.descriptorResult == null;
496             }
497             if ( noResult )
498             {
499                 List<RemoteRepository> repos =
500                       getRemoteRepositories( dc.rangeResult.getRepository( dc.version ), dc.context.getRepositories() );
501                 addDependencyNode( dc.args.nodes.top(), dc.relocations, dc.preManaged, dc.rangeResult, dc.version,
502                                    dc.managedDependency, null, repos, dc.args.request.getRequestContext() );
503             }
504             else
505             {
506                 processDependencyVersion( dc );
507             }
508         }
509         catch ( InterruptedException e )
510         {
511             dc.context.getResults().addException( dc.preManaged.managedDependency, e, dc.args.nodes );
512         }
513         catch ( ExecutionException e )
514         {
515             dc.context.getResults().addException( dc.preManaged.managedDependency, (Exception) e.getCause(),
516                                                   dc.args.nodes );
517         }
518     }
519 
520     private boolean processDependencyVersion( DependencyContext dc )
521     {
522         Args args = dc.context.getArgs();
523         Results results = dc.context.getResults();
524         Dependency d = dc.managedDependency.setArtifact( dc.descriptorResult.getArtifact() );
525         dc.managedDependency = d;
526 
527         DependencyNode node = args.nodes.top();
528 
529         int cycleEntry = args.nodes.find( d.getArtifact() );
530         if ( cycleEntry >= 0 )
531         {
532             results.addCycle( args.nodes, cycleEntry, d );
533             DependencyNode cycleNode = args.nodes.get( cycleEntry );
534             if ( cycleNode.getDependency() != null )
535             {
536                 createDependencyNode( node, dc.relocations, dc.preManaged, dc.rangeResult, dc.version, d,
537                                       dc.descriptorResult, cycleNode );
538                 return true;
539             }
540         }
541 
542         if ( !dc.descriptorResult.getRelocations().isEmpty() )
543         {
544             boolean disableVersionManagementSubsequently =
545                     dc.originalArtifact.getGroupId().equals( d.getArtifact().getGroupId() )
546                             && dc.originalArtifact.getArtifactId().equals( d.getArtifact().getArtifactId() );
547 
548             DependencyContext dc2 = new DependencyContext();
549             dc2.context = dc.context;
550             dc2.origDependency = d;
551             dc2.relocations = dc.descriptorResult.getRelocations();
552             dc2.disableVersionManagement = disableVersionManagementSubsequently;
553             dc2 = processDependency( dc2 );
554             processDependencyNode( dc2 );
555             return true;
556         }
557         else
558         {
559             d = args.pool.intern( d );
560 
561             List<RemoteRepository> repos =
562                     getRemoteRepositories( dc.rangeResult.getRepository( dc.version ), dc.context.getRepositories() );
563 
564             DefaultDependencyNode child =
565                     addDependencyNode( node, dc.relocations, dc.preManaged, dc.rangeResult, dc.version, d,
566                                        dc.descriptorResult.getAliases(), repos, args.request.getRequestContext() );
567 
568             if ( dc.traverse && !dc.descriptorResult.getDependencies().isEmpty() )
569             {
570                 doRecurse( dc.context, d, dc.descriptorResult, child );
571             }
572             return false;
573         }
574     }
575 
576     private void doRecurse( DefaultDependencyCollectionContext context, Dependency d,
577                             ArtifactDescriptorResult descriptorResult, DefaultDependencyNode child )
578     {
579         context.setDependency( d );
580         context.setManagedDependencies( descriptorResult.getManagedDependencies() );
581 
582         DefaultDependencyCollectionContext childContext = context.createChildContext();
583         Args args = context.getArgs();
584 
585         final List<RemoteRepository> childRepos = args.ignoreRepos ? context.getRepositories()
586                 : remoteRepositoryManager.aggregateRepositories( args.session, context.getRepositories(),
587                 descriptorResult.getRepositories(), true );
588         childContext.setRepositories( childRepos );
589 
590         Object key = args.pool.toKey( d.getArtifact(), childContext );
591 
592         List<DependencyNode> children = args.pool.getChildren( key );
593         if ( children == null )
594         {
595             args.pool.putChildren( key, child.getChildren() );
596 
597             args.nodes.push( child );
598 
599             childContext.setArgs( args );
600             childContext.setResults( context.getResults() );
601             childContext.setDependencies( descriptorResult.getDependencies() );
602 
603             process( childContext );
604 
605             args.nodes.pop();
606         }
607         else
608         {
609             child.setChildren( children );
610         }
611     }
612 
613     private Future<ArtifactDescriptorResult> getArtifactDescriptorResult( Args args, Results results,
614                                                                           boolean noDescriptor, Dependency d,
615                                                                           ArtifactDescriptorRequest descriptorRequest )
616     {
617         return noDescriptor
618                 ? new FutureResult<>( new ArtifactDescriptorResult( descriptorRequest ) )
619                 : resolveCachedArtifactDescriptor( args.pool, descriptorRequest, args.session, d, results,
620                 args );
621     }
622 
623     private Future<ArtifactDescriptorResult> resolveCachedArtifactDescriptor(
624             final DataPool pool, final ArtifactDescriptorRequest descriptorRequest,
625             final RepositorySystemSession session, final Dependency d, final Results results, final Args args )
626     {
627         final Object key = pool.toKey( descriptorRequest );
628         Future<ArtifactDescriptorResult> descriptorResult = pool.getDescriptor( key, descriptorRequest );
629         if ( descriptorResult == null )
630         {
631             descriptorResult = args.executor.submit( new Callable<ArtifactDescriptorResult>()
632             {
633                 public ArtifactDescriptorResult call()
634                 {
635                     try
636                     {
637                         return descriptorReader.readArtifactDescriptor( session, descriptorRequest );
638                     }
639                     catch ( ArtifactDescriptorException e )
640                     {
641                         results.addException( d, e, args.nodes );
642                         pool.putDescriptor( key, e );
643                         return null;
644                     }
645                 }
646             } );
647 
648             pool.putDescriptor( key, descriptorResult );
649         }
650         else if ( descriptorResult == DataPool.NO_DESCRIPTOR )
651         {
652             return new FutureResult<>( null );
653         }
654 
655         return descriptorResult;
656     }
657     private VersionRangeResult cachedResolveRangeResult( VersionRangeRequest rangeRequest, DataPool pool,
658                                                          RepositorySystemSession session )
659         throws VersionRangeResolutionException
660     {
661         Object key = pool.toKey( rangeRequest );
662         VersionRangeResult rangeResult = pool.getConstraint( key, rangeRequest );
663         if ( rangeResult == null )
664         {
665             rangeResult = versionRangeResolver.resolveVersionRange( session, rangeRequest );
666             pool.putConstraint( key, rangeResult );
667         }
668         return rangeResult;
669     }
670 
671     private static boolean isLackingDescriptor( Artifact artifact )
672     {
673         return artifact.getProperty( ArtifactProperties.LOCAL_PATH, null ) != null;
674     }
675 
676     private static List<RemoteRepository> getRemoteRepositories( ArtifactRepository repository,
677                                                                  List<RemoteRepository> repositories )
678     {
679         if ( repository instanceof RemoteRepository )
680         {
681             return Collections.singletonList( (RemoteRepository) repository );
682         }
683         if ( repository != null )
684         {
685             return Collections.emptyList();
686         }
687         return repositories;
688     }
689 }