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