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