View Javadoc
1   package org.eclipse.aether.util.graph.visitor;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.eclipse.aether.artifact.Artifact;
23  import org.eclipse.aether.graph.Dependency;
24  import org.eclipse.aether.graph.DependencyNode;
25  import org.eclipse.aether.graph.DependencyVisitor;
26  
27  import java.io.File;
28  import java.util.ArrayList;
29  import java.util.IdentityHashMap;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Map;
33  
34  /**
35   * Abstract base class for depth first dependency tree traversers. Subclasses of this visitor will visit each node
36   * exactly once regardless how many paths within the dependency graph lead to the node such that the resulting node
37   * sequence is free of duplicates.
38   * <p>
39   * Actual vertex ordering (preorder, inorder, postorder) needs to be defined by subclasses through appropriate
40   * implementations for {@link #visitEnter(org.eclipse.aether.graph.DependencyNode)} and
41   * {@link #visitLeave(org.eclipse.aether.graph.DependencyNode)}
42   */
43  abstract class AbstractDepthFirstNodeListGenerator
44      implements DependencyVisitor
45  {
46  
47      private final Map<DependencyNode, Object> visitedNodes;
48  
49      protected final List<DependencyNode> nodes;
50  
51      AbstractDepthFirstNodeListGenerator()
52      {
53          nodes = new ArrayList<>( 128 );
54          visitedNodes = new IdentityHashMap<>( 512 );
55      }
56  
57      /**
58       * Gets the list of dependency nodes that was generated during the graph traversal.
59       * 
60       * @return The list of dependency nodes, never {@code null}.
61       */
62      public List<DependencyNode> getNodes()
63      {
64          return nodes;
65      }
66  
67      /**
68       * Gets the dependencies seen during the graph traversal.
69       * 
70       * @param includeUnresolved Whether unresolved dependencies shall be included in the result or not.
71       * @return The list of dependencies, never {@code null}.
72       */
73      public List<Dependency> getDependencies( boolean includeUnresolved )
74      {
75          List<Dependency> dependencies = new ArrayList<>( getNodes().size() );
76  
77          for ( DependencyNode node : getNodes() )
78          {
79              Dependency dependency = node.getDependency();
80              if ( dependency != null )
81              {
82                  if ( includeUnresolved || dependency.getArtifact().getFile() != null )
83                  {
84                      dependencies.add( dependency );
85                  }
86              }
87          }
88  
89          return dependencies;
90      }
91  
92      /**
93       * Gets the artifacts associated with the list of dependency nodes generated during the graph traversal.
94       * 
95       * @param includeUnresolved Whether unresolved artifacts shall be included in the result or not.
96       * @return The list of artifacts, never {@code null}.
97       */
98      public List<Artifact> getArtifacts( boolean includeUnresolved )
99      {
100         List<Artifact> artifacts = new ArrayList<>( getNodes().size() );
101 
102         for ( DependencyNode node : getNodes() )
103         {
104             if ( node.getDependency() != null )
105             {
106                 Artifact artifact = node.getDependency().getArtifact();
107                 if ( includeUnresolved || artifact.getFile() != null )
108                 {
109                     artifacts.add( artifact );
110                 }
111             }
112         }
113 
114         return artifacts;
115     }
116 
117     /**
118      * Gets the files of resolved artifacts seen during the graph traversal.
119      * 
120      * @return The list of artifact files, never {@code null}.
121      */
122     public List<File> getFiles()
123     {
124         List<File> files = new ArrayList<>( getNodes().size() );
125 
126         for ( DependencyNode node : getNodes() )
127         {
128             if ( node.getDependency() != null )
129             {
130                 File file = node.getDependency().getArtifact().getFile();
131                 if ( file != null )
132                 {
133                     files.add( file );
134                 }
135             }
136         }
137 
138         return files;
139     }
140 
141     /**
142      * Gets a class path by concatenating the artifact files of the visited dependency nodes. Nodes with unresolved
143      * artifacts are automatically skipped.
144      * 
145      * @return The class path, using the platform-specific path separator, never {@code null}.
146      */
147     public String getClassPath()
148     {
149         StringBuilder buffer = new StringBuilder( 1024 );
150 
151         for ( Iterator<DependencyNode> it = getNodes().iterator(); it.hasNext(); )
152         {
153             DependencyNode node = it.next();
154             if ( node.getDependency() != null )
155             {
156                 Artifact artifact = node.getDependency().getArtifact();
157                 if ( artifact.getFile() != null )
158                 {
159                     buffer.append( artifact.getFile().getAbsolutePath() );
160                     if ( it.hasNext() )
161                     {
162                         buffer.append( File.pathSeparatorChar );
163                     }
164                 }
165             }
166         }
167 
168         return buffer.toString();
169     }
170 
171     /**
172      * Marks the specified node as being visited and determines whether the node has been visited before.
173      * 
174      * @param node The node being visited, must not be {@code null}.
175      * @return {@code true} if the node has not been visited before, {@code false} if the node was already visited.
176      */
177     protected boolean setVisited( DependencyNode node )
178     {
179         return visitedNodes.put( node, Boolean.TRUE ) == null;
180     }
181 
182     public abstract boolean visitEnter( DependencyNode node );
183 
184     public abstract boolean visitLeave( DependencyNode node );
185 
186 }