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