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