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