This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/master by this push:
     new 69aeda6  [MRESOLVER-240] Using breadth-first approach to resolve Maven 
dependencies
69aeda6 is described below

commit 69aeda6c7976e5ff39ed7d0f888e4895a50a7f75
Author: Cai <we...@ebay.com>
AuthorDate: Mon Jan 31 18:17:30 2022 -0800

    [MRESOLVER-240] Using breadth-first approach to resolve Maven dependencies
    
    Co-authored-by: ibabiankou <ivan.babian...@gmail.com>
    
    This closes #144
---
 .../impl/collect/DefaultDependencyCollector.java   | 190 ++++++++++-----------
 .../impl/collect/DefaultDependencyCycle.java       |  55 +++++-
 .../impl/collect/DependencyProcessingContext.java  |  77 +++++++++
 .../aether/internal/impl/collect/NodeStack.java    | 127 --------------
 .../impl/collect/DefaultDependencyCycleTest.java   |  10 +-
 5 files changed, 228 insertions(+), 231 deletions(-)

diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCollector.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCollector.java
index a46499d..a773367 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCollector.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCollector.java
@@ -19,6 +19,7 @@ package org.eclipse.aether.internal.impl.collect;
  * under the License.
  */
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -27,7 +28,10 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Queue;
+
 import static java.util.Objects.requireNonNull;
+import static 
org.eclipse.aether.internal.impl.collect.DefaultDependencyCycle.find;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -244,22 +248,34 @@ public class DefaultDependencyCollector
         {
             DataPool pool = new DataPool( session );
 
-            NodeStack nodes = new NodeStack();
-            nodes.push( node );
-
             DefaultDependencyCollectionContext context =
                 new DefaultDependencyCollectionContext( session, 
request.getRootArtifact(), root, managedDependencies );
 
             DefaultVersionFilterContext versionContext = new 
DefaultVersionFilterContext( session );
 
-            Args args = new Args( session, trace, pool, nodes, context, 
versionContext, request );
+            Args args = new Args( session, trace, pool, context, 
versionContext, request );
             Results results = new Results( result, session );
 
-            process( args, results, dependencies, repositories,
-                     depSelector != null ? depSelector.deriveChildSelector( 
context ) : null,
-                     depManager != null ? depManager.deriveChildManager( 
context ) : null,
-                     depTraverser != null ? depTraverser.deriveChildTraverser( 
context ) : null,
-                     verFilter != null ? verFilter.deriveChildFilter( context 
) : null );
+            DependencySelector rootDepSelector =
+                    depSelector != null ? depSelector.deriveChildSelector( 
context ) : null;
+            DependencyManager rootDepManager = depManager != null ? 
depManager.deriveChildManager( context ) : null;
+            DependencyTraverser rootDepTraverser =
+                    depTraverser != null ? depTraverser.deriveChildTraverser( 
context ) : null;
+            VersionFilter rootVerFilter = verFilter != null ? 
verFilter.deriveChildFilter( context ) : null;
+
+            for ( Dependency dependency : dependencies )
+            {
+                args.dependencyProcessingQueue.add(
+                        new DependencyProcessingContext( rootDepSelector, 
rootDepManager, rootDepTraverser,
+                                rootVerFilter, repositories, 
managedDependencies, Collections.singletonList( node ),
+                                dependency ) );
+            }
+
+            while ( !args.dependencyProcessingQueue.isEmpty() )
+            {
+                processDependency( args, results, 
args.dependencyProcessingQueue.remove(), Collections.emptyList(),
+                        false );
+            }
 
             errorPath = results.errorPath;
         }
@@ -344,61 +360,39 @@ public class DefaultDependencyCollector
     }
 
     @SuppressWarnings( "checkstyle:parameternumber" )
-    private void process( final Args args, Results results, List<Dependency> 
dependencies,
-                          List<RemoteRepository> repositories, 
DependencySelector depSelector,
-                          DependencyManager depManager, DependencyTraverser 
depTraverser, VersionFilter verFilter )
-    {
-        for ( Dependency dependency : dependencies )
-        {
-            processDependency( args, results, repositories, depSelector, 
depManager, depTraverser, verFilter,
-                               dependency );
-        }
-    }
-
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private void processDependency( Args args, Results results, 
List<RemoteRepository> repositories,
-                                    DependencySelector depSelector, 
DependencyManager depManager,
-                                    DependencyTraverser depTraverser, 
VersionFilter verFilter, Dependency dependency )
-    {
-
-        List<Artifact> relocations = Collections.emptyList();
-        processDependency( args, results, repositories, depSelector, 
depManager, depTraverser, verFilter, dependency,
-                           relocations, false );
-    }
-
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private void processDependency( Args args, Results results, 
List<RemoteRepository> repositories,
-                                    DependencySelector depSelector, 
DependencyManager depManager,
-                                    DependencyTraverser depTraverser, 
VersionFilter verFilter, Dependency dependency,
+    private void processDependency( Args args, Results results, 
DependencyProcessingContext context,
                                     List<Artifact> relocations, boolean 
disableVersionManagement )
     {
 
-        if ( depSelector != null && !depSelector.selectDependency( dependency 
) )
+        if ( context.depSelector != null && 
!context.depSelector.selectDependency( context.dependency ) )
         {
             return;
         }
 
         PremanagedDependency preManaged =
-            PremanagedDependency.create( depManager, dependency, 
disableVersionManagement, args.premanagedState );
-        dependency = preManaged.managedDependency;
+                PremanagedDependency.create( context.depManager, 
context.dependency, disableVersionManagement,
+                        args.premanagedState );
+        Dependency dependency = preManaged.managedDependency;
 
         boolean noDescriptor = isLackingDescriptor( dependency.getArtifact() );
 
-        boolean traverse = !noDescriptor && ( depTraverser == null || 
depTraverser.traverseDependency( dependency ) );
+        boolean traverse =
+                !noDescriptor && ( context.depTraverser == null || 
context.depTraverser.traverseDependency(
+                        dependency ) );
 
         List<? extends Version> versions;
         VersionRangeResult rangeResult;
         try
         {
-            VersionRangeRequest rangeRequest = createVersionRangeRequest( 
args, repositories, dependency );
+            VersionRangeRequest rangeRequest = createVersionRangeRequest( 
args, context.repositories, dependency );
 
             rangeResult = cachedResolveRangeResult( rangeRequest, args.pool, 
args.session );
 
-            versions = filterVersions( dependency, rangeResult, verFilter, 
args.versionContext );
+            versions = filterVersions( dependency, rangeResult, 
context.verFilter, args.versionContext );
         }
         catch ( VersionRangeResolutionException e )
         {
-            results.addException( dependency, e, args.nodes );
+            results.addException( dependency, e, context.parents );
             return;
         }
 
@@ -407,27 +401,30 @@ public class DefaultDependencyCollector
             Artifact originalArtifact = dependency.getArtifact().setVersion( 
version.toString() );
             Dependency d = dependency.setArtifact( originalArtifact );
 
-            ArtifactDescriptorRequest descriptorRequest = 
createArtifactDescriptorRequest( args, repositories, d );
+            ArtifactDescriptorRequest descriptorRequest =
+                    createArtifactDescriptorRequest( args, 
context.repositories, d );
 
             final ArtifactDescriptorResult descriptorResult =
-                getArtifactDescriptorResult( args, results, noDescriptor, d, 
descriptorRequest );
+                    noDescriptor
+                            ? new ArtifactDescriptorResult( descriptorRequest )
+                            : resolveCachedArtifactDescriptor( args.pool, 
descriptorRequest, args.session,
+                                    context.withDependency( d ), results );
+
             if ( descriptorResult != null )
             {
                 d = d.setArtifact( descriptorResult.getArtifact() );
 
-                DependencyNode node = args.nodes.top();
-
-                int cycleEntry = args.nodes.find( d.getArtifact() );
+                int cycleEntry = find( context.parents, d.getArtifact() );
                 if ( cycleEntry >= 0 )
                 {
-                    results.addCycle( args.nodes, cycleEntry, d );
-                    DependencyNode cycleNode = args.nodes.get( cycleEntry );
+                    results.addCycle( context.parents, cycleEntry, d );
+                    DependencyNode cycleNode = context.parents.get( cycleEntry 
);
                     if ( cycleNode.getDependency() != null )
                     {
                         DefaultDependencyNode child =
-                            createDependencyNode( relocations, preManaged, 
rangeResult, version, d, descriptorResult,
-                                                  cycleNode );
-                        node.getChildren().add( child );
+                                createDependencyNode( relocations, preManaged, 
rangeResult, version, d,
+                                        descriptorResult, cycleNode );
+                        context.getParent().getChildren().add( child );
                         continue;
                     }
                 }
@@ -438,8 +435,8 @@ public class DefaultDependencyCollector
                         originalArtifact.getGroupId().equals( 
d.getArtifact().getGroupId() )
                             && originalArtifact.getArtifactId().equals( 
d.getArtifact().getArtifactId() );
 
-                    processDependency( args, results, repositories, 
depSelector, depManager, depTraverser, verFilter, d,
-                                       descriptorResult.getRelocations(), 
disableVersionManagementSubsequently );
+                    processDependency( args, results, context.withDependency( 
d ), descriptorResult.getRelocations(),
+                            disableVersionManagementSubsequently );
                     return;
                 }
                 else
@@ -447,69 +444,72 @@ public class DefaultDependencyCollector
                     d = args.pool.intern( d.setArtifact( args.pool.intern( 
d.getArtifact() ) ) );
 
                     List<RemoteRepository> repos =
-                        getRemoteRepositories( rangeResult.getRepository( 
version ), repositories );
+                        getRemoteRepositories( rangeResult.getRepository( 
version ), context.repositories );
 
                     DefaultDependencyNode child =
                         createDependencyNode( relocations, preManaged, 
rangeResult, version, d,
                                               descriptorResult.getAliases(), 
repos, args.request.getRequestContext() );
 
-                    node.getChildren().add( child );
+                    context.getParent().getChildren().add( child );
 
                     boolean recurse = traverse && 
!descriptorResult.getDependencies().isEmpty();
                     if ( recurse )
                     {
-                        doRecurse( args, results, repositories, depSelector, 
depManager, depTraverser, verFilter, d,
-                                   descriptorResult, child );
+                        doRecurse( args, context.withDependency( d ), 
descriptorResult, child );
                     }
                 }
             }
             else
             {
-                DependencyNode node = args.nodes.top();
                 List<RemoteRepository> repos =
-                    getRemoteRepositories( rangeResult.getRepository( version 
), repositories );
+                    getRemoteRepositories( rangeResult.getRepository( version 
), context.repositories );
                 DefaultDependencyNode child =
                     createDependencyNode( relocations, preManaged, 
rangeResult, version, d, null, repos,
                                           args.request.getRequestContext() );
-                node.getChildren().add( child );
+                context.getParent().getChildren().add( child );
             }
         }
     }
 
     @SuppressWarnings( "checkstyle:parameternumber" )
-    private void doRecurse( Args args, Results results, List<RemoteRepository> 
repositories,
-                            DependencySelector depSelector, DependencyManager 
depManager,
-                            DependencyTraverser depTraverser, VersionFilter 
verFilter, Dependency d,
+    private void doRecurse( Args args, DependencyProcessingContext 
parentContext,
                             ArtifactDescriptorResult descriptorResult, 
DefaultDependencyNode child )
     {
         DefaultDependencyCollectionContext context = args.collectionContext;
-        context.set( d, descriptorResult.getManagedDependencies() );
+        context.set( parentContext.dependency, 
descriptorResult.getManagedDependencies() );
 
-        DependencySelector childSelector = depSelector != null ? 
depSelector.deriveChildSelector( context ) : null;
-        DependencyManager childManager = depManager != null ? 
depManager.deriveChildManager( context ) : null;
-        DependencyTraverser childTraverser = depTraverser != null ? 
depTraverser.deriveChildTraverser( context ) : null;
-        VersionFilter childFilter = verFilter != null ? 
verFilter.deriveChildFilter( context ) : null;
+        DependencySelector childSelector =
+                parentContext.depSelector != null ? 
parentContext.depSelector.deriveChildSelector( context ) : null;
+        DependencyManager childManager =
+                parentContext.depManager != null ? 
parentContext.depManager.deriveChildManager( context ) : null;
+        DependencyTraverser childTraverser =
+                parentContext.depTraverser != null ? 
parentContext.depTraverser.deriveChildTraverser( context ) : null;
+        VersionFilter childFilter =
+                parentContext.verFilter != null ? 
parentContext.verFilter.deriveChildFilter( context ) : null;
 
         final List<RemoteRepository> childRepos =
-            args.ignoreRepos
-                ? repositories
-                : remoteRepositoryManager.aggregateRepositories( args.session, 
repositories,
-                                                                 
descriptorResult.getRepositories(), true );
+                args.ignoreRepos
+                        ? parentContext.repositories
+                        : remoteRepositoryManager.aggregateRepositories( 
args.session, parentContext.repositories,
+                        descriptorResult.getRepositories(), true );
 
         Object key =
-            args.pool.toKey( d.getArtifact(), childRepos, childSelector, 
childManager, childTraverser, childFilter );
+                args.pool.toKey( parentContext.dependency.getArtifact(), 
childRepos, childSelector, childManager,
+                        childTraverser, childFilter );
 
         List<DependencyNode> children = args.pool.getChildren( key );
         if ( children == null )
         {
             args.pool.putChildren( key, child.getChildren() );
 
-            args.nodes.push( child );
-
-            process( args, results, descriptorResult.getDependencies(), 
childRepos, childSelector, childManager,
-                     childTraverser, childFilter );
-
-            args.nodes.pop();
+            List<DependencyNode> parents = new ArrayList<>( 
parentContext.parents );
+            parents.add( child );
+            for ( Dependency dependency : descriptorResult.getDependencies() )
+            {
+                args.dependencyProcessingQueue.add(
+                        new DependencyProcessingContext( childSelector, 
childManager, childTraverser, childFilter,
+                                childRepos, 
descriptorResult.getManagedDependencies(), parents, dependency ) );
+            }
         }
         else
         {
@@ -517,20 +517,11 @@ public class DefaultDependencyCollector
         }
     }
 
-    private ArtifactDescriptorResult getArtifactDescriptorResult( Args args, 
Results results, boolean noDescriptor,
-                                                                  Dependency d,
-                                                                  
ArtifactDescriptorRequest descriptorRequest )
-    {
-        return noDescriptor
-                   ? new ArtifactDescriptorResult( descriptorRequest )
-                   : resolveCachedArtifactDescriptor( args.pool, 
descriptorRequest, args.session, d, results, args );
-
-    }
-
     private ArtifactDescriptorResult resolveCachedArtifactDescriptor( DataPool 
pool,
                                                                       
ArtifactDescriptorRequest descriptorRequest,
-                                                                      
RepositorySystemSession session, Dependency d,
-                                                                      Results 
results, Args args )
+                                                                      
RepositorySystemSession session,
+                                                                      
DependencyProcessingContext context,
+                                                                      Results 
results )
     {
         Object key = pool.toKey( descriptorRequest );
         ArtifactDescriptorResult descriptorResult = pool.getDescriptor( key, 
descriptorRequest );
@@ -543,7 +534,7 @@ public class DefaultDependencyCollector
             }
             catch ( ArtifactDescriptorException e )
             {
-                results.addException( d, e, args.nodes );
+                results.addException( context.dependency, e, context.parents );
                 pool.putDescriptor( key, e );
                 return null;
             }
@@ -698,7 +689,7 @@ public class DefaultDependencyCollector
 
         final DataPool pool;
 
-        final NodeStack nodes;
+        final Queue<DependencyProcessingContext> dependencyProcessingQueue = 
new ArrayDeque<>();
 
         final DefaultDependencyCollectionContext collectionContext;
 
@@ -706,7 +697,7 @@ public class DefaultDependencyCollector
 
         final CollectRequest request;
 
-        Args( RepositorySystemSession session, RequestTrace trace, DataPool 
pool, NodeStack nodes,
+        Args( RepositorySystemSession session, RequestTrace trace, DataPool 
pool,
                      DefaultDependencyCollectionContext collectionContext, 
DefaultVersionFilterContext versionContext,
                      CollectRequest request )
         {
@@ -716,7 +707,6 @@ public class DefaultDependencyCollector
             this.premanagedState = ConfigUtils.getBoolean( session, false, 
DependencyManagerUtils.CONFIG_PROP_VERBOSE );
             this.trace = trace;
             this.pool = pool;
-            this.nodes = nodes;
             this.collectionContext = collectionContext;
             this.versionContext = versionContext;
         }
@@ -744,7 +734,7 @@ public class DefaultDependencyCollector
             maxCycles = ConfigUtils.getInteger( session, 
CONFIG_PROP_MAX_CYCLES_DEFAULT, CONFIG_PROP_MAX_CYCLES );
         }
 
-        public void addException( Dependency dependency, Exception e, 
NodeStack nodes )
+        public void addException( Dependency dependency, Exception e, 
List<DependencyNode> nodes )
         {
             if ( maxExceptions < 0 || result.getExceptions().size() < 
maxExceptions )
             {
@@ -752,13 +742,13 @@ public class DefaultDependencyCollector
                 if ( errorPath == null )
                 {
                     StringBuilder buffer = new StringBuilder( 256 );
-                    for ( int i = 0; i < nodes.size(); i++ )
+                    for ( DependencyNode node : nodes )
                     {
                         if ( buffer.length() > 0 )
                         {
                             buffer.append( " -> " );
                         }
-                        Dependency dep = nodes.get( i ).getDependency();
+                        Dependency dep = node.getDependency();
                         if ( dep != null )
                         {
                             buffer.append( dep.getArtifact() );
@@ -774,7 +764,7 @@ public class DefaultDependencyCollector
             }
         }
 
-        public void addCycle( NodeStack nodes, int cycleEntry, Dependency 
dependency )
+        public void addCycle( List<DependencyNode> nodes, int cycleEntry, 
Dependency dependency )
         {
             if ( maxCycles < 0 || result.getCycles().size() < maxCycles )
             {
diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle.java
index 42a56c2..dd1565c 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle.java
@@ -23,6 +23,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
+import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.graph.Dependency;
 import org.eclipse.aether.graph.DependencyCycle;
 import org.eclipse.aether.graph.DependencyNode;
@@ -39,7 +40,7 @@ final class DefaultDependencyCycle
 
     private final int cycleEntry;
 
-    DefaultDependencyCycle( NodeStack nodes, int cycleEntry, Dependency 
dependency )
+    DefaultDependencyCycle( List<DependencyNode> nodes, int cycleEntry, 
Dependency dependency )
     {
         // skip root node unless it actually has a dependency or is considered 
the cycle entry (due to its label)
         int offset = ( cycleEntry > 0 && nodes.get( 0 ).getDependency() == 
null ) ? 1 : 0;
@@ -69,6 +70,58 @@ final class DefaultDependencyCycle
         return dependencies.subList( cycleEntry, dependencies.size() );
     }
 
+    /**
+     * Searches for a node associated with the given artifact. A version of 
the artifact is not considered during the
+     * search.
+     *
+     * @param nodes a list representing single path in the dependency graph. 
First element is the root.
+     * @param artifact to find among the parent nodes.
+     * @return the index of the node furthest from the root and associated 
with the given artifact, or {@literal -1} if
+     * there is no such node.
+     */
+    public static int find( List<DependencyNode> nodes, Artifact artifact )
+    {
+
+        for ( int i = nodes.size() - 1; i >= 0; i-- )
+        {
+            DependencyNode node = nodes.get( i );
+
+            Artifact a = node.getArtifact();
+            if ( a == null )
+            {
+                break;
+            }
+
+            if ( !a.getArtifactId().equals( artifact.getArtifactId() ) )
+            {
+                continue;
+            }
+            if ( !a.getGroupId().equals( artifact.getGroupId() ) )
+            {
+                continue;
+            }
+            if ( !a.getExtension().equals( artifact.getExtension() ) )
+            {
+                continue;
+            }
+            if ( !a.getClassifier().equals( artifact.getClassifier() ) )
+            {
+                continue;
+            }
+            /*
+             * NOTE: While a:1 and a:2 are technically different artifacts, we 
want to consider the path a:2 -> b:2 ->
+             * a:1 a cycle in the current context. The artifacts themselves 
might not form a cycle but their producing
+             * projects surely do. Furthermore, conflict resolution will 
always have to consider a:1 a loser (otherwise
+             * its ancestor a:2 would get pruned and so would a:1) so there is 
no point in building the sub graph of
+             * a:1.
+             */
+
+            return i;
+        }
+
+        return -1;
+    }
+
     @Override
     public String toString()
     {
diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyProcessingContext.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyProcessingContext.java
new file mode 100644
index 0000000..71815d0
--- /dev/null
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyProcessingContext.java
@@ -0,0 +1,77 @@
+package org.eclipse.aether.internal.impl.collect;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.List;
+
+import org.eclipse.aether.collection.DependencyManager;
+import org.eclipse.aether.collection.DependencySelector;
+import org.eclipse.aether.collection.DependencyTraverser;
+import org.eclipse.aether.collection.VersionFilter;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.repository.RemoteRepository;
+
+final class DependencyProcessingContext
+{
+    final DependencySelector depSelector;
+    final DependencyManager depManager;
+    final DependencyTraverser depTraverser;
+    final VersionFilter verFilter;
+    final List<RemoteRepository> repositories;
+    final List<Dependency> managedDependencies;
+
+    /**
+     * All parents of the dependency in the top > down order.
+     */
+    final List<DependencyNode> parents;
+    final Dependency dependency;
+
+    @SuppressWarnings( "checkstyle:parameternumber" )
+    DependencyProcessingContext( DependencySelector depSelector,
+                                 DependencyManager depManager,
+                                 DependencyTraverser depTraverser,
+                                 VersionFilter verFilter,
+                                 List<RemoteRepository> repositories,
+                                 List<Dependency> managedDependencies,
+                                 List<DependencyNode> parents,
+                                 Dependency dependency )
+    {
+        this.depSelector = depSelector;
+        this.depManager = depManager;
+        this.depTraverser = depTraverser;
+        this.verFilter = verFilter;
+        this.repositories = repositories;
+        this.dependency = dependency;
+        this.managedDependencies = managedDependencies;
+        this.parents = parents;
+    }
+
+    DependencyProcessingContext withDependency( Dependency dependency )
+    {
+        return new DependencyProcessingContext( depSelector, depManager, 
depTraverser, verFilter, repositories,
+                managedDependencies, parents, dependency );
+    }
+
+    DependencyNode getParent()
+    {
+        return parents.get( parents.size() - 1 );
+    }
+}
diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/NodeStack.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/NodeStack.java
deleted file mode 100644
index 668dbc4..0000000
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/NodeStack.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package org.eclipse.aether.internal.impl.collect;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *  http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Arrays;
-
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.graph.DependencyNode;
-
-/**
- * @see DefaultDependencyCollector
- */
-final class NodeStack
-{
-
-    @SuppressWarnings( {"unchecked", "checkstyle:magicnumber" } )
-    // CHECKSTYLE_OFF: MagicNumber
-    private DependencyNode[] nodes = new DependencyNode[96];
-    // CHECKSTYLE_ON: MagicNumber
-
-    private int size;
-
-    public DependencyNode top()
-    {
-        if ( size <= 0 )
-        {
-            throw new IllegalStateException( "stack empty" );
-        }
-        return nodes[size - 1];
-    }
-
-    public void push( DependencyNode node )
-    {
-        if ( size >= nodes.length )
-        {
-            DependencyNode[] tmp = new DependencyNode[size + 64];
-            System.arraycopy( nodes, 0, tmp, 0, nodes.length );
-            nodes = tmp;
-        }
-        nodes[size++] = node;
-    }
-
-    public void pop()
-    {
-        if ( size <= 0 )
-        {
-            throw new IllegalStateException( "stack empty" );
-        }
-        size--;
-    }
-
-    public int find( Artifact artifact )
-    {
-        for ( int i = size - 1; i >= 0; i-- )
-        {
-            DependencyNode node = nodes[i];
-
-            Artifact a = node.getArtifact();
-            if ( a == null )
-            {
-                break;
-            }
-
-            if ( !a.getArtifactId().equals( artifact.getArtifactId() ) )
-            {
-                continue;
-            }
-            if ( !a.getGroupId().equals( artifact.getGroupId() ) )
-            {
-                continue;
-            }
-            if ( !a.getExtension().equals( artifact.getExtension() ) )
-            {
-                continue;
-            }
-            if ( !a.getClassifier().equals( artifact.getClassifier() ) )
-            {
-                continue;
-            }
-            /*
-             * NOTE: While a:1 and a:2 are technically different artifacts, we 
want to consider the path a:2 -> b:2 ->
-             * a:1 a cycle in the current context. The artifacts themselves 
might not form a cycle but their producing
-             * projects surely do. Furthermore, conflict resolution will 
always have to consider a:1 a loser (otherwise
-             * its ancestor a:2 would get pruned and so would a:1) so there is 
no point in building the sub graph of
-             * a:1.
-             */
-
-            return i;
-        }
-
-        return -1;
-    }
-
-    public int size()
-    {
-        return size;
-    }
-
-    public DependencyNode get( int index )
-    {
-        return nodes[index];
-    }
-
-    @Override
-    public String toString()
-    {
-        return Arrays.toString( nodes );
-    }
-
-}
diff --git 
a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycleTest.java
 
b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycleTest.java
index 53cddc2..0a382f8 100644
--- 
a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycleTest.java
+++ 
b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycleTest.java
@@ -23,8 +23,12 @@ import org.eclipse.aether.artifact.DefaultArtifact;
 import org.eclipse.aether.graph.DefaultDependencyNode;
 import org.eclipse.aether.graph.Dependency;
 import org.eclipse.aether.graph.DependencyCycle;
+import org.eclipse.aether.graph.DependencyNode;
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import static org.junit.Assert.assertEquals;
 
 public class DefaultDependencyCycleTest
@@ -35,9 +39,9 @@ public class DefaultDependencyCycleTest
     @Test
     public void testToString()
     {
-        NodeStack nodeStack = new NodeStack();
-        nodeStack.push( new DefaultDependencyNode( FOO_DEPENDENCY ) );
-        DependencyCycle cycle = new DefaultDependencyCycle( nodeStack, 1, 
BAR_DEPENDENCY );
+        List<DependencyNode> nodes = new ArrayList<>();
+        nodes.add( new DefaultDependencyNode( FOO_DEPENDENCY ) );
+        DependencyCycle cycle = new DefaultDependencyCycle( nodes, 1, 
BAR_DEPENDENCY );
 
         assertEquals( "group-id:foo:jar -> group-id:bar:jar", cycle.toString() 
);
     }

Reply via email to