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