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.artifact.resolver;
20  
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.Iterator;
24  import java.util.LinkedList;
25  import java.util.List;
26  import java.util.Set;
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.artifact.repository.ArtifactRepository;
29  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
30  import org.apache.maven.artifact.versioning.ArtifactVersion;
31  import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
32  
33  /**
34   * ResolutionNode
35   */
36  public class ResolutionNode {
37      private Artifact artifact;
38  
39      private List<ResolutionNode> children;
40  
41      private final List<Object> parents;
42  
43      private final int depth;
44  
45      private final ResolutionNode parent;
46  
47      private final List<ArtifactRepository> remoteRepositories;
48  
49      private boolean active = true;
50  
51      private List<Artifact> trail;
52  
53      public ResolutionNode(Artifact artifact, List<ArtifactRepository> remoteRepositories) {
54          this.artifact = artifact;
55          this.remoteRepositories = remoteRepositories;
56          depth = 0;
57          parents = Collections.emptyList();
58          parent = null;
59      }
60  
61      public ResolutionNode(Artifact artifact, List<ArtifactRepository> remoteRepositories, ResolutionNode parent) {
62          this.artifact = artifact;
63          this.remoteRepositories = remoteRepositories;
64          depth = parent.depth + 1;
65          parents = new ArrayList<>();
66          parents.addAll(parent.parents);
67          parents.add(parent.getKey());
68          this.parent = parent;
69      }
70  
71      public Artifact getArtifact() {
72          return artifact;
73      }
74  
75      public Object getKey() {
76          return artifact.getDependencyConflictId();
77      }
78  
79      public void addDependencies(
80              Set<Artifact> artifacts, List<ArtifactRepository> remoteRepositories, ArtifactFilter filter)
81              throws CyclicDependencyException, OverConstrainedVersionException {
82          if (artifacts != null && !artifacts.isEmpty()) {
83              children = new ArrayList<>(artifacts.size());
84  
85              for (Artifact a : artifacts) {
86                  if (parents.contains(a.getDependencyConflictId())) {
87                      a.setDependencyTrail(getDependencyTrail());
88  
89                      throw new CyclicDependencyException("A dependency has introduced a cycle", a);
90                  }
91  
92                  children.add(new ResolutionNode(a, remoteRepositories, this));
93              }
94              children = Collections.unmodifiableList(children);
95          } else {
96              children = Collections.emptyList();
97          }
98          trail = null;
99      }
100 
101     /**
102      * @return {@link List} &lt; {@link String} &gt; with artifact ids
103      * @throws OverConstrainedVersionException if version specification is over constrained
104      */
105     public List<String> getDependencyTrail() throws OverConstrainedVersionException {
106         List<Artifact> trial = getTrail();
107 
108         List<String> ret = new ArrayList<>(trial.size());
109 
110         for (Artifact artifact : trial) {
111             ret.add(artifact.getId());
112         }
113 
114         return ret;
115     }
116 
117     private List<Artifact> getTrail() throws OverConstrainedVersionException {
118         if (trail == null) {
119             List<Artifact> ids = new LinkedList<>();
120             ResolutionNode node = this;
121             while (node != null) {
122                 Artifact artifact = node.getArtifact();
123                 if (artifact.getVersion() == null) {
124                     // set the recommended version
125                     ArtifactVersion selected = artifact.getSelectedVersion();
126                     // MNG-2123: null is a valid response to getSelectedVersion, don't
127                     // assume it won't ever be.
128                     if (selected != null) {
129                         artifact.selectVersion(selected.toString());
130                     } else {
131                         throw new OverConstrainedVersionException(
132                                 "Unable to get a selected Version for " + artifact.getArtifactId(), artifact);
133                     }
134                 }
135 
136                 ids.add(0, artifact);
137                 node = node.parent;
138             }
139             trail = ids;
140         }
141         return trail;
142     }
143 
144     public boolean isResolved() {
145         return children != null;
146     }
147 
148     /**
149      * Test whether the node is direct or transitive dependency.
150      *
151      * @return whether the node is direct or transitive dependency
152      */
153     public boolean isChildOfRootNode() {
154         return parent != null && parent.parent == null;
155     }
156 
157     public Iterator<ResolutionNode> getChildrenIterator() {
158         return children.iterator();
159     }
160 
161     public int getDepth() {
162         return depth;
163     }
164 
165     public List<ArtifactRepository> getRemoteRepositories() {
166         return remoteRepositories;
167     }
168 
169     public boolean isActive() {
170         return active;
171     }
172 
173     public void enable() {
174         active = true;
175 
176         // TODO if it was null, we really need to go find them now... or is this taken care of by the ordering?
177         if (children != null) {
178             for (ResolutionNode node : children) {
179                 node.enable();
180             }
181         }
182     }
183 
184     public void disable() {
185         active = false;
186         if (children != null) {
187             for (ResolutionNode node : children) {
188                 node.disable();
189             }
190         }
191     }
192 
193     public boolean filterTrail(ArtifactFilter filter) throws OverConstrainedVersionException {
194         boolean success = true;
195         if (filter != null) {
196             for (Artifact artifact : getTrail()) {
197                 if (!filter.include(artifact)) {
198                     success = false;
199                 }
200             }
201         }
202         return success;
203     }
204 
205     @Override
206     public String toString() {
207         return artifact.toString() + " (" + depth + "; " + (active ? "enabled" : "disabled") + ")";
208     }
209 
210     public void setArtifact(Artifact artifact) {
211         this.artifact = artifact;
212     }
213 }