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