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:25 UTC

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

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;