You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by hb...@apache.org on 2016/09/03 20:23:27 UTC

[04/51] [partial] maven-aether git commit: [MNG-6007] rename Aether to Maven Artifact Resolver

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectRequest.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectRequest.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectRequest.java
new file mode 100644
index 0000000..d9c2527
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectRequest.java
@@ -0,0 +1,356 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A request to collect the transitive dependencies and to build a dependency graph from them. There are three ways to
+ * create a dependency graph. First, only the root dependency can be given. Second, a root dependency and direct
+ * dependencies can be specified in which case the specified direct dependencies are merged with the direct dependencies
+ * retrieved from the artifact descriptor of the root dependency. And last, only direct dependencies can be specified in
+ * which case the root node of the resulting graph has no associated dependency.
+ * 
+ * @see RepositorySystem#collectDependencies(RepositorySystemSession, CollectRequest)
+ */
+public final class CollectRequest
+{
+
+    private Artifact rootArtifact;
+
+    private Dependency root;
+
+    private List<Dependency> dependencies = Collections.emptyList();
+
+    private List<Dependency> managedDependencies = Collections.emptyList();
+
+    private List<RemoteRepository> repositories = Collections.emptyList();
+
+    private String context = "";
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public CollectRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request with the specified properties.
+     * 
+     * @param root The root dependency whose transitive dependencies should be collected, may be {@code null}.
+     * @param repositories The repositories to use for the collection, may be {@code null}.
+     */
+    public CollectRequest( Dependency root, List<RemoteRepository> repositories )
+    {
+        setRoot( root );
+        setRepositories( repositories );
+    }
+
+    /**
+     * Creates a new request with the specified properties.
+     * 
+     * @param root The root dependency whose transitive dependencies should be collected, may be {@code null}.
+     * @param dependencies The direct dependencies to merge with the direct dependencies from the root dependency's
+     *            artifact descriptor.
+     * @param repositories The repositories to use for the collection, may be {@code null}.
+     */
+    public CollectRequest( Dependency root, List<Dependency> dependencies, List<RemoteRepository> repositories )
+    {
+        setRoot( root );
+        setDependencies( dependencies );
+        setRepositories( repositories );
+    }
+
+    /**
+     * Creates a new request with the specified properties.
+     * 
+     * @param dependencies The direct dependencies of some imaginary root, may be {@code null}.
+     * @param managedDependencies The dependency management information to apply to the transitive dependencies, may be
+     *            {@code null}.
+     * @param repositories The repositories to use for the collection, may be {@code null}.
+     */
+    public CollectRequest( List<Dependency> dependencies, List<Dependency> managedDependencies,
+                           List<RemoteRepository> repositories )
+    {
+        setDependencies( dependencies );
+        setManagedDependencies( managedDependencies );
+        setRepositories( repositories );
+    }
+
+    /**
+     * Gets the root artifact for the dependency graph.
+     * 
+     * @return The root artifact for the dependency graph or {@code null} if none.
+     */
+    public Artifact getRootArtifact()
+    {
+        return rootArtifact;
+    }
+
+    /**
+     * Sets the root artifact for the dependency graph. This must not be confused with {@link #setRoot(Dependency)}: The
+     * root <em>dependency</em>, like any other specified dependency, will be subject to dependency
+     * collection/resolution, i.e. should have an artifact descriptor and a corresponding artifact file. The root
+     * <em>artifact</em> on the other hand is only used as a label for the root node of the graph in case no root
+     * dependency was specified. As such, the configured root artifact is ignored if {@link #getRoot()} does not return
+     * {@code null}.
+     * 
+     * @param rootArtifact The root artifact for the dependency graph, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setRootArtifact( Artifact rootArtifact )
+    {
+        this.rootArtifact = rootArtifact;
+        return this;
+    }
+
+    /**
+     * Gets the root dependency of the graph.
+     * 
+     * @return The root dependency of the graph or {@code null} if none.
+     */
+    public Dependency getRoot()
+    {
+        return root;
+    }
+
+    /**
+     * Sets the root dependency of the graph.
+     * 
+     * @param root The root dependency of the graph, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setRoot( Dependency root )
+    {
+        this.root = root;
+        return this;
+    }
+
+    /**
+     * Gets the direct dependencies.
+     * 
+     * @return The direct dependencies, never {@code null}.
+     */
+    public List<Dependency> getDependencies()
+    {
+        return dependencies;
+    }
+
+    /**
+     * Sets the direct dependencies. If both a root dependency and direct dependencies are given in the request, the
+     * direct dependencies from the request will be merged with the direct dependencies from the root dependency's
+     * artifact descriptor, giving higher priority to the dependencies from the request.
+     * 
+     * @param dependencies The direct dependencies, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setDependencies( List<Dependency> dependencies )
+    {
+        if ( dependencies == null )
+        {
+            this.dependencies = Collections.emptyList();
+        }
+        else
+        {
+            this.dependencies = dependencies;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified direct dependency.
+     * 
+     * @param dependency The dependency to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest addDependency( Dependency dependency )
+    {
+        if ( dependency != null )
+        {
+            if ( this.dependencies.isEmpty() )
+            {
+                this.dependencies = new ArrayList<Dependency>();
+            }
+            this.dependencies.add( dependency );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the dependency management to apply to transitive dependencies.
+     * 
+     * @return The dependency management to apply to transitive dependencies, never {@code null}.
+     */
+    public List<Dependency> getManagedDependencies()
+    {
+        return managedDependencies;
+    }
+
+    /**
+     * Sets the dependency management to apply to transitive dependencies. To clarify, this management does not apply to
+     * the direct dependencies of the root node.
+     * 
+     * @param managedDependencies The dependency management, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setManagedDependencies( List<Dependency> managedDependencies )
+    {
+        if ( managedDependencies == null )
+        {
+            this.managedDependencies = Collections.emptyList();
+        }
+        else
+        {
+            this.managedDependencies = managedDependencies;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified managed dependency.
+     * 
+     * @param managedDependency The managed dependency to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest addManagedDependency( Dependency managedDependency )
+    {
+        if ( managedDependency != null )
+        {
+            if ( this.managedDependencies.isEmpty() )
+            {
+                this.managedDependencies = new ArrayList<Dependency>();
+            }
+            this.managedDependencies.add( managedDependency );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the repositories to use for the collection.
+     * 
+     * @return The repositories to use for the collection, never {@code null}.
+     */
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the repositories to use for the collection.
+     * 
+     * @param repositories The repositories to use for the collection, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified repository for collection.
+     * 
+     * @param repository The repository to collect dependency information from, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest addRepository( RemoteRepository repository )
+    {
+        if ( repository != null )
+        {
+            if ( this.repositories.isEmpty() )
+            {
+                this.repositories = new ArrayList<RemoteRepository>();
+            }
+            this.repositories.add( repository );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the context in which this request is made.
+     * 
+     * @return The context, never {@code null}.
+     */
+    public String getRequestContext()
+    {
+        return context;
+    }
+
+    /**
+     * Sets the context in which this request is made.
+     * 
+     * @param context The context, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setRequestContext( String context )
+    {
+        this.context = ( context != null ) ? context : "";
+        return this;
+    }
+
+    /**
+     * Gets the trace information that describes the higher level request/operation in which this request is issued.
+     * 
+     * @return The trace information about the higher level operation or {@code null} if none.
+     */
+    public RequestTrace getTrace()
+    {
+        return trace;
+    }
+
+    /**
+     * Sets the trace information that describes the higher level request/operation in which this request is issued.
+     * 
+     * @param trace The trace information about the higher level operation, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getRoot() + " -> " + getDependencies() + " < " + getRepositories();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectResult.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectResult.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectResult.java
new file mode 100644
index 0000000..dd9f02e
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectResult.java
@@ -0,0 +1,159 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.graph.DependencyCycle;
+import org.eclipse.aether.graph.DependencyNode;
+
+/**
+ * The result of a dependency collection request.
+ * 
+ * @see RepositorySystem#collectDependencies(RepositorySystemSession, CollectRequest)
+ */
+public final class CollectResult
+{
+
+    private final CollectRequest request;
+
+    private List<Exception> exceptions;
+
+    private List<DependencyCycle> cycles;
+
+    private DependencyNode root;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The resolution request, must not be {@code null}.
+     */
+    public CollectResult( CollectRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "dependency collection request has not been specified" );
+        }
+        this.request = request;
+        exceptions = Collections.emptyList();
+        cycles = Collections.emptyList();
+    }
+
+    /**
+     * Gets the collection request that was made.
+     * 
+     * @return The collection request, never {@code null}.
+     */
+    public CollectRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the exceptions that occurred while building the dependency graph.
+     * 
+     * @return The exceptions that occurred, never {@code null}.
+     */
+    public List<Exception> getExceptions()
+    {
+        return exceptions;
+    }
+
+    /**
+     * Records the specified exception while building the dependency graph.
+     * 
+     * @param exception The exception to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public CollectResult addException( Exception exception )
+    {
+        if ( exception != null )
+        {
+            if ( exceptions.isEmpty() )
+            {
+                exceptions = new ArrayList<Exception>();
+            }
+            exceptions.add( exception );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the dependency cycles that were encountered while building the dependency graph.
+     * 
+     * @return The dependency cycles in the (raw) graph, never {@code null}.
+     */
+    public List<DependencyCycle> getCycles()
+    {
+        return cycles;
+    }
+
+    /**
+     * Records the specified dependency cycle.
+     * 
+     * @param cycle The dependency cycle to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public CollectResult addCycle( DependencyCycle cycle )
+    {
+        if ( cycle != null )
+        {
+            if ( cycles.isEmpty() )
+            {
+                cycles = new ArrayList<DependencyCycle>();
+            }
+            cycles.add( cycle );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the root node of the dependency graph.
+     * 
+     * @return The root node of the dependency graph or {@code null} if none.
+     */
+    public DependencyNode getRoot()
+    {
+        return root;
+    }
+
+    /**
+     * Sets the root node of the dependency graph.
+     * 
+     * @param root The root node of the dependency graph, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public CollectResult setRoot( DependencyNode root )
+    {
+        this.root = root;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.valueOf( getRoot() );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyCollectionContext.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyCollectionContext.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyCollectionContext.java
new file mode 100644
index 0000000..671bd2a
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyCollectionContext.java
@@ -0,0 +1,75 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.Dependency;
+
+/**
+ * A context used during dependency collection to update the dependency manager, selector and traverser.
+ * 
+ * @see DependencyManager#deriveChildManager(DependencyCollectionContext)
+ * @see DependencyTraverser#deriveChildTraverser(DependencyCollectionContext)
+ * @see DependencySelector#deriveChildSelector(DependencyCollectionContext)
+ * @see VersionFilter#deriveChildFilter(DependencyCollectionContext)
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface DependencyCollectionContext
+{
+
+    /**
+     * Gets the repository system session during which the dependency collection happens.
+     * 
+     * @return The repository system session, never {@code null}.
+     */
+    RepositorySystemSession getSession();
+
+    /**
+     * Gets the artifact whose children are to be processed next during dependency collection. For all nodes but the
+     * root, this is simply shorthand for {@code getDependency().getArtifact()}. In case of the root node however,
+     * {@link #getDependency()} might be {@code null} while the node still has an artifact which serves as its label and
+     * is not to be resolved.
+     * 
+     * @return The artifact whose children are going to be processed or {@code null} in case of the root node without
+     *         dependency and label.
+     */
+    Artifact getArtifact();
+
+    /**
+     * Gets the dependency whose children are to be processed next during dependency collection.
+     * 
+     * @return The dependency whose children are going to be processed or {@code null} in case of the root node without
+     *         dependency.
+     */
+    Dependency getDependency();
+
+    /**
+     * Gets the dependency management information that was contributed by the artifact descriptor of the current
+     * dependency.
+     * 
+     * @return The dependency management information, never {@code null}.
+     */
+    List<Dependency> getManagedDependencies();
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyCollectionException.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyCollectionException.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyCollectionException.java
new file mode 100644
index 0000000..8a04d79
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyCollectionException.java
@@ -0,0 +1,111 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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 org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of bad artifact descriptors, version ranges or other issues encountered during calculation of the
+ * dependency graph.
+ */
+public class DependencyCollectionException
+    extends RepositoryException
+{
+
+    private final transient CollectResult result;
+
+    /**
+     * Creates a new exception with the specified result.
+     * 
+     * @param result The collection result at the point the exception occurred, may be {@code null}.
+     */
+    public DependencyCollectionException( CollectResult result )
+    {
+        super( "Failed to collect dependencies for " + getSource( result ), getCause( result ) );
+        this.result = result;
+    }
+
+    /**
+     * Creates a new exception with the specified result and detail message.
+     * 
+     * @param result The collection result at the point the exception occurred, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public DependencyCollectionException( CollectResult result, String message )
+    {
+        super( message, getCause( result ) );
+        this.result = result;
+    }
+
+    /**
+     * Creates a new exception with the specified result, detail message and cause.
+     * 
+     * @param result The collection result at the point the exception occurred, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public DependencyCollectionException( CollectResult result, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.result = result;
+    }
+
+    /**
+     * Gets the collection result at the point the exception occurred. Despite being incomplete, callers might want to
+     * use this result to fail gracefully and continue their operation with whatever interim data has been gathered.
+     * 
+     * @return The collection result or {@code null} if unknown.
+     */
+    public CollectResult getResult()
+    {
+        return result;
+    }
+
+    private static String getSource( CollectResult result )
+    {
+        if ( result == null )
+        {
+            return "";
+        }
+
+        CollectRequest request = result.getRequest();
+        if ( request.getRoot() != null )
+        {
+            return request.getRoot().toString();
+        }
+        if ( request.getRootArtifact() != null )
+        {
+            return request.getRootArtifact().toString();
+        }
+
+        return request.getDependencies().toString();
+    }
+
+    private static Throwable getCause( CollectResult result )
+    {
+        Throwable cause = null;
+        if ( result != null && !result.getExceptions().isEmpty() )
+        {
+            cause = result.getExceptions().get( 0 );
+        }
+        return cause;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyGraphTransformationContext.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyGraphTransformationContext.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyGraphTransformationContext.java
new file mode 100644
index 0000000..ba66474
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyGraphTransformationContext.java
@@ -0,0 +1,58 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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 org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * A context used during dependency collection to exchange information within a chain of dependency graph transformers.
+ * 
+ * @see DependencyGraphTransformer
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface DependencyGraphTransformationContext
+{
+
+    /**
+     * Gets the repository system session during which the graph transformation happens.
+     * 
+     * @return The repository system session, never {@code null}.
+     */
+    RepositorySystemSession getSession();
+
+    /**
+     * Gets a keyed value from the context.
+     * 
+     * @param key The key used to query the value, must not be {@code null}.
+     * @return The queried value or {@code null} if none.
+     */
+    Object get( Object key );
+
+    /**
+     * Puts a keyed value into the context.
+     * 
+     * @param key The key used to store the value, must not be {@code null}.
+     * @param value The value to store, may be {@code null} to remove the mapping.
+     * @return The previous value associated with the key or {@code null} if none.
+     */
+    Object put( Object key, Object value );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyGraphTransformer.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyGraphTransformer.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyGraphTransformer.java
new file mode 100644
index 0000000..c472500
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyGraphTransformer.java
@@ -0,0 +1,51 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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 org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.graph.DependencyNode;
+
+/**
+ * Transforms a given dependency graph.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> Dependency graphs may generally contain cycles. As such a graph transformer that cannot assume for
+ * sure that cycles have already been eliminated must gracefully handle cyclic graphs, e.g. guard against infinite
+ * recursion.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getDependencyGraphTransformer()
+ */
+public interface DependencyGraphTransformer
+{
+
+    /**
+     * Transforms the dependency graph denoted by the specified root node. The transformer may directly change the
+     * provided input graph or create a new graph, the former is recommended for performance reasons.
+     * 
+     * @param node The root node of the (possibly cyclic!) graph to transform, must not be {@code null}.
+     * @param context The graph transformation context, must not be {@code null}.
+     * @return The result graph of the transformation, never {@code null}.
+     * @throws RepositoryException If the transformation failed.
+     */
+    DependencyNode transformGraph( DependencyNode node, DependencyGraphTransformationContext context )
+        throws RepositoryException;
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyManagement.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyManagement.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyManagement.java
new file mode 100644
index 0000000..054bfe0
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyManagement.java
@@ -0,0 +1,177 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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.Collection;
+import java.util.Map;
+
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.Exclusion;
+
+/**
+ * The management updates to apply to a dependency.
+ * 
+ * @see DependencyManager#manageDependency(Dependency)
+ */
+public final class DependencyManagement
+{
+
+    private String version;
+
+    private String scope;
+
+    private Boolean optional;
+
+    private Collection<Exclusion> exclusions;
+
+    private Map<String, String> properties;
+
+    /**
+     * Creates an empty management update.
+     */
+    public DependencyManagement()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Gets the new version to apply to the dependency.
+     * 
+     * @return The new version or {@code null} if the version is not managed and the existing dependency version should
+     *         remain unchanged.
+     */
+    public String getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * Sets the new version to apply to the dependency.
+     * 
+     * @param version The new version, may be {@code null} if the version is not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setVersion( String version )
+    {
+        this.version = version;
+        return this;
+    }
+
+    /**
+     * Gets the new scope to apply to the dependency.
+     * 
+     * @return The new scope or {@code null} if the scope is not managed and the existing dependency scope should remain
+     *         unchanged.
+     */
+    public String getScope()
+    {
+        return scope;
+    }
+
+    /**
+     * Sets the new scope to apply to the dependency.
+     * 
+     * @param scope The new scope, may be {@code null} if the scope is not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setScope( String scope )
+    {
+        this.scope = scope;
+        return this;
+    }
+
+    /**
+     * Gets the new optional flag to apply to the dependency.
+     * 
+     * @return The new optional flag or {@code null} if the flag is not managed and the existing optional flag of the
+     *         dependency should remain unchanged.
+     */
+    public Boolean getOptional()
+    {
+        return optional;
+    }
+
+    /**
+     * Sets the new optional flag to apply to the dependency.
+     * 
+     * @param optional The optional flag, may be {@code null} if the flag is not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setOptional( Boolean optional )
+    {
+        this.optional = optional;
+        return this;
+    }
+
+    /**
+     * Gets the new exclusions to apply to the dependency. Note that this collection denotes the complete set of
+     * exclusions for the dependency, i.e. the dependency manager controls whether any existing exclusions get merged
+     * with information from dependency management or overridden by it.
+     * 
+     * @return The new exclusions or {@code null} if the exclusions are not managed and the existing dependency
+     *         exclusions should remain unchanged.
+     */
+    public Collection<Exclusion> getExclusions()
+    {
+        return exclusions;
+    }
+
+    /**
+     * Sets the new exclusions to apply to the dependency. Note that this collection denotes the complete set of
+     * exclusions for the dependency, i.e. the dependency manager controls whether any existing exclusions get merged
+     * with information from dependency management or overridden by it.
+     * 
+     * @param exclusions The new exclusions, may be {@code null} if the exclusions are not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setExclusions( Collection<Exclusion> exclusions )
+    {
+        this.exclusions = exclusions;
+        return this;
+    }
+
+    /**
+     * Gets the new properties to apply to the dependency. Note that this map denotes the complete set of properties,
+     * i.e. the dependency manager controls whether any existing properties get merged with the information from
+     * dependency management or overridden by it.
+     * 
+     * @return The new artifact properties or {@code null} if the properties are not managed and the existing properties
+     *         should remain unchanged.
+     */
+    public Map<String, String> getProperties()
+    {
+        return properties;
+    }
+
+    /**
+     * Sets the new properties to apply to the dependency. Note that this map denotes the complete set of properties,
+     * i.e. the dependency manager controls whether any existing properties get merged with the information from
+     * dependency management or overridden by it.
+     * 
+     * @param properties The new artifact properties, may be {@code null} if the properties are not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setProperties( Map<String, String> properties )
+    {
+        this.properties = properties;
+        return this;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyManager.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyManager.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyManager.java
new file mode 100644
index 0000000..993e388
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyManager.java
@@ -0,0 +1,57 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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 org.eclipse.aether.graph.Dependency;
+
+/**
+ * Applies dependency management to the dependencies of a dependency node.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> This hook is called from a hot spot and therefore implementations should pay attention to
+ * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getDependencyManager()
+ * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession,
+ *      CollectRequest)
+ */
+public interface DependencyManager
+{
+
+    /**
+     * Applies dependency management to the specified dependency.
+     * 
+     * @param dependency The dependency to manage, must not be {@code null}.
+     * @return The management update to apply to the dependency or {@code null} if the dependency is not managed at all.
+     */
+    DependencyManagement manageDependency( Dependency dependency );
+
+    /**
+     * Derives a dependency manager for the specified collection context. When calculating the child manager,
+     * implementors are strongly advised to simply return the current instance if nothing changed to help save memory.
+     * 
+     * @param context The dependency collection context, must not be {@code null}.
+     * @return The dependency manager for the dependencies of the target node or {@code null} if dependency management
+     *         should no longer be applied.
+     */
+    DependencyManager deriveChildManager( DependencyCollectionContext context );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencySelector.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencySelector.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencySelector.java
new file mode 100644
index 0000000..b257ffa
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencySelector.java
@@ -0,0 +1,58 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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 org.eclipse.aether.graph.Dependency;
+
+/**
+ * Decides what dependencies to include in the dependency graph.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> This hook is called from a hot spot and therefore implementations should pay attention to
+ * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getDependencySelector()
+ * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession,
+ *      CollectRequest)
+ */
+public interface DependencySelector
+{
+
+    /**
+     * Decides whether the specified dependency should be included in the dependency graph.
+     * 
+     * @param dependency The dependency to check, must not be {@code null}.
+     * @return {@code false} if the dependency should be excluded from the children of the current node, {@code true}
+     *         otherwise.
+     */
+    boolean selectDependency( Dependency dependency );
+
+    /**
+     * Derives a dependency selector for the specified collection context. When calculating the child selector,
+     * implementors are strongly advised to simply return the current instance if nothing changed to help save memory.
+     * 
+     * @param context The dependency collection context, must not be {@code null}.
+     * @return The dependency selector for the target node or {@code null} if dependencies should be unconditionally
+     *         included in the sub graph.
+     */
+    DependencySelector deriveChildSelector( DependencyCollectionContext context );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyTraverser.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyTraverser.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyTraverser.java
new file mode 100644
index 0000000..be1887b
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/DependencyTraverser.java
@@ -0,0 +1,59 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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 org.eclipse.aether.graph.Dependency;
+
+/**
+ * Decides whether the dependencies of a dependency node should be traversed as well.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> This hook is called from a hot spot and therefore implementations should pay attention to
+ * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getDependencyTraverser()
+ * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession,
+ *      CollectRequest)
+ */
+public interface DependencyTraverser
+{
+
+    /**
+     * Decides whether the dependencies of the specified dependency should be traversed.
+     * 
+     * @param dependency The dependency to check, must not be {@code null}.
+     * @return {@code true} if the dependency graph builder should recurse into the specified dependency and process its
+     *         dependencies, {@code false} otherwise.
+     */
+    boolean traverseDependency( Dependency dependency );
+
+    /**
+     * Derives a dependency traverser that will be used to decide whether the transitive dependencies of the dependency
+     * given in the collection context shall be traversed. When calculating the child traverser, implementors are
+     * strongly advised to simply return the current instance if nothing changed to help save memory.
+     * 
+     * @param context The dependency collection context, must not be {@code null}.
+     * @return The dependency traverser for the target node or {@code null} if dependencies should be unconditionally
+     *         traversed in the sub graph.
+     */
+    DependencyTraverser deriveChildTraverser( DependencyCollectionContext context );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/UnsolvableVersionConflictException.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/UnsolvableVersionConflictException.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/UnsolvableVersionConflictException.java
new file mode 100644
index 0000000..54a7004
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/UnsolvableVersionConflictException.java
@@ -0,0 +1,142 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.version.VersionConstraint;
+
+/**
+ * Thrown in case of an unsolvable conflict between different version constraints for a dependency.
+ */
+public class UnsolvableVersionConflictException
+    extends RepositoryException
+{
+
+    private final transient Collection<String> versions;
+
+    private final transient Collection<? extends List<? extends DependencyNode>> paths;
+
+    /**
+     * Creates a new exception with the specified paths to conflicting nodes in the dependency graph.
+     * 
+     * @param paths The paths to the dependency nodes that participate in the version conflict, may be {@code null}.
+     */
+    public UnsolvableVersionConflictException( Collection<? extends List<? extends DependencyNode>> paths )
+    {
+        super( "Could not resolve version conflict among " + toPaths( paths ) );
+        if ( paths == null )
+        {
+            this.paths = Collections.emptyList();
+            this.versions = Collections.emptyList();
+        }
+        else
+        {
+            this.paths = paths;
+            this.versions = new LinkedHashSet<String>();
+            for ( List<? extends DependencyNode> path : paths )
+            {
+                VersionConstraint constraint = path.get( path.size() - 1 ).getVersionConstraint();
+                if ( constraint != null && constraint.getRange() != null )
+                {
+                    versions.add( constraint.toString() );
+                }
+            }
+        }
+    }
+
+    private static String toPaths( Collection<? extends List<? extends DependencyNode>> paths )
+    {
+        String result = "";
+
+        if ( paths != null )
+        {
+            Collection<String> strings = new LinkedHashSet<String>();
+
+            for ( List<? extends DependencyNode> path : paths )
+            {
+                strings.add( toPath( path ) );
+            }
+
+            result = strings.toString();
+        }
+
+        return result;
+    }
+
+    private static String toPath( List<? extends DependencyNode> path )
+    {
+        StringBuilder buffer = new StringBuilder( 256 );
+
+        for ( Iterator<? extends DependencyNode> it = path.iterator(); it.hasNext(); )
+        {
+            DependencyNode node = it.next();
+            if ( node.getDependency() == null )
+            {
+                continue;
+            }
+
+            Artifact artifact = node.getDependency().getArtifact();
+            buffer.append( artifact.getGroupId() );
+            buffer.append( ':' ).append( artifact.getArtifactId() );
+            buffer.append( ':' ).append( artifact.getExtension() );
+            if ( artifact.getClassifier().length() > 0 )
+            {
+                buffer.append( ':' ).append( artifact.getClassifier() );
+            }
+            buffer.append( ':' ).append( node.getVersionConstraint() );
+
+            if ( it.hasNext() )
+            {
+                buffer.append( " -> " );
+            }
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * Gets the paths leading to the conflicting dependencies.
+     * 
+     * @return The (read-only) paths leading to the conflicting dependencies, never {@code null}.
+     */
+    public Collection<? extends List<? extends DependencyNode>> getPaths()
+    {
+        return paths;
+    }
+
+    /**
+     * Gets the conflicting version constraints of the dependency.
+     * 
+     * @return The (read-only) conflicting version constraints, never {@code null}.
+     */
+    public Collection<String> getVersions()
+    {
+        return versions;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/VersionFilter.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/VersionFilter.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/VersionFilter.java
new file mode 100644
index 0000000..fb36747
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/VersionFilter.java
@@ -0,0 +1,135 @@
+package org.eclipse.aether.collection;
+
+/*
+ * 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.Iterator;
+import java.util.List;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.repository.ArtifactRepository;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.version.Version;
+import org.eclipse.aether.version.VersionConstraint;
+
+/**
+ * Decides which versions matching a version range should actually be considered for the dependency graph. The version
+ * filter is not invoked for dependencies that do not declare a version range but a single version.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> This hook is called from a hot spot and therefore implementations should pay attention to
+ * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getVersionFilter()
+ * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession,
+ *      CollectRequest)
+ */
+public interface VersionFilter
+{
+
+    /**
+     * A context used during version filtering to hold relevant data.
+     * 
+     * @noimplement This interface is not intended to be implemented by clients.
+     * @noextend This interface is not intended to be extended by clients.
+     */
+    interface VersionFilterContext
+        extends Iterable<Version>
+    {
+
+        /**
+         * Gets the repository system session during which the version filtering happens.
+         * 
+         * @return The repository system session, never {@code null}.
+         */
+        RepositorySystemSession getSession();
+
+        /**
+         * Gets the dependency whose version range is being filtered.
+         * 
+         * @return The dependency, never {@code null}.
+         */
+        Dependency getDependency();
+
+        /**
+         * Gets the total number of available versions. This count reflects any removals made during version filtering.
+         * 
+         * @return The total number of available versions.
+         */
+        int getCount();
+
+        /**
+         * Gets an iterator over the available versions of the dependency. The iterator returns versions in ascending
+         * order. Use {@link Iterator#remove()} to exclude a version from further consideration in the dependency graph.
+         * 
+         * @return The iterator of available versions, never {@code null}.
+         */
+        Iterator<Version> iterator();
+
+        /**
+         * Gets the version constraint that was parsed from the dependency's version string.
+         * 
+         * @return The parsed version constraint, never {@code null}.
+         */
+        VersionConstraint getVersionConstraint();
+
+        /**
+         * Gets the repository from which the specified version was resolved.
+         * 
+         * @param version The version whose source repository should be retrieved, must not be {@code null}.
+         * @return The repository from which the version was resolved or {@code null} if unknown.
+         */
+        ArtifactRepository getRepository( Version version );
+
+        /**
+         * Gets the remote repositories from which the versions were resolved.
+         * 
+         * @return The (read-only) list of repositories, never {@code null}.
+         */
+        List<RemoteRepository> getRepositories();
+
+    }
+
+    /**
+     * Filters the available versions for a given dependency. Implementations will usually call
+     * {@link VersionFilterContext#iterator() context.iterator()} to inspect the available versions and use
+     * {@link java.util.Iterator#remove()} to delete unacceptable versions. If no versions remain after all filtering
+     * has been performed, the dependency collection process will automatically fail, i.e. implementations need not
+     * handle this situation on their own.
+     * 
+     * @param context The version filter context, must not be {@code null}.
+     * @throws RepositoryException If the filtering could not be performed.
+     */
+    void filterVersions( VersionFilterContext context )
+        throws RepositoryException;
+
+    /**
+     * Derives a version filter for the specified collection context. The derived filter will be used to handle version
+     * ranges encountered in child dependencies of the current node. When calculating the child filter, implementors are
+     * strongly advised to simply return the current instance if nothing changed to help save memory.
+     * 
+     * @param context The dependency collection context, must not be {@code null}.
+     * @return The version filter for the target node or {@code null} if versions should not be filtered any more.
+     */
+    VersionFilter deriveChildFilter( DependencyCollectionContext context );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/collection/package-info.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/package-info.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/package-info.java
new file mode 100644
index 0000000..414629f
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/package-info.java
@@ -0,0 +1,25 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/*
+ * 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.
+ */
+/**
+ * The types and extension points for collecting the transitive dependencies of an artifact and building a dependency
+ * graph.
+ */
+package org.eclipse.aether.collection;
+

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeployRequest.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeployRequest.java b/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeployRequest.java
new file mode 100644
index 0000000..637f47d
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeployRequest.java
@@ -0,0 +1,202 @@
+package org.eclipse.aether.deployment;
+
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A request to deploy artifacts and their accompanying metadata into the a remote repository.
+ * 
+ * @see RepositorySystem#deploy(RepositorySystemSession, DeployRequest)
+ */
+public final class DeployRequest
+{
+
+    private Collection<Artifact> artifacts = Collections.emptyList();
+
+    private Collection<Metadata> metadata = Collections.emptyList();
+
+    private RemoteRepository repository;
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public DeployRequest()
+    {
+    }
+
+    /**
+     * Gets the artifact to deploy.
+     * 
+     * @return The artifacts to deploy, never {@code null}.
+     */
+    public Collection<Artifact> getArtifacts()
+    {
+        return artifacts;
+    }
+
+    /**
+     * Sets the artifacts to deploy.
+     * 
+     * @param artifacts The artifacts to deploy, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest setArtifacts( Collection<Artifact> artifacts )
+    {
+        if ( artifacts == null )
+        {
+            this.artifacts = Collections.emptyList();
+        }
+        else
+        {
+            this.artifacts = artifacts;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified artifacts for deployment.
+     * 
+     * @param artifact The artifact to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest addArtifact( Artifact artifact )
+    {
+        if ( artifact != null )
+        {
+            if ( artifacts.isEmpty() )
+            {
+                artifacts = new ArrayList<Artifact>();
+            }
+            artifacts.add( artifact );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the metadata to deploy.
+     * 
+     * @return The metadata to deploy, never {@code null}.
+     */
+    public Collection<Metadata> getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata to deploy.
+     * 
+     * @param metadata The metadata to deploy, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest setMetadata( Collection<Metadata> metadata )
+    {
+        if ( metadata == null )
+        {
+            this.metadata = Collections.emptyList();
+        }
+        else
+        {
+            this.metadata = metadata;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified metadata for deployment.
+     * 
+     * @param metadata The metadata to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest addMetadata( Metadata metadata )
+    {
+        if ( metadata != null )
+        {
+            if ( this.metadata.isEmpty() )
+            {
+                this.metadata = new ArrayList<Metadata>();
+            }
+            this.metadata.add( metadata );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the repository to deploy to.
+     * 
+     * @return The repository to deploy to or {@code null} if not set.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the repository to deploy to.
+     * 
+     * @param repository The repository to deploy to, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest setRepository( RemoteRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    /**
+     * Gets the trace information that describes the higher level request/operation in which this request is issued.
+     * 
+     * @return The trace information about the higher level operation or {@code null} if none.
+     */
+    public RequestTrace getTrace()
+    {
+        return trace;
+    }
+
+    /**
+     * Sets the trace information that describes the higher level request/operation in which this request is issued.
+     * 
+     * @param trace The trace information about the higher level operation, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifacts() + ", " + getMetadata() + " > " + getRepository();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeployResult.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeployResult.java b/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeployResult.java
new file mode 100644
index 0000000..f75705e
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeployResult.java
@@ -0,0 +1,174 @@
+package org.eclipse.aether.deployment;
+
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+
+/**
+ * The result of deploying artifacts and their accompanying metadata into the a remote repository.
+ * 
+ * @see RepositorySystem#deploy(RepositorySystemSession, DeployRequest)
+ */
+public final class DeployResult
+{
+
+    private final DeployRequest request;
+
+    private Collection<Artifact> artifacts;
+
+    private Collection<Metadata> metadata;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The deployment request, must not be {@code null}.
+     */
+    public DeployResult( DeployRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "deploy request has not been specified" );
+        }
+        this.request = request;
+        artifacts = Collections.emptyList();
+        metadata = Collections.emptyList();
+    }
+
+    /**
+     * Gets the deploy request that was made.
+     * 
+     * @return The deploy request, never {@code null}.
+     */
+    public DeployRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the artifacts that got deployed.
+     * 
+     * @return The deployed artifacts, never {@code null}.
+     */
+    public Collection<Artifact> getArtifacts()
+    {
+        return artifacts;
+    }
+
+    /**
+     * Sets the artifacts that got deployed.
+     * 
+     * @param artifacts The deployed artifacts, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DeployResult setArtifacts( Collection<Artifact> artifacts )
+    {
+        if ( artifacts == null )
+        {
+            this.artifacts = Collections.emptyList();
+        }
+        else
+        {
+            this.artifacts = artifacts;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified artifacts to the result.
+     * 
+     * @param artifact The deployed artifact to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DeployResult addArtifact( Artifact artifact )
+    {
+        if ( artifact != null )
+        {
+            if ( artifacts.isEmpty() )
+            {
+                artifacts = new ArrayList<Artifact>();
+            }
+            artifacts.add( artifact );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the metadata that got deployed. Note that due to automatically generated metadata, there might have been
+     * more metadata deployed than originally specified in the deploy request.
+     * 
+     * @return The deployed metadata, never {@code null}.
+     */
+    public Collection<Metadata> getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata that got deployed.
+     * 
+     * @param metadata The deployed metadata, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DeployResult setMetadata( Collection<Metadata> metadata )
+    {
+        if ( metadata == null )
+        {
+            this.metadata = Collections.emptyList();
+        }
+        else
+        {
+            this.metadata = metadata;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified metadata to this result.
+     * 
+     * @param metadata The deployed metadata to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DeployResult addMetadata( Metadata metadata )
+    {
+        if ( metadata != null )
+        {
+            if ( this.metadata.isEmpty() )
+            {
+                this.metadata = new ArrayList<Metadata>();
+            }
+            this.metadata.add( metadata );
+        }
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifacts() + ", " + getMetadata();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeploymentException.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeploymentException.java b/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeploymentException.java
new file mode 100644
index 0000000..53252ba
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/DeploymentException.java
@@ -0,0 +1,52 @@
+package org.eclipse.aether.deployment;
+
+/*
+ * 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 org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of a deployment error like authentication failure.
+ */
+public class DeploymentException
+    extends RepositoryException
+{
+
+    /**
+     * Creates a new exception with the specified detail message.
+     * 
+     * @param message The detail message, may be {@code null}.
+     */
+    public DeploymentException( String message )
+    {
+        super( message );
+    }
+
+    /**
+     * Creates a new exception with the specified detail message and cause.
+     * 
+     * @param message The detail message, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public DeploymentException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/package-info.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/package-info.java b/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/package-info.java
new file mode 100644
index 0000000..dc50c21
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/deployment/package-info.java
@@ -0,0 +1,24 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/*
+ * 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.
+ */
+/**
+ * The types supporting the publishing of artifacts to a remote repository.
+ */
+package org.eclipse.aether.deployment;
+

http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/graph/DefaultDependencyNode.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/graph/DefaultDependencyNode.java b/maven-resolver-api/src/main/java/org/eclipse/aether/graph/DefaultDependencyNode.java
new file mode 100644
index 0000000..a2ffd0c
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/graph/DefaultDependencyNode.java
@@ -0,0 +1,399 @@
+package org.eclipse.aether.graph;
+
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.version.Version;
+import org.eclipse.aether.version.VersionConstraint;
+
+/**
+ * A node within a dependency graph.
+ */
+public final class DefaultDependencyNode
+    implements DependencyNode
+{
+
+    private DependencyNode parent;
+
+    private List<DependencyNode> children;
+
+    private Dependency dependency;
+
+    private Artifact artifact;
+
+    private List<? extends Artifact> relocations;
+
+    private Collection<? extends Artifact> aliases;
+
+    private VersionConstraint versionConstraint;
+
+    private Version version;
+
+    private byte managedBits;
+
+    private List<RemoteRepository> repositories;
+
+    private String context;
+
+    private Map<Object, Object> data;
+
+    /**
+     * Creates a new root node with the specified dependency.
+     *
+     * @param dependency The dependency associated with this node, may be {@code null} for a root node.
+     */
+    public DefaultDependencyNode( Dependency dependency )
+    {
+        this( null, dependency );
+    }
+
+    /**
+     * Creates a new root node with the specified artifact as its label. Note that the new node has no dependency, i.e.
+     * {@link #getDependency()} will return {@code null}. Put differently, the specified artifact will not be subject to
+     * dependency collection/resolution.
+     *
+     * @param artifact The artifact to use as label for this node, may be {@code null}.
+     */
+    public DefaultDependencyNode( Artifact artifact )
+    {
+        super();
+        this.parent = null;
+        this.artifact = artifact;
+        children = new ArrayList<DependencyNode>( 0 );
+        aliases = relocations = Collections.emptyList();
+        repositories = Collections.emptyList();
+        context = "";
+        data = Collections.emptyMap();
+    }
+
+    /**
+     * Creates a mostly shallow clone of the specified node. The new node has its own copy of any custom data and
+     * initially no children.
+     *
+     * @param node The node to copy, must not be {@code null}.
+     */
+    public DefaultDependencyNode( DependencyNode node )
+    {
+        super();
+        parent = node.getParent();
+        dependency = node.getDependency();
+        artifact = node.getArtifact();
+        children = new ArrayList<DependencyNode>( 0 );
+        setAliases( node.getAliases() );
+        setRequestContext( node.getRequestContext() );
+        setManagedBits( node.getManagedBits() );
+        setRelocations( node.getRelocations() );
+        setRepositories( node.getRepositories() );
+        setVersion( node.getVersion() );
+        setVersionConstraint( node.getVersionConstraint() );
+        Map<?, ?> data = node.getData();
+        setData( data.isEmpty() ? null : new HashMap<Object, Object>( data ) );
+    }
+
+    /**
+     * Creates a new node with the specified dependency.
+     *
+     * @param parent The parent node of the node or {@code null}.
+     * @param dependency The dependency associated with this node, may be {@code null} for a root node.
+     *
+     * @since 1.2
+     */
+    public DefaultDependencyNode( DependencyNode parent, Dependency dependency )
+    {
+        super();
+        this.parent = parent;
+        this.dependency = dependency;
+        artifact = ( dependency != null ) ? dependency.getArtifact() : null;
+        children = new ArrayList<DependencyNode>( 0 );
+        aliases = relocations = Collections.emptyList();
+        repositories = Collections.emptyList();
+        context = "";
+        data = Collections.emptyMap();
+    }
+
+    public long getDepth()
+    {
+        return this.getParent() != null ? this.getParent().getDepth() + 1L : 0L;
+    }
+
+    public DependencyNode getParent()
+    {
+        return this.parent;
+    }
+
+    public List<DependencyNode> getChildren()
+    {
+        return children;
+    }
+
+    public void setChildren( List<DependencyNode> children )
+    {
+        if ( children == null )
+        {
+            this.children = new ArrayList<DependencyNode>( 0 );
+        }
+        else
+        {
+            this.children = children;
+        }
+    }
+
+    public Dependency getDependency()
+    {
+        return dependency;
+    }
+
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    public void setArtifact( Artifact artifact )
+    {
+        if ( dependency == null )
+        {
+            throw new UnsupportedOperationException( "node does not have a dependency" );
+        }
+        dependency = dependency.setArtifact( artifact );
+        this.artifact = dependency.getArtifact();
+    }
+
+    public List<? extends Artifact> getRelocations()
+    {
+        return relocations;
+    }
+
+    /**
+     * Sets the sequence of relocations that was followed to resolve this dependency's artifact.
+     *
+     * @param relocations The sequence of relocations, may be {@code null}.
+     */
+    public void setRelocations( List<? extends Artifact> relocations )
+    {
+        if ( relocations == null || relocations.isEmpty() )
+        {
+            this.relocations = Collections.emptyList();
+        }
+        else
+        {
+            this.relocations = relocations;
+        }
+    }
+
+    public Collection<? extends Artifact> getAliases()
+    {
+        return aliases;
+    }
+
+    /**
+     * Sets the known aliases for this dependency's artifact.
+     *
+     * @param aliases The known aliases, may be {@code null}.
+     */
+    public void setAliases( Collection<? extends Artifact> aliases )
+    {
+        if ( aliases == null || aliases.isEmpty() )
+        {
+            this.aliases = Collections.emptyList();
+        }
+        else
+        {
+            this.aliases = aliases;
+        }
+    }
+
+    public VersionConstraint getVersionConstraint()
+    {
+        return versionConstraint;
+    }
+
+    /**
+     * Sets the version constraint that was parsed from the dependency's version declaration.
+     *
+     * @param versionConstraint The version constraint for this node, may be {@code null}.
+     */
+    public void setVersionConstraint( VersionConstraint versionConstraint )
+    {
+        this.versionConstraint = versionConstraint;
+    }
+
+    public Version getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * Sets the version that was selected for the dependency's target artifact.
+     *
+     * @param version The parsed version, may be {@code null}.
+     */
+    public void setVersion( Version version )
+    {
+        this.version = version;
+    }
+
+    public void setScope( String scope )
+    {
+        if ( dependency == null )
+        {
+            throw new UnsupportedOperationException( "node does not have a dependency" );
+        }
+        dependency = dependency.setScope( scope );
+    }
+
+    public void setOptional( Boolean optional )
+    {
+        if ( dependency == null )
+        {
+            throw new UnsupportedOperationException( "node does not have a dependency" );
+        }
+        dependency = dependency.setOptional( optional );
+    }
+
+    public int getManagedBits()
+    {
+        return managedBits;
+    }
+
+    /**
+     * Sets a bit field indicating which attributes of this node were subject to dependency management.
+     *
+     * @param managedBits The bit field indicating the managed attributes or {@code 0} if dependency management wasn't
+     * applied.
+     */
+    public void setManagedBits( int managedBits )
+    {
+        this.managedBits = (byte) ( managedBits & 0x1F );
+    }
+
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the remote repositories from which this node's artifact shall be resolved.
+     *
+     * @param repositories The remote repositories to use for artifact resolution, may be {@code null}.
+     */
+    public void setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null || repositories.isEmpty() )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+    }
+
+    public String getRequestContext()
+    {
+        return context;
+    }
+
+    public void setRequestContext( String context )
+    {
+        this.context = ( context != null ) ? context : "";
+    }
+
+    public Map<Object, Object> getData()
+    {
+        return data;
+    }
+
+    public void setData( Map<Object, Object> data )
+    {
+        if ( data == null )
+        {
+            this.data = Collections.emptyMap();
+        }
+        else
+        {
+            this.data = data;
+        }
+    }
+
+    public void setData( Object key, Object value )
+    {
+        if ( key == null )
+        {
+            throw new IllegalArgumentException( "key must not be null" );
+        }
+
+        if ( value == null )
+        {
+            if ( !data.isEmpty() )
+            {
+                data.remove( key );
+
+                if ( data.isEmpty() )
+                {
+                    data = Collections.emptyMap();
+                }
+            }
+        }
+        else
+        {
+            if ( data.isEmpty() )
+            {
+                data = new HashMap<Object, Object>( 1, 2 ); // nodes can be numerous so let's be space conservative
+            }
+            data.put( key, value );
+        }
+    }
+
+    public boolean accept( DependencyVisitor visitor )
+    {
+        if ( visitor.visitEnter( this ) )
+        {
+            for ( DependencyNode child : children )
+            {
+                if ( !child.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+
+        return visitor.visitLeave( this );
+    }
+
+    @Override
+    public String toString()
+    {
+        Dependency dep = getDependency();
+        if ( dep == null )
+        {
+            return String.valueOf( getArtifact() );
+        }
+        return dep.toString();
+    }
+
+}