API: Added methods 'getParent' and 'getDepth' to interface 'DependencyNode'.
     To more easily support bottom-up graph traversals in addition to top-down.
diff --git a/aether-api/src/main/java/org/eclipse/aether/graph/DefaultDependencyNode.java b/aether-api/src/main/java/org/eclipse/aether/graph/DefaultDependencyNode.java
index 66a60c6..a2ffd0c 100644
--- a/aether-api/src/main/java/org/eclipse/aether/graph/DefaultDependencyNode.java
+++ b/aether-api/src/main/java/org/eclipse/aether/graph/DefaultDependencyNode.java
@@ -8,9 +8,9 @@
  * 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
@@ -38,6 +38,8 @@
     implements DependencyNode
 {
 
+    private DependencyNode parent;
+
     private List<DependencyNode> children;
 
     private Dependency dependency;
@@ -61,30 +63,26 @@
     private Map<Object, Object> data;
 
     /**
-     * Creates a new node with the specified dependency.
-     * 
+     * Creates a new root node with the specified dependency.
+     *
      * @param dependency The dependency associated with this node, may be {@code null} for a root node.
      */
     public DefaultDependencyNode( Dependency dependency )
     {
-        this.dependency = dependency;
-        artifact = ( dependency != null ) ? dependency.getArtifact() : null;
-        children = new ArrayList<DependencyNode>( 0 );
-        aliases = relocations = Collections.emptyList();
-        repositories = Collections.emptyList();
-        context = "";
-        data = Collections.emptyMap();
+        this( null, dependency );
     }
 
     /**
      * Creates a new root node with the specified artifact as its label. Note that the new node has no dependency, i.e.
      * {@link #getDependency()} will return {@code null}. Put differently, the specified artifact will not be subject to
      * dependency collection/resolution.
-     * 
+     *
      * @param artifact The artifact to use as label for this node, may be {@code null}.
      */
     public DefaultDependencyNode( Artifact artifact )
     {
+        super();
+        this.parent = null;
         this.artifact = artifact;
         children = new ArrayList<DependencyNode>( 0 );
         aliases = relocations = Collections.emptyList();
@@ -96,11 +94,13 @@
     /**
      * Creates a mostly shallow clone of the specified node. The new node has its own copy of any custom data and
      * initially no children.
-     * 
+     *
      * @param node The node to copy, must not be {@code null}.
      */
     public DefaultDependencyNode( DependencyNode node )
     {
+        super();
+        parent = node.getParent();
         dependency = node.getDependency();
         artifact = node.getArtifact();
         children = new ArrayList<DependencyNode>( 0 );
@@ -115,6 +115,37 @@
         setData( data.isEmpty() ? null : new HashMap<Object, Object>( data ) );
     }
 
+    /**
+     * Creates a new node with the specified dependency.
+     *
+     * @param parent The parent node of the node or {@code null}.
+     * @param dependency The dependency associated with this node, may be {@code null} for a root node.
+     *
+     * @since 1.2
+     */
+    public DefaultDependencyNode( DependencyNode parent, Dependency dependency )
+    {
+        super();
+        this.parent = parent;
+        this.dependency = dependency;
+        artifact = ( dependency != null ) ? dependency.getArtifact() : null;
+        children = new ArrayList<DependencyNode>( 0 );
+        aliases = relocations = Collections.emptyList();
+        repositories = Collections.emptyList();
+        context = "";
+        data = Collections.emptyMap();
+    }
+
+    public long getDepth()
+    {
+        return this.getParent() != null ? this.getParent().getDepth() + 1L : 0L;
+    }
+
+    public DependencyNode getParent()
+    {
+        return this.parent;
+    }
+
     public List<DependencyNode> getChildren()
     {
         return children;
@@ -159,7 +190,7 @@
 
     /**
      * Sets the sequence of relocations that was followed to resolve this dependency's artifact.
-     * 
+     *
      * @param relocations The sequence of relocations, may be {@code null}.
      */
     public void setRelocations( List<? extends Artifact> relocations )
@@ -181,7 +212,7 @@
 
     /**
      * Sets the known aliases for this dependency's artifact.
-     * 
+     *
      * @param aliases The known aliases, may be {@code null}.
      */
     public void setAliases( Collection<? extends Artifact> aliases )
@@ -203,7 +234,7 @@
 
     /**
      * Sets the version constraint that was parsed from the dependency's version declaration.
-     * 
+     *
      * @param versionConstraint The version constraint for this node, may be {@code null}.
      */
     public void setVersionConstraint( VersionConstraint versionConstraint )
@@ -218,7 +249,7 @@
 
     /**
      * Sets the version that was selected for the dependency's target artifact.
-     * 
+     *
      * @param version The parsed version, may be {@code null}.
      */
     public void setVersion( Version version )
@@ -251,9 +282,9 @@
 
     /**
      * Sets a bit field indicating which attributes of this node were subject to dependency management.
-     * 
+     *
      * @param managedBits The bit field indicating the managed attributes or {@code 0} if dependency management wasn't
-     *            applied.
+     * applied.
      */
     public void setManagedBits( int managedBits )
     {
@@ -267,7 +298,7 @@
 
     /**
      * Sets the remote repositories from which this node's artifact shall be resolved.
-     * 
+     *
      * @param repositories The remote repositories to use for artifact resolution, may be {@code null}.
      */
     public void setRepositories( List<RemoteRepository> repositories )
diff --git a/aether-api/src/main/java/org/eclipse/aether/graph/DependencyNode.java b/aether-api/src/main/java/org/eclipse/aether/graph/DependencyNode.java
index 2551043..da30124 100644
--- a/aether-api/src/main/java/org/eclipse/aether/graph/DependencyNode.java
+++ b/aether-api/src/main/java/org/eclipse/aether/graph/DependencyNode.java
@@ -8,9 +8,9 @@
  * 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
@@ -34,7 +34,7 @@
  * discover multiple paths leading to the same node instance unless the input graph is known to be a duplicate-free
  * tree. <em>Note:</em> Unless otherwise noted, implementation classes are not thread-safe and dependency nodes should
  * not be mutated by concurrent threads.
- * 
+ *
  * @noimplement This interface is not intended to be implemented by clients.
  * @noextend This interface is not intended to be extended by clients.
  */
@@ -43,52 +43,70 @@
 
     /**
      * A bit flag indicating the dependency version was subject to dependency management
-     * 
+     *
      * @see #getManagedBits()
      */
     int MANAGED_VERSION = 0x01;
 
     /**
      * A bit flag indicating the dependency scope was subject to dependency management
-     * 
+     *
      * @see #getManagedBits()
      */
     int MANAGED_SCOPE = 0x02;
 
     /**
      * A bit flag indicating the optional flag was subject to dependency management
-     * 
+     *
      * @see #getManagedBits()
      */
     int MANAGED_OPTIONAL = 0x04;
 
     /**
      * A bit flag indicating the artifact properties were subject to dependency management
-     * 
+     *
      * @see #getManagedBits()
      */
     int MANAGED_PROPERTIES = 0x08;
 
     /**
      * A bit flag indicating the exclusions were subject to dependency management
-     * 
+     *
      * @see #getManagedBits()
      */
     int MANAGED_EXCLUSIONS = 0x10;
 
     /**
+     * Gets the depth of the node.
+     *
+     * @return The depth of the node.
+     *
+     * @since 1.2
+     */
+    long getDepth();
+
+    /**
+     * Gets the parent node of this node.
+     *
+     * @return The parent node of this node or {@code null}, if this node is the root of the graph.
+     *
+     * @since 1.2
+     */
+    DependencyNode getParent();
+
+    /**
      * Gets the child nodes of this node. To conserve memory, dependency nodes with equal dependencies may share the
      * same child list instance. Hence clients mutating the child list need to be aware that these changes might affect
      * more than this node. Where this is not desired, the child list should be copied before mutation if the client
      * cannot be sure whether it might be shared with other nodes in the graph.
-     * 
+     *
      * @return The child nodes of this node, never {@code null}.
      */
     List<DependencyNode> getChildren();
 
     /**
      * Sets the child nodes of this node.
-     * 
+     *
      * @param children The child nodes, may be {@code null}
      */
     void setChildren( List<DependencyNode> children );
@@ -97,7 +115,7 @@
      * Gets the dependency associated with this node. <em>Note:</em> For dependency graphs that have been constructed
      * without a root dependency, this method will yield {@code null} when invoked on the graph's root node. The root
      * node of such graphs may however still have a label as returned by {@link #getArtifact()}.
-     * 
+     *
      * @return The dependency or {@code null} if none.
      */
     Dependency getDependency();
@@ -106,7 +124,7 @@
      * Gets the artifact associated with this node. If this node is associated with a dependency, this is equivalent to
      * {@code getDependency().getArtifact()}. Otherwise the artifact merely provides a label for this node in which case
      * the artifact must not be subjected to dependency collection/resolution.
-     * 
+     *
      * @return The associated artifact or {@code null} if none.
      */
     Artifact getArtifact();
@@ -115,14 +133,14 @@
      * Updates the artifact of the dependency after resolution. The new artifact must have the same coordinates as the
      * original artifact. This method may only be invoked if this node actually has a dependency, i.e. if
      * {@link #getDependency()} is not null.
-     * 
+     *
      * @param artifact The artifact satisfying the dependency, must not be {@code null}.
      */
     void setArtifact( Artifact artifact );
 
     /**
      * Gets the sequence of relocations that was followed to resolve the artifact referenced by the dependency.
-     * 
+     *
      * @return The (read-only) sequence of relocations, never {@code null}.
      */
     List<? extends Artifact> getRelocations();
@@ -131,21 +149,21 @@
      * Gets the known aliases for this dependency's artifact. An alias can be used to mark a patched rebuild of some
      * other artifact as such, thereby allowing conflict resolution to consider the patched and the original artifact as
      * a conflict.
-     * 
+     *
      * @return The (read-only) set of known aliases, never {@code null}.
      */
     Collection<? extends Artifact> getAliases();
 
     /**
      * Gets the version constraint that was parsed from the dependency's version declaration.
-     * 
+     *
      * @return The version constraint for this node or {@code null}.
      */
     VersionConstraint getVersionConstraint();
 
     /**
      * Gets the version that was selected for the dependency's target artifact.
-     * 
+     *
      * @return The parsed version or {@code null}.
      */
     Version getVersion();
@@ -153,7 +171,7 @@
     /**
      * Sets the scope of the dependency. This method may only be invoked if this node actually has a dependency, i.e. if
      * {@link #getDependency()} is not null.
-     * 
+     *
      * @param scope The scope, may be {@code null}.
      */
     void setScope( String scope );
@@ -161,14 +179,14 @@
     /**
      * Sets the optional flag of the dependency. This method may only be invoked if this node actually has a dependency,
      * i.e. if {@link #getDependency()} is not null.
-     * 
+     *
      * @param optional The optional flag, may be {@code null}.
      */
     void setOptional( Boolean optional );
 
     /**
      * Gets a bit field indicating which attributes of this node were subject to dependency management.
-     * 
+     *
      * @return A bit field containing any of the bits {@link #MANAGED_VERSION}, {@link #MANAGED_SCOPE},
      *         {@link #MANAGED_OPTIONAL}, {@link #MANAGED_PROPERTIES} and {@link #MANAGED_EXCLUSIONS} if the
      *         corresponding attribute was set via dependency management.
@@ -177,21 +195,21 @@
 
     /**
      * Gets the remote repositories from which this node's artifact shall be resolved.
-     * 
+     *
      * @return The (read-only) list of remote repositories to use for artifact resolution, never {@code null}.
      */
     List<RemoteRepository> getRepositories();
 
     /**
      * Gets the request context in which this dependency node was created.
-     * 
+     *
      * @return The request context, never {@code null}.
      */
     String getRequestContext();
 
     /**
      * Sets the request context in which this dependency node was created.
-     * 
+     *
      * @param context The context, may be {@code null}.
      */
     void setRequestContext( String context );
@@ -200,14 +218,14 @@
      * Gets the custom data associated with this dependency node. Clients of the repository system can use this data to
      * annotate dependency nodes with domain-specific information. Note that the returned map is read-only and
      * {@link #setData(Object, Object)} needs to be used to update the custom data.
-     * 
+     *
      * @return The (read-only) key-value mappings, never {@code null}.
      */
     Map<?, ?> getData();
 
     /**
      * Sets the custom data associated with this dependency node.
-     * 
+     *
      * @param data The new custom data, may be {@code null}.
      */
     void setData( Map<Object, Object> data );
@@ -215,7 +233,7 @@
     /**
      * Associates the specified dependency node data with the given key. <em>Note:</em> This method must not be called
      * while {@link #getData()} is being iterated.
-     * 
+     *
      * @param key The key under which to store the data, must not be {@code null}.
      * @param value The data to associate with the key, may be {@code null} to remove the mapping.
      */
@@ -223,7 +241,7 @@
 
     /**
      * 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.
      */
diff --git a/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java b/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java
index 62a8ff2..4fb8374 100644
--- a/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java
+++ b/aether-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDependencyCollector.java
@@ -8,9 +8,9 @@
  * 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
@@ -431,8 +431,8 @@
                     if ( cycleNode.getDependency() != null )
                     {
                         DefaultDependencyNode child =
-                            createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult,
-                                                  cycleNode );
+                            createDependencyNode( node, relocations, preManaged, rangeResult, version, d,
+                                                  descriptorResult, cycleNode );
                         node.getChildren().add( child );
                         continue;
                     }
@@ -456,7 +456,7 @@
                         getRemoteRepositories( rangeResult.getRepository( version ), repositories );
 
                     DefaultDependencyNode child =
-                        createDependencyNode( relocations, preManaged, rangeResult, version, d,
+                        createDependencyNode( node, relocations, preManaged, rangeResult, version, d,
                                               descriptorResult.getAliases(), repos, args.request.getRequestContext() );
 
                     node.getChildren().add( child );
@@ -475,7 +475,7 @@
                 List<RemoteRepository> repos =
                     getRemoteRepositories( rangeResult.getRepository( version ), repositories );
                 DefaultDependencyNode child =
-                    createDependencyNode( relocations, preManaged, rangeResult, version, d, null, repos,
+                    createDependencyNode( node, relocations, preManaged, rangeResult, version, d, null, repos,
                                           args.request.getRequestContext() );
                 node.getChildren().add( child );
             }
@@ -560,13 +560,14 @@
         return descriptorResult;
     }
 
-    private static DefaultDependencyNode createDependencyNode( List<Artifact> relocations,
+    private static DefaultDependencyNode createDependencyNode( DependencyNode parent,
+                                                               List<Artifact> relocations,
                                                                PremanagedDependency preManaged,
                                                                VersionRangeResult rangeResult, Version version,
                                                                Dependency d, Collection<Artifact> aliases,
                                                                List<RemoteRepository> repos, String requestContext )
     {
-        DefaultDependencyNode child = new DefaultDependencyNode( d );
+        DefaultDependencyNode child = new DefaultDependencyNode( parent, d );
         preManaged.applyTo( child );
         child.setRelocations( relocations );
         child.setVersionConstraint( rangeResult.getVersionConstraint() );
@@ -577,15 +578,18 @@
         return child;
     }
 
-    private static DefaultDependencyNode createDependencyNode( List<Artifact> relocations,
+    private static DefaultDependencyNode createDependencyNode( DependencyNode parent,
+                                                               List<Artifact> relocations,
                                                                PremanagedDependency preManaged,
                                                                VersionRangeResult rangeResult, Version version,
                                                                Dependency d, ArtifactDescriptorResult descriptorResult,
                                                                DependencyNode cycleNode )
     {
         DefaultDependencyNode child =
-            createDependencyNode( relocations, preManaged, rangeResult, version, d, descriptorResult.getAliases(),
-                                  cycleNode.getRepositories(), cycleNode.getRequestContext() );
+            createDependencyNode( parent, relocations, preManaged, rangeResult, version, d,
+                                  descriptorResult.getAliases(), cycleNode.getRepositories(),
+                                  cycleNode.getRequestContext() );
+
         child.setChildren( cycleNode.getChildren() );
         return child;
     }
diff --git a/aether-test-util/src/main/java/org/eclipse/aether/internal/test/util/DependencyGraphParser.java b/aether-test-util/src/main/java/org/eclipse/aether/internal/test/util/DependencyGraphParser.java
index 7976487..e4deefb 100644
--- a/aether-test-util/src/main/java/org/eclipse/aether/internal/test/util/DependencyGraphParser.java
+++ b/aether-test-util/src/main/java/org/eclipse/aether/internal/test/util/DependencyGraphParser.java
@@ -8,9 +8,9 @@
  * 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
@@ -46,7 +46,7 @@
 /**
  * Creates a dependency graph from a text description. <h2>Definition</h2> Each (non-empty) line in the input defines
  * one node of the resulting graph:
- * 
+ *
  * <pre>
  * line      ::= (indent? ("(null)" | node | reference))? comment?
  * comment   ::= "#" rest-of-line
@@ -55,7 +55,7 @@
  * node      ::= coords (range)? space (scope("&lt;" premanagedScope)?)? space "optional"? space ("relocations=" coords ("," coords)*)? ("(" id ")")?
  * coords    ::= groupId ":" artifactId (":" extension (":" classifier)?)? ":" version
  * </pre>
- * 
+ *
  * The special token {@code (null)} may be used to indicate an "empty" root node with no dependency.
  * <p>
  * If {@code indent} is empty, the line defines the root node. Only one root node may be defined. The level is
@@ -64,7 +64,7 @@
  * The {@code ^id} syntax allows to reuse a previously built node to share common sub graphs among different parent
  * nodes.
  * <h2>Example</h2>
- * 
+ *
  * <pre>
  * gid:aid:ver
  * +- gid:aid2:ver scope
@@ -72,7 +72,7 @@
  * +- gid:aid4:ext:ver scope
  * \- ^id1                            # reuse previous node
  * </pre>
- * 
+ *
  * <h2>Multiple definitions in one resource</h2>
  * <p>
  * By using {@link #parseMultiResource(String)}, definitions divided by a line beginning with "---" can be read from the
@@ -83,12 +83,12 @@
  * {@link #DependencyGraphParser(String, Collection)}). Every '%s' in the definition will be substituted by the next
  * String in the defined substitutions.
  * <h3>Example</h3>
- * 
+ *
  * <pre>
  * parser.setSubstitutions( &quot;foo&quot;, &quot;bar&quot; );
  * String def = &quot;gid:%s:ext:ver\n&quot; + &quot;+- gid:%s:ext:ver&quot;;
  * </pre>
- * 
+ *
  * The first node will have "foo" as its artifact id, the second node (child to the first) will have "bar" as its
  * artifact id.
  */
@@ -103,7 +103,7 @@
 
     /**
      * Create a parser with the given prefix and the given substitution strings.
-     * 
+     *
      * @see DependencyGraphParser#parseResource(String)
      */
     public DependencyGraphParser( String prefix, Collection<String> substitutions )
@@ -115,7 +115,7 @@
 
     /**
      * Create a parser with the given prefix.
-     * 
+     *
      * @see DependencyGraphParser#parseResource(String)
      */
     public DependencyGraphParser( String prefix )
@@ -338,7 +338,7 @@
         {
             DefaultArtifact artifact = new DefaultArtifact( def.coords, def.properties );
             Dependency dependency = new Dependency( artifact, def.scope, def.optional );
-            node = new DefaultDependencyNode( dependency );
+            node = new DefaultDependencyNode( parent, dependency );
             int managedBits = 0;
             if ( def.premanagedScope != null )
             {