View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.dependency.tree;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Stack;
24  import org.apache.maven.artifact.Artifact;
25  import org.apache.maven.model.Exclusion;
26  import org.apache.maven.shared.dependency.graph.DependencyNode;
27  import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
28  
29  /**
30   * A dependency node visitor that clones visited nodes into a new dependency tree. This can be used in conjunction with
31   * a dependency node filter to construct subtrees.
32   *
33   * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
34   */
35  public class BuildingDependencyNodeVisitor implements DependencyNodeVisitor {
36      // fields -----------------------------------------------------------------
37  
38      /**
39       * The dependency node visitor to apply on the resultant dependency tree, or <code>null</code> for none.
40       */
41      private final DependencyNodeVisitor visitor;
42  
43      /**
44       * The resultant tree parent nodes for the currently visited node.
45       */
46      private final Stack<DependencyNode> parentNodes;
47  
48      /**
49       * The root node of the resultant tree.
50       */
51      private DependencyNode rootNode;
52  
53      // constructors -----------------------------------------------------------
54  
55      /**
56       * Creates a dependency node visitor that clones visited nodes into a new dependency tree.
57       */
58      public BuildingDependencyNodeVisitor() {
59          this(null);
60      }
61  
62      /**
63       * Creates a dependency node visitor that clones visited nodes into a new dependency tree, and then applies the
64       * specified dependency node visitor on the resultant dependency tree.
65       *
66       * @param visitor the dependency node visitor to apply on the resultant dependency tree, or <code>null</code> for
67       *            none
68       */
69      public BuildingDependencyNodeVisitor(DependencyNodeVisitor visitor) {
70          this.visitor = visitor;
71  
72          parentNodes = new Stack<DependencyNode>();
73      }
74  
75      // DependencyNodeVisitor methods ------------------------------------------
76  
77      /**
78       * {@inheritDoc}
79       */
80      @Override
81      public boolean visit(DependencyNode node) {
82          // clone the node
83          WrapperNode newNode = new WrapperNode(
84                  parentNodes.isEmpty() ? null : parentNodes.peek(),
85                  node.getArtifact(),
86                  node.getPremanagedVersion(),
87                  node.getPremanagedScope(),
88                  node.getVersionConstraint(),
89                  node.getOptional(),
90                  node.getExclusions(),
91                  node.toNodeString());
92          newNode.setChildren(new ArrayList<DependencyNode>());
93  
94          if (parentNodes.empty()) {
95              rootNode = newNode;
96          } else {
97              DependencyNode parentNode = parentNodes.peek();
98              parentNode.getChildren().add(newNode);
99          }
100 
101         parentNodes.push(newNode);
102 
103         return true;
104     }
105 
106     /**
107      * {@inheritDoc}
108      */
109     @Override
110     public boolean endVisit(DependencyNode node) {
111         parentNodes.pop();
112 
113         // apply the visitor to the resultant tree on the last visit
114         if (parentNodes.empty() && visitor != null) {
115             rootNode.accept(visitor);
116         }
117 
118         return true;
119     }
120 
121     // public methods ---------------------------------------------------------
122 
123     /**
124      * Gets the dependency node visitor that this visitor applies on the resultant dependency tree.
125      *
126      * @return the dependency node visitor, or <code>null</code> for none
127      */
128     public DependencyNodeVisitor getDependencyNodeVisitor() {
129         return visitor;
130     }
131 
132     /**
133      * Gets the root node of the resultant dependency tree constructed by this visitor.
134      *
135      * @return the root node, or <code>null</code> if the source tree has not yet been visited
136      */
137     public DependencyNode getDependencyTree() {
138         return rootNode;
139     }
140 
141     private static class WrapperNode implements DependencyNode {
142 
143         private final Artifact artifact;
144 
145         private final DependencyNode parent;
146 
147         private final String premanagedVersion;
148 
149         private final String premanagedScope;
150 
151         private final String versionConstraint;
152 
153         private List<DependencyNode> children;
154 
155         private final Boolean optional;
156 
157         private final List<Exclusion> exclusions;
158 
159         private final String nodeString;
160 
161         private WrapperNode(
162                 DependencyNode parent,
163                 Artifact artifact,
164                 String premanagedVersion,
165                 String premanagedScope,
166                 String versionConstraint,
167                 Boolean optional,
168                 List<Exclusion> exclusions,
169                 String nodeString) {
170             this.artifact = artifact;
171             this.parent = parent;
172             this.premanagedVersion = premanagedVersion;
173             this.premanagedScope = premanagedScope;
174             this.versionConstraint = versionConstraint;
175             this.optional = optional;
176             this.exclusions = exclusions;
177             this.nodeString = nodeString;
178         }
179 
180         @Override
181         public Artifact getArtifact() {
182             return artifact;
183         }
184 
185         @Override
186         public List<DependencyNode> getChildren() {
187             return children;
188         }
189 
190         @Override
191         public boolean accept(DependencyNodeVisitor visitor) {
192             if (visitor.visit(this)) {
193                 for (DependencyNode child : getChildren()) {
194                     if (!child.accept(visitor)) {
195                         break;
196                     }
197                 }
198             }
199 
200             return visitor.endVisit(this);
201         }
202 
203         @Override
204         public DependencyNode getParent() {
205             return parent;
206         }
207 
208         @Override
209         public String getPremanagedVersion() {
210             return premanagedVersion;
211         }
212 
213         @Override
214         public String getPremanagedScope() {
215             return premanagedScope;
216         }
217 
218         @Override
219         public String getVersionConstraint() {
220             return versionConstraint;
221         }
222 
223         @Override
224         public String toNodeString() {
225             return nodeString;
226         }
227 
228         @Override
229         public Boolean getOptional() {
230             return optional;
231         }
232 
233         @Override
234         public List<Exclusion> getExclusions() {
235             return exclusions;
236         }
237 
238         public void setChildren(List<DependencyNode> children) {
239             this.children = children;
240         }
241     }
242 }