You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rf...@apache.org on 2020/02/17 21:04:24 UTC

[maven-artifact-transfer] branch MSHARED-843 created (now a2505ed)

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

rfscholte pushed a change to branch MSHARED-843
in repository https://gitbox.apache.org/repos/asf/maven-artifact-transfer.git.


      at a2505ed  Implement Maven dependency collector to wrap Aether functionality.

This branch includes the following new commits:

     new a2505ed  Implement Maven dependency collector to wrap Aether functionality.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[maven-artifact-transfer] 01/01: Implement Maven dependency collector to wrap Aether functionality.

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MSHARED-843
in repository https://gitbox.apache.org/repos/asf/maven-artifact-transfer.git

commit a2505edefaf797f6492dc8365e0af8fab56c750a
Author: Pim Moerenhout <pi...@gmail.com>
AuthorDate: Wed Jan 1 21:38:36 2020 +0100

    Implement Maven dependency collector to wrap Aether functionality.
---
 src/it/maven-dependency-collector-plugin/pom.xml   | 131 ++++++++
 .../collector/DependencyCollectorMojo.java         |  77 +++++
 .../collector/DependencyCollectorTest.java         |  84 +++++
 .../src/test/projects/example/pom.xml              |  67 ++++
 .../shared/transfer/collection/CollectRequest.java | 307 +++++++++++++++++++
 .../shared/transfer/collection/CollectResult.java  |  49 +++
 .../DependencyCollectionException.java}            |  79 ++---
 .../transfer/collection/DependencyCollector.java   |  78 +++++
 .../internal/DefaultDependencyCollector.java       | 199 ++++++++++++
 .../transfer/collection/internal/Invoker.java      | 166 ++++++++++
 .../internal/Maven30ArtifactRepositoryAdapter.java | 265 ++++++++++++++++
 .../collection/internal/Maven30CollectResult.java  |  68 +++++
 .../internal/Maven30DependencyCollector.java       | 339 +++++++++++----------
 .../internal/Maven30DependencyNodeAdapter.java     | 163 ++++++++++
 .../internal/Maven31ArtifactRepositoryAdapter.java | 265 ++++++++++++++++
 .../collection/internal/Maven31CollectResult.java  |  62 ++++
 .../internal/Maven31DependencyCollector.java}      | 339 +++++++++++----------
 .../internal/Maven31DependencyNodeAdapter.java     | 163 ++++++++++
 .../internal/MavenDependencyCollector.java}        |  80 ++---
 .../dependencies/collect/CollectorResult.java      |   2 +-
 .../internal/DefaultDependencyCollector.java       |  13 +-
 .../internal/Maven30DependencyCollector.java       |   1 -
 .../internal/Maven30DependencyNodeAdapter.java     | 163 ++++++++++
 .../internal/Maven31DependencyNodeAdapter.java     | 163 ++++++++++
 .../shared/transfer/graph/DependencyNode.java      |  69 +++++
 .../shared/transfer/graph/DependencyVisitor.java   |  48 +++
 .../internal/DefaultDependencyCollectorTest.java   | 101 ++++++
 .../internal/DefaultDependencyCollectorTest.java   |   1 -
 28 files changed, 3116 insertions(+), 426 deletions(-)

diff --git a/src/it/maven-dependency-collector-plugin/pom.xml b/src/it/maven-dependency-collector-plugin/pom.xml
new file mode 100644
index 0000000..62ee27a
--- /dev/null
+++ b/src/it/maven-dependency-collector-plugin/pom.xml
@@ -0,0 +1,131 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+  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.
+-->
+
+<project
+  xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.plugins</groupId>
+    <artifactId>maven-plugins</artifactId>
+    <version>31</version>
+    <relativePath />
+  </parent>
+
+  <artifactId>maven-dependency-collector-plugin</artifactId>
+  <version>1.0.0</version>
+  <packaging>maven-plugin</packaging>
+
+  <name>Apache Maven Dependency Collector Plugin</name>
+  <description>The plugin is only intended as a real testing environment for parts 
+    of the maven-artifact-transfer component. In this test we check the DependencyCollector</description>
+  <prerequisites>
+    <maven>${mavenVersion}</maven>
+  </prerequisites>
+
+  <properties>
+    <surefire.version>2.21.0</surefire.version>
+    <mavenVersion>3.0</mavenVersion>
+    <javaVersion>8</javaVersion>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>${mavenVersion}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-artifact</artifactId>
+      <version>${mavenVersion}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.shared</groupId>
+      <artifactId>maven-artifact-transfer</artifactId>
+      <version>@project.version@</version>
+    </dependency>
+
+    <!-- dependencies to annotations -->
+    <dependency>
+      <groupId>org.apache.maven.plugin-tools</groupId>
+      <artifactId>maven-plugin-annotations</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>io.takari.maven.plugins</groupId>
+      <artifactId>takari-plugin-integration-testing</artifactId>
+      <version>2.9.2</version>
+      <type>pom</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>io.takari.maven.plugins</groupId>
+      <artifactId>takari-plugin-testing</artifactId>
+      <version>2.9.2</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.rat</groupId>
+          <artifactId>apache-rat-plugin</artifactId>
+          <configuration>
+            <skip>true</skip>
+          </configuration>
+        </plugin>
+        <plugin>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <configuration>
+            <systemProperties>
+              <maven.local.repo>${maven.local.repo}</maven.local.repo>
+              <localRepositoryPath>${localRepositoryPath}</localRepositoryPath>
+              <mvnVersion>${mvnVersion}</mvnVersion>
+            </systemProperties>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>io.takari.maven.plugins</groupId>
+        <artifactId>takari-lifecycle-plugin</artifactId>
+        <version>1.13.9</version>
+        <executions>
+          <execution>
+            <?m2e ignore ?>
+            <id>testProperties</id>
+            <phase>process-test-resources</phase>
+            <goals>
+              <goal>testProperties</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+
+  </build>
+</project>
diff --git a/src/it/maven-dependency-collector-plugin/src/main/java/org/apache/maven/plugin/dependency/collector/DependencyCollectorMojo.java b/src/it/maven-dependency-collector-plugin/src/main/java/org/apache/maven/plugin/dependency/collector/DependencyCollectorMojo.java
new file mode 100644
index 0000000..eb74bdb
--- /dev/null
+++ b/src/it/maven-dependency-collector-plugin/src/main/java/org/apache/maven/plugin/dependency/collector/DependencyCollectorMojo.java
@@ -0,0 +1,77 @@
+package org.apache.maven.plugin.artifact.installer;
+
+/*
+ * 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.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.model.Model;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.shared.transfer.collection.DependencyCollector;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+
+/**
+ * This mojo is implemented to test the DependencyCollector part of the maven-artifact-transfer shared component.
+ */
+@Mojo( name = "dependency-collector", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true )
+public class DependencyCollectorMojo
+    extends AbstractMojo
+{
+
+    /**
+     * Parameter to have different locations for each Maven version we are testing with.
+     */
+    @Parameter
+    private String mvnVersion;
+
+    @Parameter( defaultValue = "${session}", required = true, readonly = true )
+    protected MavenSession session;
+
+    @Component
+    private DependencyCollector collector;
+
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        getLog().info( "Hello from dependency-collector plugin" );
+        collectDependencies( session.getProjectBuildingRequest(), session.getCurrentProject().getModel() );
+        getLog().info( "Bye bye from dependency-collector plugin" );
+    }
+
+    private void collectDependencies( ProjectBuildingRequest projectBuildingRequest, Model model )
+        throws MojoFailureException, MojoExecutionException
+    {
+        try
+        {
+            collector.collectDependencies( projectBuildingRequest, model );
+        }
+        catch ( DependencyCollectionException e )
+        {
+            throw new MojoExecutionException( "DependencyCollectionException", e );
+        }
+    }
+
+}
diff --git a/src/it/maven-dependency-collector-plugin/src/test/java/org/apache/maven/plugin/dependency/collector/DependencyCollectorTest.java b/src/it/maven-dependency-collector-plugin/src/test/java/org/apache/maven/plugin/dependency/collector/DependencyCollectorTest.java
new file mode 100644
index 0000000..15e51fa
--- /dev/null
+++ b/src/it/maven-dependency-collector-plugin/src/test/java/org/apache/maven/plugin/dependency/collector/DependencyCollectorTest.java
@@ -0,0 +1,84 @@
+package org.apache.maven.plugin.dependency.collector;
+
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import io.takari.maven.testing.TestResources;
+import io.takari.maven.testing.executor.MavenExecutionResult;
+import io.takari.maven.testing.executor.MavenRuntime;
+import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder;
+import io.takari.maven.testing.executor.MavenVersions;
+import io.takari.maven.testing.executor.junit.MavenJUnitTestRunner;
+
+/**
+ * This will check if the DependencyCollector works for all Maven versions 3.0.5, 3.1.1, 3.2.5, 3.3.1, 3.3.9, 3.5.0,
+ * 3.5.4, 3.6.3. This is done by using the test plugin <code>maven-artifact-installer-plugin</code> which uses the
+ * ArtifactInstaller as component. By using this way we get a real runtime environment which supports all Maven
+ * versions.
+ * 
+ * @author Karl Heinz Marbaise
+ */
+@RunWith( MavenJUnitTestRunner.class )
+@MavenVersions( { "3.0.5", "3.1.1", "3.2.5", "3.3.1", "3.3.9", "3.5.0", "3.5.4", "3.6.3" } )
+public class DependencyCollectorTest
+{
+
+    @Rule
+    public final TestResources resources = new TestResources();
+
+    public final MavenRuntime mavenRuntime;
+
+    public DependencyCollectorTest( MavenRuntimeBuilder builder )
+        throws Exception
+    {
+        this.mavenRuntime = builder.build();
+    }
+
+    @Test
+    public void buildExample()
+        throws Exception
+    {
+        File basedir = resources.getBasedir( "example" );
+        //@formatter:off
+        MavenExecutionResult result =
+            mavenRuntime
+                .forProject( basedir )
+                .withCliOption( "-DmvnVersion=" + mavenRuntime.getMavenVersion() ) // Might be superfluous
+                .withCliOption( "-B" )
+                .withCliOption( "-V" )
+                .execute( "clean", "verify" );
+        //@formatter:on
+
+        result.assertErrorFreeLog();
+        // Check that the current plugins has been called at least once.
+        result.assertLogText( "[INFO] --- maven-dependency-collector-plugin:1.0.0:dependency-collector (id-dependency-collector) @ maven-dependency-collector-plugin-it ---" );
+
+        System.out.println( "mavenVersion='" + mavenRuntime.getMavenVersion() + "'" );
+    }
+
+}
\ No newline at end of file
diff --git a/src/it/maven-dependency-collector-plugin/src/test/projects/example/pom.xml b/src/it/maven-dependency-collector-plugin/src/test/projects/example/pom.xml
new file mode 100644
index 0000000..f3624bb
--- /dev/null
+++ b/src/it/maven-dependency-collector-plugin/src/test/projects/example/pom.xml
@@ -0,0 +1,67 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+>
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.shared</groupId>
+    <artifactId>maven-shared-components</artifactId>
+    <version>31</version>
+    <relativePath />
+  </parent>
+
+  <artifactId>maven-dependency-collector-plugin-it</artifactId>
+  <version>1.0.0-A</version>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.rat</groupId>
+          <artifactId>apache-rat-plugin</artifactId>
+          <configuration>
+            <skip>true</skip>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-collector-plugin</artifactId>
+        <version>${it-plugin.version}</version>
+        <configuration>
+          <localRepositoryPath>${localRepositoryPath}</localRepositoryPath>
+          <mvnVersion>${mvnVersion}</mvnVersion>
+        </configuration>
+        <executions>
+          <execution>
+            <id>id-dependency-collector</id>
+            <goals>
+              <goal>dependency-collector</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/CollectRequest.java b/src/main/java/org/apache/maven/shared/transfer/collection/CollectRequest.java
new file mode 100644
index 0000000..be7dbbf
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/CollectRequest.java
@@ -0,0 +1,307 @@
+package org.apache.maven.shared.transfer.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.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * 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 DependencyCollector#collectDependencies(org.apache.maven.project.ProjectBuildingRequest, org.apache.maven.model.Dependency)
+ * @see DependencyCollector#collectDependencies(org.apache.maven.project.ProjectBuildingRequest, org.apache.maven.shared.transfer.dependencies.DependableCoordinate)
+ * @see DependencyCollector#collectDependencies(org.apache.maven.project.ProjectBuildingRequest, org.apache.maven.model.Model)
+ */
+public final class CollectRequest
+{
+
+    private org.apache.maven.artifact.Artifact rootArtifact;
+
+    private Dependency root;
+
+    private List<Dependency> dependencies = Collections.emptyList();
+
+    private List<Dependency> managedDependencies = Collections.emptyList();
+
+    private List<ArtifactRepository> repositories = Collections.emptyList();
+
+    /**
+     * 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<ArtifactRepository> 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<ArtifactRepository> 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<ArtifactRepository> 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<ArtifactRepository> 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<ArtifactRepository> 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( ArtifactRepository repository )
+    {
+        if ( repository != null )
+        {
+            if ( this.repositories.isEmpty() )
+            {
+                this.repositories = new ArrayList<ArtifactRepository>();
+            }
+            this.repositories.add( repository );
+        }
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getRoot() + " -> " + getDependencies() + " < " + getRepositories();
+    }
+
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/CollectResult.java b/src/main/java/org/apache/maven/shared/transfer/collection/CollectResult.java
new file mode 100644
index 0000000..7f30b7d
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/CollectResult.java
@@ -0,0 +1,49 @@
+package org.apache.maven.shared.transfer.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.apache.maven.shared.transfer.graph.DependencyNode;
+
+/**
+ * The result of a dependency collection request.
+ *
+ * @see DependencyCollector#collectDependencies(org.apache.maven.project.ProjectBuildingRequest, org.apache.maven.model.Dependency)
+ * @see DependencyCollector#collectDependencies(org.apache.maven.project.ProjectBuildingRequest, org.apache.maven.shared.transfer.dependencies.DependableCoordinate)
+ * @see DependencyCollector#collectDependencies(org.apache.maven.project.ProjectBuildingRequest, org.apache.maven.model.Model)
+ */
+public interface CollectResult
+{
+  /**
+   * Gets the exceptions that occurred while building the dependency graph.
+   *
+   * @return The exceptions that occurred, never {@code null}.
+   */
+  List<Exception> getExceptions();
+
+  /**
+   * Gets the root node of the dependency graph.
+   *
+   * @return The root node of the dependency graph or {@code null} if none.
+   */
+  DependencyNode getRoot();
+
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java b/src/main/java/org/apache/maven/shared/transfer/collection/DependencyCollectionException.java
similarity index 58%
copy from src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java
copy to src/main/java/org/apache/maven/shared/transfer/collection/DependencyCollectionException.java
index f7b8809..eafcfcf 100644
--- a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/DependencyCollectionException.java
@@ -1,37 +1,42 @@
-package org.apache.maven.shared.transfer.dependencies.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.apache.maven.artifact.repository.ArtifactRepository;
-
-/**
- * 
- * @author Robert Scholte
- *
- */
-public interface CollectorResult
-{
-    /**
-     * @return {@link ArtifactRepository}
-     */
-    List<ArtifactRepository> getRemoteRepositories();
-}
+package org.apache.maven.shared.transfer.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.
+ */
+
+/**
+ * Thrown in case of bad artifact descriptors, version ranges or other issues encountered during calculation of the
+ * dependency graph.
+ */
+public class DependencyCollectionException
+    extends Exception
+{
+    /**
+     *
+     */
+    private static final long serialVersionUID = -3134726259840210686L;
+
+    /**
+     * @param message The message you would give for the exception.
+     * @param cause The cause which is related to the message.
+     */
+    public DependencyCollectionException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/DependencyCollector.java b/src/main/java/org/apache/maven/shared/transfer/collection/DependencyCollector.java
new file mode 100644
index 0000000..28f2ff0
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/DependencyCollector.java
@@ -0,0 +1,78 @@
+package org.apache.maven.shared.transfer.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.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
+
+/**
+ * Will only download the pom files when not available, never the artifact. 
+ * 
+ * @author Robert Scholte
+ *
+ */
+public interface DependencyCollector
+{
+
+    /**
+     * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+     * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+     * artifact files. The supplied session carries various hooks to customize the dependency graph that must be invoked
+     * throughout the operation.
+     *
+     * @param buildingRequest The Maven project buildingrequest, must not be {@code null}.
+     * @param root The Maven Dependency, must not be {@code null}.
+     * @return The collection result, never {@code null}.
+     * @throws DependencyCollectionException If the dependency tree could not be built.
+     */
+    CollectResult collectDependencies( ProjectBuildingRequest buildingRequest, Dependency root )
+        throws DependencyCollectionException;
+
+    /**
+     * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+     * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+     * artifact files. The supplied session carries various hooks to customize the dependency graph that must be invoked
+     * throughout the operation.
+     *
+     * @param buildingRequest The Maven project buildingrequest, must not be {@code null}.
+     * @param root The Maven DependableCoordinate, must not be {@code null}.
+     * @return The collection result, never {@code null}.
+     * @throws DependencyCollectionException If the dependency tree could not be built.
+     */
+    CollectResult collectDependencies( ProjectBuildingRequest buildingRequest, DependableCoordinate root )
+        throws DependencyCollectionException;
+
+    /**
+     * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+     * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+     * artifact files. The supplied session carries various hooks to customize the dependency graph that must be invoked
+     * throughout the operation.
+     *
+     * @param buildingRequest The Maven project buildingrequest, must not be {@code null}.
+     * @param root The Maven model, must not be {@code null}.
+     * @return The collection result, never {@code null}.
+     * @throws DependencyCollectionException If the dependency tree could not be built.
+     */
+    CollectResult collectDependencies( ProjectBuildingRequest buildingRequest, Model root )
+        throws DependencyCollectionException;
+
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/internal/DefaultDependencyCollector.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/DefaultDependencyCollector.java
new file mode 100644
index 0000000..62a8fb2
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/DefaultDependencyCollector.java
@@ -0,0 +1,199 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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 java.util.Objects;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
+import org.apache.maven.shared.transfer.collection.CollectResult;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+import org.apache.maven.shared.transfer.collection.DependencyCollector;
+import org.codehaus.plexus.PlexusConstants;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.context.Context;
+import org.codehaus.plexus.context.ContextException;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
+
+/**
+ * This DependencyCollector passes the request to the proper Maven 3.x implementation
+ *
+ * @author Robert Scholte
+ */
+@Component( role = DependencyCollector.class, hint = "default" )
+class DefaultDependencyCollector implements DependencyCollector, Contextualizable
+{
+    private PlexusContainer container;
+
+    @Override
+    public CollectResult collectDependencies( ProjectBuildingRequest buildingRequest, Dependency root )
+        throws DependencyCollectionException
+    {
+        validateParameters( buildingRequest, root );
+
+        try
+        {
+            return getMavenDependencyCollector( buildingRequest ).collectDependencies( root );
+        }
+        catch ( ComponentLookupException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+
+    @Override
+    public CollectResult collectDependencies( ProjectBuildingRequest buildingRequest, DependableCoordinate root )
+        throws DependencyCollectionException
+    {
+        validateParameters( buildingRequest, root );
+
+        try
+        {
+            return getMavenDependencyCollector( buildingRequest ).collectDependencies( root );
+        }
+        catch ( ComponentLookupException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+
+    @Override
+    public CollectResult collectDependencies( ProjectBuildingRequest buildingRequest, Model root )
+        throws DependencyCollectionException
+    {
+        validateParameters( buildingRequest, root );
+
+        try
+        {
+            return getMavenDependencyCollector( buildingRequest ).collectDependencies( root );
+        }
+        catch ( ComponentLookupException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+  }
+
+  private void validateParameters( ProjectBuildingRequest buildingRequest, DependableCoordinate root )
+  {
+    validateBuildingRequest( buildingRequest );
+    Objects.requireNonNull( root, "The parameter root is not allowed to be null." );
+  }
+
+  private void validateParameters( ProjectBuildingRequest buildingRequest, Dependency root )
+  {
+    validateBuildingRequest( buildingRequest );
+    Objects.requireNonNull( root, "The parameter root is not allowed to be null." );
+  }
+
+  private void validateParameters( ProjectBuildingRequest buildingRequest, Model root )
+  {
+    validateBuildingRequest( buildingRequest );
+    Objects.requireNonNull( root, "The parameter root is not allowed to be null." );
+  }
+
+  private void validateBuildingRequest( ProjectBuildingRequest buildingRequest )
+  {
+    Objects.requireNonNull( buildingRequest, "The parameter buildingRequest is not allowed to be null." );
+  }
+
+  /**
+   * @return true if the current Maven version is Maven 3.1.
+   */
+  private boolean isMaven31()
+  {
+    return canFindCoreClass( "org.eclipse.aether.artifact.Artifact" ); // Maven 3.1 specific
+  }
+
+  private boolean canFindCoreClass( String className )
+  {
+    try
+    {
+      Thread.currentThread().getContextClassLoader().loadClass( className );
+
+      return true;
+    }
+    catch ( ClassNotFoundException e )
+    {
+      return false;
+    }
+  }
+
+  /**
+   * Injects the Plexus content.
+   *
+   * @param context Plexus context to inject.
+   * @throws ContextException if the PlexusContainer could not be located.
+   */
+  public void contextualize( Context context )
+      throws ContextException
+  {
+    container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
+  }
+
+  private MavenDependencyCollector getMavenDependencyCollector( ProjectBuildingRequest buildingRequest )
+      throws ComponentLookupException, DependencyCollectionException
+  {
+    ArtifactHandlerManager artifactHandlerManager = container.lookup( ArtifactHandlerManager.class );
+
+    if ( isMaven31() )
+    {
+      org.eclipse.aether.RepositorySystem m31RepositorySystem =
+          container.lookup( org.eclipse.aether.RepositorySystem.class );
+
+      org.eclipse.aether.RepositorySystemSession session =
+          (org.eclipse.aether.RepositorySystemSession) Invoker.invoke( buildingRequest, "getRepositorySession" );
+
+      @SuppressWarnings( "unchecked" )
+      List<org.eclipse.aether.repository.RemoteRepository> aetherRepositories =
+          (List<org.eclipse.aether.repository.RemoteRepository>) Invoker.invoke( RepositoryUtils.class, "toRepos",
+              List.class,
+              buildingRequest.getRemoteRepositories() );
+
+      return new Maven31DependencyCollector( m31RepositorySystem, artifactHandlerManager, session,
+          aetherRepositories );
+    }
+    else
+    {
+      org.sonatype.aether.RepositorySystem m30RepositorySystem =
+          container.lookup( org.sonatype.aether.RepositorySystem.class );
+
+      org.sonatype.aether.RepositorySystemSession session =
+          (org.sonatype.aether.RepositorySystemSession) Invoker.invoke( buildingRequest, "getRepositorySession" );
+
+      @SuppressWarnings( "unchecked" )
+      List<org.sonatype.aether.repository.RemoteRepository> aetherRepositories =
+          ( List<org.sonatype.aether.repository.RemoteRepository> ) Invoker.invoke( RepositoryUtils.class,
+              "toRepos", List.class,
+              buildingRequest.getRemoteRepositories() );
+
+      return new Maven30DependencyCollector( m30RepositorySystem, artifactHandlerManager, session,
+          aetherRepositories );
+    }
+
+  }
+
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/internal/Invoker.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Invoker.java
new file mode 100644
index 0000000..31951f8
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Invoker.java
@@ -0,0 +1,166 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.lang.reflect.InvocationTargetException;
+
+import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollectorException;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+
+/**
+ * Invokes method on objects using reflection.
+ */
+final class Invoker
+{
+    private Invoker()
+    {
+        // do not instantiate
+    }
+
+    public static Object invoke( Object object, String method )
+        throws DependencyCollectionException
+    {
+        return invoke( object.getClass(), object, method );
+    }
+
+    public static Object invoke( Class<?> objectClazz, Object object, String method )
+        throws DependencyCollectionException
+    {
+        try
+        {
+            return objectClazz.getMethod( method ).invoke( object );
+        }
+        catch ( IllegalAccessException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( InvocationTargetException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( NoSuchMethodException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+
+    public static Object invoke( Object object, String method, Class<?> argClazz, Object arg )
+        throws DependencyCollectionException
+    {
+        try
+        {
+            final Class<?> objectClazz = object.getClass();
+            return objectClazz.getMethod( method, argClazz ).invoke( object, arg );
+        }
+        catch ( IllegalAccessException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( InvocationTargetException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( NoSuchMethodException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+    
+    public static Object invoke( Class<?> objectClazz, String staticMethod, Class<?> argClazz, Object arg )
+                    throws DependencyCollectionException
+    {
+        try
+        {
+            return objectClazz.getMethod( staticMethod, argClazz ).invoke( null, arg );
+        }
+        catch ( IllegalAccessException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( InvocationTargetException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( NoSuchMethodException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+    
+    /**
+     * <strong>Note:</strong> Ensure that argClasses and args have the same number of elements 
+     * 
+     * @param objectClazz the class of the static method
+     * @param staticMethod the static method to call
+     * @param argClasses the classes of the argument, used to select the right static method
+     * @param args the actual arguments to be passed
+     * @return the result of the method invocation
+     * @throws DependencyCollectorException if any checked exception occurs
+     */
+    public static Object invoke( Class<?> objectClazz, String staticMethod, Class<?>[] argClasses, Object[] args )
+                    throws DependencyCollectionException
+    {
+        try
+        {
+            return objectClazz.getMethod( staticMethod, argClasses ).invoke( null, args );
+        }
+        catch ( IllegalAccessException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( InvocationTargetException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( NoSuchMethodException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+
+    public static Object newInstance( Class<?> objectClazz, Class<?> argClazz, Object arg )
+        throws DependencyCollectionException
+    {
+        try
+        {
+            return objectClazz.getConstructor( argClazz ).newInstance( arg );
+        }
+        catch ( InstantiationException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( IllegalAccessException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( InvocationTargetException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+        catch ( NoSuchMethodException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30ArtifactRepositoryAdapter.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30ArtifactRepositoryAdapter.java
new file mode 100644
index 0000000..40d9143
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30ArtifactRepositoryAdapter.java
@@ -0,0 +1,265 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.Authentication;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.repository.Proxy;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.repository.RepositoryPolicy;
+
+/**
+ * ArtifactRepository wrapper around {@link RemoteRepository}
+ * 
+ * @author Robert Scholte
+ *
+ */
+class Maven30ArtifactRepositoryAdapter implements ArtifactRepository
+{
+    private static final String LS = System.lineSeparator();
+    private RemoteRepository remoteRepository;
+
+    /**
+     * @param remoteRepository {@link RemoteRepository}
+     */
+    Maven30ArtifactRepositoryAdapter( RemoteRepository remoteRepository )
+    {
+        this.remoteRepository = remoteRepository;
+    }
+
+    @Override
+    public String pathOf( Artifact artifact )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getUrl()
+    {
+        return remoteRepository.getUrl();
+    }
+
+    @Override
+    public void setUrl( String url )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getBasedir()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getProtocol()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getId()
+    {
+        return remoteRepository.getId();
+    }
+
+    @Override
+    public void setId( String id )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArtifactRepositoryPolicy getSnapshots()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy policy )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArtifactRepositoryPolicy getReleases()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy policy )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArtifactRepositoryLayout getLayout()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setLayout( ArtifactRepositoryLayout layout )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getKey()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isUniqueVersion()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isBlacklisted()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBlacklisted( boolean blackListed )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Artifact find( Artifact artifact )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<String> findVersions( Artifact artifact )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isProjectAware()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAuthentication( Authentication authentication )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Authentication getAuthentication()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setProxy( Proxy proxy )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Proxy getProxy()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "       id: " ).append( getId() ).append( LS );
+        sb.append( "      url: " ).append( getUrl() ).append( LS );
+        sb.append( "   layout: " ).append( "default" ).append( LS );
+
+        RepositoryPolicy snapshotPolicy = remoteRepository.getPolicy( true ); 
+        sb.append( "snapshots: [enabled => " ).append( snapshotPolicy.isEnabled() );
+        sb.append( ", update => " ).append( snapshotPolicy.getUpdatePolicy() ).append( "]" ).append( LS );
+
+        RepositoryPolicy releasePolicy = remoteRepository.getPolicy( false ); 
+        sb.append( " releases: [enabled => " ).append( releasePolicy.isEnabled() );
+        sb.append( ", update => " ).append( releasePolicy.getUpdatePolicy() ).append( "]" ).append( LS );
+
+        return sb.toString();
+    }
+    
+    @Override
+    public int hashCode()
+    {
+        return remoteRepository.hashCode();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        
+        Maven30ArtifactRepositoryAdapter other = (Maven30ArtifactRepositoryAdapter) obj;
+        if ( remoteRepository == null )
+        {
+            if ( other.remoteRepository != null )
+            {
+                return false;
+            }
+        }
+        else if ( !remoteRepository.equals( other.remoteRepository ) )
+        {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30CollectResult.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30CollectResult.java
new file mode 100644
index 0000000..c5e6c90
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30CollectResult.java
@@ -0,0 +1,68 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.apache.maven.shared.transfer.collection.CollectResult;
+import org.apache.maven.shared.transfer.graph.DependencyNode;
+
+
+/**
+ * CollectResult wrapper around {@link CollectResult}
+ * 
+ * @author Pim Moerenhout
+ *
+ */
+class Maven30CollectResult implements CollectResult
+{
+    private final org.sonatype.aether.collection.CollectResult collectResult;
+
+    /**
+     * @param collectResult {@link CollectResult}
+     */
+    Maven30CollectResult( org.sonatype.aether.collection.CollectResult collectResult )
+    {
+        this.collectResult = collectResult;
+    }
+
+    @Override
+    public List<Exception> getExceptions()
+    {
+        return collectResult.getExceptions();
+    }
+
+    /**
+     * Gets the root node of the dependency graph.
+     *
+     * @return The root node of the dependency graph or {@code null} if none.
+     */
+    @Override
+    public DependencyNode getRoot()
+    {
+        return new Maven30DependencyNodeAdapter( collectResult.getRoot() );
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.valueOf( getRoot() );
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30DependencyCollector.java
similarity index 76%
copy from src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java
copy to src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30DependencyCollector.java
index 4b4eaf2..67e3556 100644
--- a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30DependencyCollector.java
@@ -1,169 +1,170 @@
-package org.apache.maven.shared.transfer.dependencies.collect.internal;
-
-/*
- * 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.List;
-
-import org.apache.maven.RepositoryUtils;
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
-import org.apache.maven.model.Model;
-
-import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
-import org.apache.maven.shared.transfer.dependencies.collect.CollectorResult;
-import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollector;
-import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollectorException;
-import org.sonatype.aether.RepositorySystem;
-import org.sonatype.aether.RepositorySystemSession;
-import org.sonatype.aether.artifact.Artifact;
-import org.sonatype.aether.artifact.ArtifactTypeRegistry;
-import org.sonatype.aether.collection.CollectRequest;
-import org.sonatype.aether.collection.DependencyCollectionException;
-import org.sonatype.aether.graph.Dependency;
-import org.sonatype.aether.repository.RemoteRepository;
-import org.sonatype.aether.util.artifact.DefaultArtifact;
-
-/**
- * Maven 3.0 implementation of the {@link DependencyCollector}
- * 
- * @author Robert Scholte
- *
- */
-class Maven30DependencyCollector
-    implements MavenDependencyCollector
-{
-    private final RepositorySystem repositorySystem;
-
-    private final ArtifactHandlerManager artifactHandlerManager;
-
-    private final RepositorySystemSession session;
-    
-    private final List<RemoteRepository> aetherRepositories;
-    
-    Maven30DependencyCollector( RepositorySystem repositorySystem, ArtifactHandlerManager artifactHandlerManager,
-                                RepositorySystemSession session, List<RemoteRepository> aetherRepositories )
-    {
-        super();
-        this.repositorySystem = repositorySystem;
-        this.artifactHandlerManager = artifactHandlerManager;
-        this.session = session;
-        this.aetherRepositories = aetherRepositories;
-    }
-
-    @Override
-    public CollectorResult collectDependencies( org.apache.maven.model.Dependency root )
-        throws DependencyCollectorException
-    {
-        ArtifactTypeRegistry typeRegistry =
-                        (ArtifactTypeRegistry) Invoker.invoke( RepositoryUtils.class, "newArtifactTypeRegistry",
-                                                               ArtifactHandlerManager.class, artifactHandlerManager );
-
-        CollectRequest request = new CollectRequest();
-        request.setRoot( toDependency( root, typeRegistry ) );
-
-        return collectDependencies( request );
-    }
-
-    @Override
-    public CollectorResult collectDependencies( DependableCoordinate root )
-        throws DependencyCollectorException
-    {
-        ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( root.getType() );
-        
-        String extension = artifactHandler != null ? artifactHandler.getExtension() : null;
-        
-        Artifact aetherArtifact = new DefaultArtifact( root.getGroupId(), root.getArtifactId(), root.getClassifier(),
-                                                       extension, root.getVersion() );
-        
-        CollectRequest request = new CollectRequest();
-        request.setRoot( new Dependency( aetherArtifact, null ) );
-
-        return collectDependencies( request );
-    }
-    
-    @Override
-    public CollectorResult collectDependencies( Model root )
-        throws DependencyCollectorException
-    {
-        // Are there examples where packaging and type are NOT in sync
-        ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( root.getPackaging() );
-        
-        String extension = artifactHandler != null ? artifactHandler.getExtension() : null;
-        
-        Artifact aetherArtifact =
-            new DefaultArtifact( root.getGroupId(), root.getArtifactId(), extension, root.getVersion() );
-        
-        CollectRequest request = new CollectRequest();
-        request.setRoot( new Dependency( aetherArtifact, null ) );
-
-        ArtifactTypeRegistry typeRegistry =
-                        (ArtifactTypeRegistry) Invoker.invoke( RepositoryUtils.class, "newArtifactTypeRegistry",
-                                                               ArtifactHandlerManager.class, artifactHandlerManager );
-
-        List<Dependency> aetherDependencies = new ArrayList<Dependency>( root.getDependencies().size() );
-        for ( org.apache.maven.model.Dependency mavenDependency : root.getDependencies() )
-        {
-            aetherDependencies.add( toDependency( mavenDependency, typeRegistry ) );
-        }
-        request.setDependencies( aetherDependencies );
-
-        if ( root.getDependencyManagement() != null )
-        {
-            List<Dependency> aetherManagerDependencies =
-                new ArrayList<Dependency>( root.getDependencyManagement().getDependencies().size() );
-            
-            for ( org.apache.maven.model.Dependency mavenDependency : root.getDependencyManagement().getDependencies() )
-            {
-                aetherManagerDependencies.add( toDependency( mavenDependency, typeRegistry ) );
-            }
-            
-            request.setManagedDependencies( aetherManagerDependencies );
-        }
-        
-        return collectDependencies( request );
-    }
-
-    private CollectorResult collectDependencies( CollectRequest request )
-        throws DependencyCollectorException
-    {
-        request.setRepositories( aetherRepositories );
-
-        try
-        {
-            return new Maven30CollectorResult( repositorySystem.collectDependencies( session, request ) );
-        }
-        catch ( DependencyCollectionException e )
-        {
-            throw new DependencyCollectorException( e.getMessage(), e );
-        }
-    }
-
-    private static Dependency toDependency( org.apache.maven.model.Dependency mavenDependency,
-                                            ArtifactTypeRegistry typeRegistry )
-        throws DependencyCollectorException
-    {
-        Class<?>[] argClasses = new Class<?>[] { org.apache.maven.model.Dependency.class, ArtifactTypeRegistry.class };
-
-        Object[] args = new Object[] { mavenDependency, typeRegistry };
-
-        return (Dependency) Invoker.invoke( RepositoryUtils.class, "toDependency", argClasses, args );
-    }
-}
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.List;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.model.Model;
+import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
+import org.apache.maven.shared.transfer.collection.CollectResult;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+import org.apache.maven.shared.transfer.collection.DependencyCollector;
+import org.sonatype.aether.RepositorySystem;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.artifact.ArtifactTypeRegistry;
+import org.sonatype.aether.collection.CollectRequest;
+import org.sonatype.aether.graph.Dependency;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+
+/**
+ * Maven 3.0 implementation of the {@link DependencyCollector}
+ * 
+ * @author Robert Scholte
+ *
+ */
+class Maven30DependencyCollector
+    implements MavenDependencyCollector
+{
+    private final RepositorySystem repositorySystem;
+
+    private final ArtifactHandlerManager artifactHandlerManager;
+
+    private final RepositorySystemSession session;
+    
+    private final List<RemoteRepository> aetherRepositories;
+    
+    Maven30DependencyCollector( RepositorySystem repositorySystem, ArtifactHandlerManager artifactHandlerManager,
+                                RepositorySystemSession session, List<RemoteRepository> aetherRepositories )
+    {
+        super();
+        this.repositorySystem = repositorySystem;
+        this.artifactHandlerManager = artifactHandlerManager;
+        this.session = session;
+        this.aetherRepositories = aetherRepositories;
+    }
+
+    @Override
+    public CollectResult collectDependencies( org.apache.maven.model.Dependency root )
+        throws DependencyCollectionException
+    {
+        ArtifactTypeRegistry typeRegistry =
+                        (ArtifactTypeRegistry) Invoker
+                            .invoke( RepositoryUtils.class, "newArtifactTypeRegistry",
+                                                               ArtifactHandlerManager.class, artifactHandlerManager );
+
+        CollectRequest request = new CollectRequest();
+        request.setRoot( toDependency( root, typeRegistry ) );
+
+        return collectDependencies( request );
+    }
+
+    @Override
+    public CollectResult collectDependencies( DependableCoordinate root )
+        throws DependencyCollectionException
+    {
+        ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( root.getType() );
+
+        String extension = artifactHandler != null ? artifactHandler.getExtension() : null;
+
+        Artifact aetherArtifact = new DefaultArtifact( root.getGroupId(), root.getArtifactId(), root.getClassifier(),
+                                                       extension, root.getVersion() );
+
+        CollectRequest request = new CollectRequest();
+        request.setRoot( new Dependency( aetherArtifact, null ) );
+
+        return collectDependencies( request );
+    }
+
+    @Override
+    public CollectResult collectDependencies( Model root )
+        throws DependencyCollectionException
+    {
+        // Are there examples where packaging and type are NOT in sync
+        ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( root.getPackaging() );
+
+        String extension = artifactHandler != null ? artifactHandler.getExtension() : null;
+
+        Artifact aetherArtifact =
+            new DefaultArtifact( root.getGroupId(), root.getArtifactId(), extension, root.getVersion() );
+
+        CollectRequest request = new CollectRequest();
+        request.setRoot( new Dependency( aetherArtifact, null ) );
+
+        ArtifactTypeRegistry typeRegistry =
+                        (ArtifactTypeRegistry) Invoker
+                            .invoke( RepositoryUtils.class, "newArtifactTypeRegistry",
+                                                               ArtifactHandlerManager.class, artifactHandlerManager );
+
+        List<Dependency> aetherDependencies = new ArrayList<Dependency>( root.getDependencies().size() );
+        for ( org.apache.maven.model.Dependency mavenDependency : root.getDependencies() )
+        {
+            aetherDependencies.add( toDependency( mavenDependency, typeRegistry ) );
+        }
+        request.setDependencies( aetherDependencies );
+
+        if ( root.getDependencyManagement() != null )
+        {
+            List<Dependency> aetherManagerDependencies =
+                new ArrayList<Dependency>( root.getDependencyManagement().getDependencies().size() );
+
+            for ( org.apache.maven.model.Dependency mavenDependency : root.getDependencyManagement().getDependencies() )
+            {
+                aetherManagerDependencies.add( toDependency( mavenDependency, typeRegistry ) );
+            }
+
+            request.setManagedDependencies( aetherManagerDependencies );
+        }
+
+        return collectDependencies( request );
+    }
+
+    private CollectResult collectDependencies( CollectRequest request )
+        throws DependencyCollectionException
+    {
+        request.setRepositories( aetherRepositories );
+
+        try
+        {
+            return new Maven30CollectResult( repositorySystem.collectDependencies( session, request ) );
+        }
+        catch ( org.sonatype.aether.collection.DependencyCollectionException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+
+    private static Dependency toDependency( org.apache.maven.model.Dependency mavenDependency,
+                                            ArtifactTypeRegistry typeRegistry )
+        throws DependencyCollectionException
+    {
+        Class<?>[] argClasses = new Class<?>[] { org.apache.maven.model.Dependency.class, ArtifactTypeRegistry.class };
+
+        Object[] args = new Object[] { mavenDependency, typeRegistry };
+
+        return (Dependency) Invoker
+            .invoke( RepositoryUtils.class, "toDependency", argClasses, args );
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30DependencyNodeAdapter.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30DependencyNodeAdapter.java
new file mode 100644
index 0000000..052353f
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven30DependencyNodeAdapter.java
@@ -0,0 +1,163 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.List;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+import org.apache.maven.shared.transfer.graph.DependencyNode;
+import org.apache.maven.shared.transfer.graph.DependencyVisitor;
+import org.sonatype.aether.repository.RemoteRepository;
+
+/**
+ * DependencyCollectorNode wrapper around {@link org.sonatype.aether.graph.DependencyNode}
+ * 
+ * @author Pim Moerenhout
+ *
+ */
+class Maven30DependencyNodeAdapter implements DependencyNode
+{
+
+    private org.sonatype.aether.graph.DependencyNode dependencyNode;
+
+    /**
+     * @param dependencyNode {@link org.sonatype.aether.graph.DependencyNode}
+     */
+    Maven30DependencyNodeAdapter( org.sonatype.aether.graph.DependencyNode dependencyNode )
+    {
+        this.dependencyNode = dependencyNode;
+    }
+
+    @Override
+    public Artifact getArtifact()
+    {
+        return getArtifact( dependencyNode.getDependency().getArtifact() );
+    }
+
+    @Override
+    public List<DependencyNode> getChildren()
+    {
+        List<org.sonatype.aether.graph.DependencyNode> aetherChildren = dependencyNode.getChildren();
+        List<DependencyNode> children = new ArrayList<>( aetherChildren.size() );
+        for ( org.sonatype.aether.graph.DependencyNode aetherChild : aetherChildren )
+        {
+            children.add( new Maven30DependencyNodeAdapter( aetherChild ) );
+        }
+        return children;
+    }
+
+    @Override
+    public List<ArtifactRepository> getRemoteRepositories()
+    {
+        List<RemoteRepository> aetherRepositories = dependencyNode.getRepositories();
+        List<ArtifactRepository> mavenRepositories = new ArrayList<ArtifactRepository>( aetherRepositories.size() );
+
+        for ( RemoteRepository aetherRepository : aetherRepositories )
+        {
+            mavenRepositories.add( new Maven30ArtifactRepositoryAdapter( aetherRepository ) );
+        }
+
+        return mavenRepositories;
+    }
+
+    @Override
+    public Boolean getOptional()
+    {
+        return dependencyNode.getDependency().isOptional();
+    }
+
+    @Override
+    public String getScope()
+    {
+        return dependencyNode.getDependency().getScope();
+    }
+
+    @Override
+    public boolean accept( DependencyVisitor visitor )
+    {
+        if ( visitor.visitEnter( this ) )
+        {
+            for ( org.sonatype.aether.graph.DependencyNode aetherNode : dependencyNode.getChildren() )
+            {
+                DependencyNode child = new Maven30DependencyNodeAdapter( aetherNode );
+                if ( !child.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+
+        return visitor.visitLeave( this );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return dependencyNode.hashCode();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+
+        Maven30DependencyNodeAdapter other = (Maven30DependencyNodeAdapter) obj;
+        if ( dependencyNode == null )
+        {
+            if ( other.dependencyNode != null )
+            {
+                return false;
+            }
+        }
+        else if ( !dependencyNode.equals( other.dependencyNode ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private Artifact getArtifact( org.sonatype.aether.artifact.Artifact aetherArtifact )
+    {
+        try
+        {
+            return (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
+                org.sonatype.aether.artifact.Artifact.class, aetherArtifact );
+        }
+        catch ( DependencyCollectionException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31ArtifactRepositoryAdapter.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31ArtifactRepositoryAdapter.java
new file mode 100644
index 0000000..d53a452
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31ArtifactRepositoryAdapter.java
@@ -0,0 +1,265 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.Authentication;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.repository.Proxy;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.repository.RepositoryPolicy;
+
+/**
+ * ArtifactRepository wrapper around {@link RemoteRepository}
+ * 
+ * @author Robert Scholte
+ *
+ */
+class Maven31ArtifactRepositoryAdapter implements ArtifactRepository
+{
+    private static final String LS = System.lineSeparator();
+    private RemoteRepository remoteRepository;
+
+    /**
+     * @param remoteRepository {@link RemoteRepository}
+     */
+    Maven31ArtifactRepositoryAdapter( RemoteRepository remoteRepository )
+    {
+        this.remoteRepository = remoteRepository;
+    }
+
+    @Override
+    public String pathOf( Artifact artifact )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getUrl()
+    {
+        return remoteRepository.getUrl();
+    }
+
+    @Override
+    public void setUrl( String url )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getBasedir()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getProtocol()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getId()
+    {
+        return remoteRepository.getId();
+    }
+
+    @Override
+    public void setId( String id )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArtifactRepositoryPolicy getSnapshots()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy policy )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArtifactRepositoryPolicy getReleases()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy policy )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArtifactRepositoryLayout getLayout()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setLayout( ArtifactRepositoryLayout layout )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getKey()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isUniqueVersion()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isBlacklisted()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBlacklisted( boolean blackListed )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Artifact find( Artifact artifact )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<String> findVersions( Artifact artifact )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isProjectAware()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAuthentication( Authentication authentication )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Authentication getAuthentication()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setProxy( Proxy proxy )
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Proxy getProxy()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "       id: " ).append( getId() ).append( LS );
+        sb.append( "      url: " ).append( getUrl() ).append( LS );
+        sb.append( "   layout: " ).append( "default" ).append( LS );
+
+        RepositoryPolicy snapshotPolicy = remoteRepository.getPolicy( true ); 
+        sb.append( "snapshots: [enabled => " ).append( snapshotPolicy.isEnabled() );
+        sb.append( ", update => " ).append( snapshotPolicy.getUpdatePolicy() ).append( "]" ).append( LS );
+
+        RepositoryPolicy releasePolicy = remoteRepository.getPolicy( false ); 
+        sb.append( " releases: [enabled => " ).append( releasePolicy.isEnabled() );
+        sb.append( ", update => " ).append( releasePolicy.getUpdatePolicy() ).append( "]" ).append( LS );
+
+        return sb.toString();
+    }
+    
+    @Override
+    public int hashCode()
+    {
+        return remoteRepository.hashCode();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        
+        Maven31ArtifactRepositoryAdapter other = (Maven31ArtifactRepositoryAdapter) obj;
+        if ( remoteRepository == null )
+        {
+            if ( other.remoteRepository != null )
+            {
+                return false;
+            }
+        }
+        else if ( !remoteRepository.equals( other.remoteRepository ) )
+        {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31CollectResult.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31CollectResult.java
new file mode 100644
index 0000000..8a95ad7
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31CollectResult.java
@@ -0,0 +1,62 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.apache.maven.shared.transfer.collection.CollectResult;
+import org.apache.maven.shared.transfer.graph.DependencyNode;
+
+/**
+ * CollectResult wrapper around {@link CollectResult}
+ * 
+ * @author Pim Moerenhout
+ *
+ */
+class Maven31CollectResult implements CollectResult
+{
+    private final org.eclipse.aether.collection.CollectResult collectResult;
+    
+    /**
+     * @param collectResult {@link CollectResult}
+     */
+    Maven31CollectResult( org.eclipse.aether.collection.CollectResult collectResult )
+    {
+        this.collectResult = collectResult;
+    }
+
+    /**
+     * Gets the root node of the dependency graph.
+     *
+     * @return The root node of the dependency graph or {@code null} if none.
+     */
+    @Override
+    public DependencyNode getRoot()
+    {
+        return new Maven31DependencyNodeAdapter( collectResult.getRoot() );
+    }
+
+    @Override
+    public List<Exception> getExceptions()
+    {
+        return collectResult.getExceptions();
+    }
+
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31DependencyCollector.java
similarity index 65%
copy from src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java
copy to src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31DependencyCollector.java
index 4b4eaf2..b6c5744 100644
--- a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31DependencyCollector.java
@@ -1,169 +1,170 @@
-package org.apache.maven.shared.transfer.dependencies.collect.internal;
-
-/*
- * 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.List;
-
-import org.apache.maven.RepositoryUtils;
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
-import org.apache.maven.model.Model;
-
-import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
-import org.apache.maven.shared.transfer.dependencies.collect.CollectorResult;
-import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollector;
-import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollectorException;
-import org.sonatype.aether.RepositorySystem;
-import org.sonatype.aether.RepositorySystemSession;
-import org.sonatype.aether.artifact.Artifact;
-import org.sonatype.aether.artifact.ArtifactTypeRegistry;
-import org.sonatype.aether.collection.CollectRequest;
-import org.sonatype.aether.collection.DependencyCollectionException;
-import org.sonatype.aether.graph.Dependency;
-import org.sonatype.aether.repository.RemoteRepository;
-import org.sonatype.aether.util.artifact.DefaultArtifact;
-
-/**
- * Maven 3.0 implementation of the {@link DependencyCollector}
- * 
- * @author Robert Scholte
- *
- */
-class Maven30DependencyCollector
-    implements MavenDependencyCollector
-{
-    private final RepositorySystem repositorySystem;
-
-    private final ArtifactHandlerManager artifactHandlerManager;
-
-    private final RepositorySystemSession session;
-    
-    private final List<RemoteRepository> aetherRepositories;
-    
-    Maven30DependencyCollector( RepositorySystem repositorySystem, ArtifactHandlerManager artifactHandlerManager,
-                                RepositorySystemSession session, List<RemoteRepository> aetherRepositories )
-    {
-        super();
-        this.repositorySystem = repositorySystem;
-        this.artifactHandlerManager = artifactHandlerManager;
-        this.session = session;
-        this.aetherRepositories = aetherRepositories;
-    }
-
-    @Override
-    public CollectorResult collectDependencies( org.apache.maven.model.Dependency root )
-        throws DependencyCollectorException
-    {
-        ArtifactTypeRegistry typeRegistry =
-                        (ArtifactTypeRegistry) Invoker.invoke( RepositoryUtils.class, "newArtifactTypeRegistry",
-                                                               ArtifactHandlerManager.class, artifactHandlerManager );
-
-        CollectRequest request = new CollectRequest();
-        request.setRoot( toDependency( root, typeRegistry ) );
-
-        return collectDependencies( request );
-    }
-
-    @Override
-    public CollectorResult collectDependencies( DependableCoordinate root )
-        throws DependencyCollectorException
-    {
-        ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( root.getType() );
-        
-        String extension = artifactHandler != null ? artifactHandler.getExtension() : null;
-        
-        Artifact aetherArtifact = new DefaultArtifact( root.getGroupId(), root.getArtifactId(), root.getClassifier(),
-                                                       extension, root.getVersion() );
-        
-        CollectRequest request = new CollectRequest();
-        request.setRoot( new Dependency( aetherArtifact, null ) );
-
-        return collectDependencies( request );
-    }
-    
-    @Override
-    public CollectorResult collectDependencies( Model root )
-        throws DependencyCollectorException
-    {
-        // Are there examples where packaging and type are NOT in sync
-        ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( root.getPackaging() );
-        
-        String extension = artifactHandler != null ? artifactHandler.getExtension() : null;
-        
-        Artifact aetherArtifact =
-            new DefaultArtifact( root.getGroupId(), root.getArtifactId(), extension, root.getVersion() );
-        
-        CollectRequest request = new CollectRequest();
-        request.setRoot( new Dependency( aetherArtifact, null ) );
-
-        ArtifactTypeRegistry typeRegistry =
-                        (ArtifactTypeRegistry) Invoker.invoke( RepositoryUtils.class, "newArtifactTypeRegistry",
-                                                               ArtifactHandlerManager.class, artifactHandlerManager );
-
-        List<Dependency> aetherDependencies = new ArrayList<Dependency>( root.getDependencies().size() );
-        for ( org.apache.maven.model.Dependency mavenDependency : root.getDependencies() )
-        {
-            aetherDependencies.add( toDependency( mavenDependency, typeRegistry ) );
-        }
-        request.setDependencies( aetherDependencies );
-
-        if ( root.getDependencyManagement() != null )
-        {
-            List<Dependency> aetherManagerDependencies =
-                new ArrayList<Dependency>( root.getDependencyManagement().getDependencies().size() );
-            
-            for ( org.apache.maven.model.Dependency mavenDependency : root.getDependencyManagement().getDependencies() )
-            {
-                aetherManagerDependencies.add( toDependency( mavenDependency, typeRegistry ) );
-            }
-            
-            request.setManagedDependencies( aetherManagerDependencies );
-        }
-        
-        return collectDependencies( request );
-    }
-
-    private CollectorResult collectDependencies( CollectRequest request )
-        throws DependencyCollectorException
-    {
-        request.setRepositories( aetherRepositories );
-
-        try
-        {
-            return new Maven30CollectorResult( repositorySystem.collectDependencies( session, request ) );
-        }
-        catch ( DependencyCollectionException e )
-        {
-            throw new DependencyCollectorException( e.getMessage(), e );
-        }
-    }
-
-    private static Dependency toDependency( org.apache.maven.model.Dependency mavenDependency,
-                                            ArtifactTypeRegistry typeRegistry )
-        throws DependencyCollectorException
-    {
-        Class<?>[] argClasses = new Class<?>[] { org.apache.maven.model.Dependency.class, ArtifactTypeRegistry.class };
-
-        Object[] args = new Object[] { mavenDependency, typeRegistry };
-
-        return (Dependency) Invoker.invoke( RepositoryUtils.class, "toDependency", argClasses, args );
-    }
-}
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.List;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.model.Model;
+import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
+import org.apache.maven.shared.transfer.collection.CollectResult;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+import org.apache.maven.shared.transfer.collection.DependencyCollector;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Maven 3.1+ implementation of the {@link DependencyCollector}
+ * 
+ * @author Robert Scholte
+ *
+ */
+class Maven31DependencyCollector
+    implements MavenDependencyCollector
+{
+    private final RepositorySystem repositorySystem;
+
+    private final ArtifactHandlerManager artifactHandlerManager;
+    
+    private final RepositorySystemSession session;
+    
+    private final List<RemoteRepository> aetherRepositories;
+    
+    Maven31DependencyCollector( RepositorySystem repositorySystem, ArtifactHandlerManager artifactHandlerManager,
+                                RepositorySystemSession session, List<RemoteRepository> aetherRepositories )
+    {
+        super();
+        this.repositorySystem = repositorySystem;
+        this.artifactHandlerManager = artifactHandlerManager;
+        this.session = session;
+        this.aetherRepositories = aetherRepositories;
+    }
+
+    @Override
+    public CollectResult collectDependencies( org.apache.maven.model.Dependency root )
+        throws DependencyCollectionException
+    {
+        ArtifactTypeRegistry typeRegistry =
+                        (ArtifactTypeRegistry) Invoker
+                            .invoke( RepositoryUtils.class, "newArtifactTypeRegistry",
+                                                               ArtifactHandlerManager.class, artifactHandlerManager );
+
+        CollectRequest request = new CollectRequest();
+        request.setRoot( toDependency( root, typeRegistry ) );
+
+        return collectDependencies( request );
+    }
+
+    @Override
+    public CollectResult collectDependencies( DependableCoordinate root )
+        throws DependencyCollectionException
+    {
+        ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( root.getType() );
+
+        String extension = artifactHandler != null ? artifactHandler.getExtension() : null;
+
+        Artifact aetherArtifact = new DefaultArtifact( root.getGroupId(), root.getArtifactId(), root.getClassifier(),
+                                                       extension, root.getVersion() );
+
+        CollectRequest request = new CollectRequest();
+        request.setRoot( new Dependency( aetherArtifact, null ) );
+
+        return collectDependencies( request );
+    }
+
+    @Override
+    public CollectResult collectDependencies( Model root )
+        throws DependencyCollectionException
+    {
+        // Are there examples where packaging and type are NOT in sync
+        ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( root.getPackaging() );
+
+        String extension = artifactHandler != null ? artifactHandler.getExtension() : null;
+
+        Artifact aetherArtifact =
+            new DefaultArtifact( root.getGroupId(), root.getArtifactId(), extension, root.getVersion() );
+
+        CollectRequest request = new CollectRequest();
+        request.setRoot( new Dependency( aetherArtifact, null ) );
+
+        ArtifactTypeRegistry typeRegistry =
+                        (ArtifactTypeRegistry) Invoker
+                            .invoke( RepositoryUtils.class, "newArtifactTypeRegistry",
+                                                               ArtifactHandlerManager.class, artifactHandlerManager );
+
+        List<Dependency> aetherDependencies = new ArrayList<Dependency>( root.getDependencies().size() );
+        for ( org.apache.maven.model.Dependency mavenDependency : root.getDependencies() )
+        {
+            aetherDependencies.add( toDependency( mavenDependency, typeRegistry ) );
+        }
+        request.setDependencies( aetherDependencies );
+
+        if ( root.getDependencyManagement() != null )
+        {
+            List<Dependency> aetherManagerDependencies =
+                new ArrayList<Dependency>( root.getDependencyManagement().getDependencies().size() );
+
+            for ( org.apache.maven.model.Dependency mavenDependency : root.getDependencyManagement().getDependencies() )
+            {
+                aetherManagerDependencies.add( toDependency( mavenDependency, typeRegistry ) );
+            }
+
+            request.setManagedDependencies( aetherManagerDependencies );
+        }
+
+        return collectDependencies( request );
+    }
+
+    private CollectResult collectDependencies( CollectRequest request )
+        throws DependencyCollectionException
+    {
+        request.setRepositories( aetherRepositories );
+
+        try
+        {
+            return new Maven31CollectResult( repositorySystem.collectDependencies( session, request ) );
+        }
+        catch ( org.eclipse.aether.collection.DependencyCollectionException e )
+        {
+            throw new DependencyCollectionException( e.getMessage(), e );
+        }
+    }
+
+    private static Dependency toDependency( org.apache.maven.model.Dependency root, ArtifactTypeRegistry typeRegistry )
+                    throws DependencyCollectionException
+    {
+        Class<?>[] argClasses = new Class<?>[] { org.apache.maven.model.Dependency.class, ArtifactTypeRegistry.class };
+
+        Object[] args = new Object[] { root, typeRegistry };
+
+        return (Dependency) Invoker
+            .invoke( RepositoryUtils.class, "toDependency", argClasses, args );
+    }
+
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31DependencyNodeAdapter.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31DependencyNodeAdapter.java
new file mode 100644
index 0000000..3b3dbb7
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/Maven31DependencyNodeAdapter.java
@@ -0,0 +1,163 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.List;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+import org.apache.maven.shared.transfer.graph.DependencyNode;
+import org.apache.maven.shared.transfer.graph.DependencyVisitor;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * DependencyCollectorNode wrapper around {@link org.eclipse.aether.graph.DependencyNode}
+ *
+ * @author Pim Moerenhout
+ *
+ */
+class Maven31DependencyNodeAdapter implements DependencyNode
+{
+
+    private org.eclipse.aether.graph.DependencyNode dependencyNode;
+
+    /**
+     * @param dependencyNode {@link org.eclipse.aether.graph.DependencyNode}
+     */
+    Maven31DependencyNodeAdapter( org.eclipse.aether.graph.DependencyNode dependencyNode )
+    {
+        this.dependencyNode = dependencyNode;
+    }
+
+    @Override
+    public Artifact getArtifact()
+    {
+        return getArtifact( dependencyNode.getArtifact() );
+    }
+
+    @Override
+    public List<DependencyNode> getChildren()
+    {
+        List<org.eclipse.aether.graph.DependencyNode> aetherChildren = dependencyNode.getChildren();
+        List<DependencyNode> children = new ArrayList<>( aetherChildren.size() );
+        for ( org.eclipse.aether.graph.DependencyNode aetherChild : aetherChildren )
+        {
+            children.add( new Maven31DependencyNodeAdapter( aetherChild ) );
+        }
+        return children;
+    }
+
+    @Override
+    public List<ArtifactRepository> getRemoteRepositories()
+    {
+        List<RemoteRepository> aetherRepositories = dependencyNode.getRepositories();
+        List<ArtifactRepository> mavenRepositories = new ArrayList<ArtifactRepository>( aetherRepositories.size() );
+
+        for ( RemoteRepository aetherRepository : aetherRepositories )
+        {
+            mavenRepositories.add( new Maven31ArtifactRepositoryAdapter( aetherRepository ) );
+        }
+
+        return mavenRepositories;
+    }
+
+    @Override
+    public String getScope()
+    {
+        return dependencyNode.getDependency().getScope();
+    }
+
+    @Override
+    public Boolean getOptional()
+    {
+        return dependencyNode.getDependency().getOptional();
+    }
+
+    @Override
+    public boolean accept( DependencyVisitor visitor )
+    {
+        if ( visitor.visitEnter( this ) )
+        {
+            for ( org.eclipse.aether.graph.DependencyNode aetherNode : dependencyNode.getChildren() )
+            {
+                DependencyNode child = new Maven31DependencyNodeAdapter( aetherNode );
+                if ( !child.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+
+        return visitor.visitLeave( this );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return dependencyNode.hashCode();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+
+        Maven31DependencyNodeAdapter other = (Maven31DependencyNodeAdapter) obj;
+        if ( dependencyNode == null )
+        {
+            if ( other.dependencyNode != null )
+            {
+                return false;
+            }
+        }
+        else if ( !dependencyNode.equals( other.dependencyNode ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private Artifact getArtifact( org.eclipse.aether.artifact.Artifact aetherArtifact )
+    {
+        try
+        {
+            return (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
+                org.eclipse.aether.artifact.Artifact.class, aetherArtifact );
+        }
+        catch ( DependencyCollectionException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java b/src/main/java/org/apache/maven/shared/transfer/collection/internal/MavenDependencyCollector.java
similarity index 54%
copy from src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java
copy to src/main/java/org/apache/maven/shared/transfer/collection/internal/MavenDependencyCollector.java
index f7b8809..2181380 100644
--- a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java
+++ b/src/main/java/org/apache/maven/shared/transfer/collection/internal/MavenDependencyCollector.java
@@ -1,37 +1,43 @@
-package org.apache.maven.shared.transfer.dependencies.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.apache.maven.artifact.repository.ArtifactRepository;
-
-/**
- * 
- * @author Robert Scholte
- *
- */
-public interface CollectorResult
-{
-    /**
-     * @return {@link ArtifactRepository}
-     */
-    List<ArtifactRepository> getRemoteRepositories();
-}
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
+import org.apache.maven.shared.transfer.collection.CollectResult;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+
+/**
+ * @author Robert Scholte
+ */
+public interface MavenDependencyCollector
+{
+
+  CollectResult collectDependencies( Dependency root )
+      throws DependencyCollectionException;
+
+  CollectResult collectDependencies( DependableCoordinate root )
+      throws DependencyCollectionException;
+
+  CollectResult collectDependencies( Model root )
+      throws DependencyCollectionException;
+
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java
index f7b8809..d5a13b5 100644
--- a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java
+++ b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/CollectorResult.java
@@ -31,7 +31,7 @@ import org.apache.maven.artifact.repository.ArtifactRepository;
 public interface CollectorResult
 {
     /**
-     * @return {@link ArtifactRepository}
+     * @return List of {@link ArtifactRepository}
      */
     List<ArtifactRepository> getRemoteRepositories();
 }
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollector.java b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollector.java
index 9904731..3d50a66 100644
--- a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollector.java
+++ b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollector.java
@@ -56,11 +56,7 @@ class DefaultDependencyCollector implements DependencyCollector, Contextualizabl
 
         try
         {
-            String hint = isMaven31() ? "maven31" : "maven3";
-
-            DependencyCollector effectiveDependencyCollector = container.lookup( DependencyCollector.class, hint );
-
-            return effectiveDependencyCollector.collectDependencies( buildingRequest, root );
+            return getMavenDependencyCollector( buildingRequest ).collectDependencies( root );
         }
         catch ( ComponentLookupException e )
         {
@@ -92,11 +88,7 @@ class DefaultDependencyCollector implements DependencyCollector, Contextualizabl
 
         try
         {
-            String hint = isMaven31() ? "maven31" : "maven3";
-
-            DependencyCollector effectiveDependencyCollector = container.lookup( DependencyCollector.class, hint );
-
-            return effectiveDependencyCollector.collectDependencies( buildingRequest, root );
+            return getMavenDependencyCollector( buildingRequest ).collectDependencies( root );
         }
         catch ( ComponentLookupException e )
         {
@@ -194,7 +186,6 @@ class DefaultDependencyCollector implements DependencyCollector, Contextualizabl
 
             return new Maven31DependencyCollector( m31RepositorySystem, artifactHandlerManager, session,
                                                    aetherRepositories );
-            
         }
         else
         {
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java
index 4b4eaf2..057e0bd 100644
--- a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java
+++ b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyCollector.java
@@ -26,7 +26,6 @@ import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.handler.ArtifactHandler;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.model.Model;
-
 import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
 import org.apache.maven.shared.transfer.dependencies.collect.CollectorResult;
 import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollector;
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyNodeAdapter.java b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyNodeAdapter.java
new file mode 100644
index 0000000..339c3ea
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven30DependencyNodeAdapter.java
@@ -0,0 +1,163 @@
+package org.apache.maven.shared.transfer.dependencies.collect.internal;
+
+/*
+ * 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.List;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollectorException;
+import org.apache.maven.shared.transfer.graph.DependencyNode;
+import org.apache.maven.shared.transfer.graph.DependencyVisitor;
+import org.sonatype.aether.repository.RemoteRepository;
+
+/**
+ * DependencyCollectorNode wrapper around {@link org.sonatype.aether.graph.DependencyNode}
+ * 
+ * @author Pim Moerenhout
+ *
+ */
+class Maven30DependencyNodeAdapter implements DependencyNode
+{
+
+    private org.sonatype.aether.graph.DependencyNode dependencyNode;
+
+    /**
+     * @param dependencyNode {@link org.sonatype.aether.graph.DependencyNode}
+     */
+    Maven30DependencyNodeAdapter( org.sonatype.aether.graph.DependencyNode dependencyNode )
+    {
+        this.dependencyNode = dependencyNode;
+    }
+
+    @Override
+    public Artifact getArtifact()
+    {
+        return getArtifact( dependencyNode.getDependency().getArtifact() );
+    }
+
+    @Override
+    public List<DependencyNode> getChildren()
+    {
+        List<org.sonatype.aether.graph.DependencyNode> aetherChildren = dependencyNode.getChildren();
+        List<DependencyNode> children = new ArrayList<>( aetherChildren.size() );
+        for ( org.sonatype.aether.graph.DependencyNode aetherChild : aetherChildren )
+        {
+            children.add( new Maven30DependencyNodeAdapter( aetherChild ) );
+        }
+        return children;
+    }
+
+    @Override
+    public List<ArtifactRepository> getRemoteRepositories()
+    {
+        List<RemoteRepository> aetherRepositories = dependencyNode.getRepositories();
+        List<ArtifactRepository> mavenRepositories = new ArrayList<ArtifactRepository>( aetherRepositories.size() );
+
+        for ( RemoteRepository aetherRepository : aetherRepositories )
+        {
+            mavenRepositories.add( new Maven30ArtifactRepositoryAdapter( aetherRepository ) );
+        }
+
+        return mavenRepositories;
+    }
+
+    @Override
+    public Boolean getOptional()
+    {
+        return dependencyNode.getDependency().isOptional();
+    }
+
+    @Override
+    public String getScope()
+    {
+        return dependencyNode.getDependency().getScope();
+    }
+
+    @Override
+    public boolean accept( DependencyVisitor visitor )
+    {
+        if ( visitor.visitEnter( this ) )
+        {
+            for ( org.sonatype.aether.graph.DependencyNode child : dependencyNode.getChildren() )
+            {
+                DependencyNode node = new Maven30DependencyNodeAdapter( child );
+                if ( !node.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+
+        return visitor.visitLeave( this );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return dependencyNode.hashCode();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+
+        Maven30DependencyNodeAdapter other = (Maven30DependencyNodeAdapter) obj;
+        if ( dependencyNode == null )
+        {
+            if ( other.dependencyNode != null )
+            {
+                return false;
+            }
+        }
+        else if ( !dependencyNode.equals( other.dependencyNode ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private Artifact getArtifact( org.sonatype.aether.artifact.Artifact aetherArtifact )
+    {
+        try
+        {
+            return (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
+                org.sonatype.aether.artifact.Artifact.class, aetherArtifact );
+        }
+        catch ( DependencyCollectorException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven31DependencyNodeAdapter.java b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven31DependencyNodeAdapter.java
new file mode 100644
index 0000000..0a5ec8e
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/dependencies/collect/internal/Maven31DependencyNodeAdapter.java
@@ -0,0 +1,163 @@
+package org.apache.maven.shared.transfer.dependencies.collect.internal;
+
+/*
+ * 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.List;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollectorException;
+import org.apache.maven.shared.transfer.graph.DependencyNode;
+import org.apache.maven.shared.transfer.graph.DependencyVisitor;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * DependencyCollectorNode wrapper around {@link org.eclipse.aether.graph.DependencyNode}
+ *
+ * @author Pim Moerenhout
+ *
+ */
+class Maven31DependencyNodeAdapter implements DependencyNode
+{
+
+    private org.eclipse.aether.graph.DependencyNode dependencyNode;
+
+    /**
+     * @param dependencyNode {@link org.eclipse.aether.graph.DependencyNode}
+     */
+    Maven31DependencyNodeAdapter( org.eclipse.aether.graph.DependencyNode dependencyNode )
+    {
+        this.dependencyNode = dependencyNode;
+    }
+
+    @Override
+    public Artifact getArtifact()
+    {
+        return getArtifact( dependencyNode.getArtifact() );
+    }
+
+    @Override
+    public List<DependencyNode> getChildren()
+    {
+        List<org.eclipse.aether.graph.DependencyNode> aetherChildren = dependencyNode.getChildren();
+        List<DependencyNode> children = new ArrayList<>( aetherChildren.size() );
+        for ( org.eclipse.aether.graph.DependencyNode aetherChild : aetherChildren )
+        {
+            children.add( new Maven31DependencyNodeAdapter( aetherChild ) );
+        }
+        return children;
+    }
+
+    @Override
+    public List<ArtifactRepository> getRemoteRepositories()
+    {
+        List<RemoteRepository> aetherRepositories = dependencyNode.getRepositories();
+        List<ArtifactRepository> mavenRepositories = new ArrayList<ArtifactRepository>( aetherRepositories.size() );
+
+        for ( RemoteRepository aetherRepository : aetherRepositories )
+        {
+            mavenRepositories.add( new Maven31ArtifactRepositoryAdapter( aetherRepository ) );
+        }
+
+        return mavenRepositories;
+    }
+
+    @Override
+    public String getScope()
+    {
+        return dependencyNode.getDependency().getScope();
+    }
+
+    @Override
+    public Boolean getOptional()
+    {
+        return dependencyNode.getDependency().getOptional();
+    }
+
+    @Override
+    public boolean accept( DependencyVisitor visitor )
+    {
+        if ( visitor.visitEnter( this ) )
+        {
+            for ( org.eclipse.aether.graph.DependencyNode child : dependencyNode.getChildren() )
+            {
+                DependencyNode node = new Maven31DependencyNodeAdapter( child );
+                if ( !node.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+
+        return visitor.visitLeave( this );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return dependencyNode.hashCode();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+
+        Maven31DependencyNodeAdapter other = (Maven31DependencyNodeAdapter) obj;
+        if ( dependencyNode == null )
+        {
+            if ( other.dependencyNode != null )
+            {
+                return false;
+            }
+        }
+        else if ( !dependencyNode.equals( other.dependencyNode ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private Artifact getArtifact( org.eclipse.aether.artifact.Artifact aetherArtifact )
+    {
+        try
+        {
+            return (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
+                org.eclipse.aether.artifact.Artifact.class, aetherArtifact );
+        }
+        catch ( DependencyCollectorException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/graph/DependencyNode.java b/src/main/java/org/apache/maven/shared/transfer/graph/DependencyNode.java
new file mode 100644
index 0000000..aeec86c
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/graph/DependencyNode.java
@@ -0,0 +1,69 @@
+package org.apache.maven.shared.transfer.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.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+
+/**
+ * Represents an dependency node within a Maven project's dependency collector.
+ *
+ * @author Pim Moerenhout
+ * @since 0.12
+ */
+public interface DependencyNode
+{
+    /**
+     * Gets the child nodes of this node.
+     *
+     * @return The child nodes of this node, never {@code null}.
+     */
+    List<DependencyNode> getChildren();
+
+    /**
+     * @return Artifact for this DependencyCollectorNode.
+     */
+    Artifact getArtifact();
+
+    /**
+     * @return Repositories of this DependencyCollectorNode.
+     */
+    List<ArtifactRepository> getRemoteRepositories();
+
+    /**
+     * @return true for an optional dependency.
+     */
+    Boolean getOptional();
+
+    /**
+     * @return The scope on the dependency.
+     */
+    String getScope();
+
+    /**
+     * Traverses this node and potentially its children using the specified visitor.
+     *
+     * @param visitor The visitor to call back, must not be {@code null}.
+     * @return {@code true} to visit siblings nodes of this node as well, {@code false} to skip siblings.
+     */
+    boolean accept( DependencyVisitor visitor );
+}
diff --git a/src/main/java/org/apache/maven/shared/transfer/graph/DependencyVisitor.java b/src/main/java/org/apache/maven/shared/transfer/graph/DependencyVisitor.java
new file mode 100644
index 0000000..9e499c4
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/transfer/graph/DependencyVisitor.java
@@ -0,0 +1,48 @@
+package org.apache.maven.shared.transfer.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.
+ */
+
+
+/**
+ * Defines a hierarchical visitor for collecting dependency node trees.
+ * 
+ * @author Pim Moerenhout
+ * @since 0.12
+ */
+public interface DependencyVisitor
+{
+    /**
+     * Starts the visit to the specified dependency node.
+     * 
+     * @param node the dependency node to visit
+     * @return <code>true</code> to visit the specified dependency node's children, <code>false</code> to skip the
+     *         specified dependency node's children and proceed to its next sibling
+     */
+    boolean visitEnter( DependencyNode node );
+
+    /**
+     * Ends the visit to to the specified dependency node.
+     *
+     * @param node the dependency node to visit
+     * @return <code>true</code> to visit the specified dependency node's next sibling, <code>false</code> to skip the
+     *         specified dependency node's next siblings and proceed to its parent
+     */
+    boolean visitLeave( DependencyNode node );
+}
diff --git a/src/test/java/org/apache/maven/shared/transfer/collection/internal/DefaultDependencyCollectorTest.java b/src/test/java/org/apache/maven/shared/transfer/collection/internal/DefaultDependencyCollectorTest.java
new file mode 100644
index 0000000..2dbb554
--- /dev/null
+++ b/src/test/java/org/apache/maven/shared/transfer/collection/internal/DefaultDependencyCollectorTest.java
@@ -0,0 +1,101 @@
+package org.apache.maven.shared.transfer.collection.internal;
+
+/*
+ * 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 static org.mockito.Mockito.mock;
+
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+import org.apache.maven.shared.transfer.collection.DependencyCollector;
+import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class DefaultDependencyCollectorTest {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  private DependencyCollector dc;
+
+  @Before
+  public void setUp() {
+    dc = new org.apache.maven.shared.transfer.collection.internal.DefaultDependencyCollector();
+  }
+
+  @Test
+  public void collectDependenciesWithDependencyShouldFailWithNPEWhenParameterBuildingRequestIsNull()
+      throws DependencyCollectionException {
+    thrown.expect( NullPointerException.class );
+    thrown.expectMessage( "The parameter buildingRequest is not allowed to be null." );
+
+    dc.collectDependencies(null, (org.apache.maven.model.Dependency) null);
+  }
+
+  @Test
+  public void collectDependenciesWithDependencyShouldFailWithNPEWhenParameterRootIsNull()
+      throws DependencyCollectionException {
+    thrown.expect( NullPointerException.class );
+    thrown.expectMessage("The parameter root is not allowed to be null.");
+
+    ProjectBuildingRequest request = mock( ProjectBuildingRequest.class );
+    dc.collectDependencies(request, (org.apache.maven.model.Dependency) null);
+  }
+
+  @Test
+  public void collectDependenciesWithDependableCoordinateShouldFailWithNPEWhenParameterBuildingRequestIsNull()
+      throws DependencyCollectionException {
+    thrown.expect(NullPointerException.class);
+    thrown.expectMessage("The parameter buildingRequest is not allowed to be null.");
+
+    dc.collectDependencies(null, (DependableCoordinate) null);
+  }
+
+  @Test
+  public void collectDependenciesWithDependableCoordinateShouldFailWithNPEWhenParameterRootIsNull()
+      throws DependencyCollectionException {
+    thrown.expect( NullPointerException.class );
+    thrown.expectMessage( "The parameter root is not allowed to be null." );
+
+    ProjectBuildingRequest request = mock( ProjectBuildingRequest.class );
+    dc.collectDependencies(request, (DependableCoordinate) null);
+  }
+
+  @Test
+  public void collectDependenciesWithModelShouldFailWithNPEWhenParameterBuildingRequestIsNull()
+      throws DependencyCollectionException {
+    thrown.expect( NullPointerException.class );
+    thrown.expectMessage( "The parameter buildingRequest is not allowed to be null." );
+
+    dc.collectDependencies(null, (org.apache.maven.model.Model) null);
+  }
+
+  @Test
+  public void collectDependenciesWithModelShouldFailWithNPEWhenParameterRootIsNull()
+      throws DependencyCollectionException {
+    thrown.expect( NullPointerException.class );
+    thrown.expectMessage( "The parameter root is not allowed to be null." );
+
+    ProjectBuildingRequest request = mock( ProjectBuildingRequest.class );
+    dc.collectDependencies(request, (org.apache.maven.model.Model) null);
+  }
+}
diff --git a/src/test/java/org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollectorTest.java b/src/test/java/org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollectorTest.java
index 4d2f05e..a54af31 100644
--- a/src/test/java/org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollectorTest.java
+++ b/src/test/java/org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollectorTest.java
@@ -29,7 +29,6 @@ import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverExcepti
 import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
 import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollector;
 import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollectorException;
-import org.apache.maven.shared.transfer.dependencies.collect.internal.DefaultDependencyCollector;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;