001package org.eclipse.aether.internal.impl.collect;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.addDependencyNode;
023import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.createArtifactDescriptorRequest;
024import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.createDependencyNode;
025import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.createVersionRangeRequest;
026import static org.eclipse.aether.internal.impl.collect.DependencyCollectionUtils.filterVersions;
027
028import java.util.ArrayList;
029import java.util.Collection;
030import java.util.Collections;
031import java.util.HashSet;
032import java.util.LinkedHashMap;
033import java.util.List;
034import java.util.Map;
035import static java.util.Objects.requireNonNull;
036import java.util.concurrent.Callable;
037import java.util.concurrent.ExecutionException;
038import java.util.concurrent.ExecutorService;
039import java.util.concurrent.Future;
040import java.util.concurrent.LinkedBlockingQueue;
041import java.util.concurrent.ThreadPoolExecutor;
042import java.util.concurrent.TimeUnit;
043
044import javax.inject.Inject;
045import javax.inject.Named;
046
047import org.eclipse.aether.RepositoryException;
048import org.eclipse.aether.RepositorySystemSession;
049import org.eclipse.aether.RequestTrace;
050import org.eclipse.aether.artifact.Artifact;
051import org.eclipse.aether.artifact.ArtifactProperties;
052import org.eclipse.aether.collection.CollectRequest;
053import org.eclipse.aether.collection.CollectResult;
054import org.eclipse.aether.collection.DependencyCollectionException;
055import org.eclipse.aether.collection.DependencyGraphTransformer;
056import org.eclipse.aether.collection.DependencyTraverser;
057import org.eclipse.aether.graph.DefaultDependencyNode;
058import org.eclipse.aether.graph.Dependency;
059import org.eclipse.aether.graph.DependencyNode;
060import org.eclipse.aether.impl.ArtifactDescriptorReader;
061import org.eclipse.aether.impl.DependencyCollector;
062import org.eclipse.aether.impl.RemoteRepositoryManager;
063import org.eclipse.aether.impl.VersionRangeResolver;
064import org.eclipse.aether.repository.ArtifactRepository;
065import org.eclipse.aether.repository.RemoteRepository;
066import org.eclipse.aether.resolution.ArtifactDescriptorException;
067import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
068import org.eclipse.aether.resolution.ArtifactDescriptorResult;
069import org.eclipse.aether.resolution.VersionRangeRequest;
070import org.eclipse.aether.resolution.VersionRangeResolutionException;
071import org.eclipse.aether.resolution.VersionRangeResult;
072import org.eclipse.aether.spi.locator.Service;
073import org.eclipse.aether.spi.locator.ServiceLocator;
074import org.eclipse.aether.util.ConfigUtils;
075import org.eclipse.aether.util.concurrency.FutureResult;
076import org.eclipse.aether.util.concurrency.WorkerThreadFactory;
077import org.eclipse.aether.util.graph.transformer.TransformationContextKeys;
078import org.eclipse.aether.version.Version;
079import org.slf4j.Logger;
080import org.slf4j.LoggerFactory;
081
082/**
083 */
084@Named
085public class DefaultDependencyCollector
086    implements DependencyCollector, Service
087{
088
089    static final String CONFIG_PROP_MAX_EXCEPTIONS = "aether.dependencyCollector.maxExceptions";
090
091    static final String CONFIG_PROP_MAX_CYCLES = "aether.dependencyCollector.maxCycles";
092
093    private static final String CONFIG_PROP_THREADS = "aether.artifactDescriptor.threads";
094    private static final int DEFAULT_THREADS = 5;
095
096    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultDependencyCollector.class );
097
098    private RemoteRepositoryManager remoteRepositoryManager;
099
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}