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.eclipse.aether.graph;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.eclipse.aether.artifact.Artifact;
29  import org.eclipse.aether.repository.RemoteRepository;
30  import org.eclipse.aether.version.Version;
31  import org.eclipse.aether.version.VersionConstraint;
32  
33  import static java.util.Objects.requireNonNull;
34  
35  /**
36   * A node within a dependency graph.
37   */
38  public final class DefaultDependencyNode implements DependencyNode {
39  
40      private List<DependencyNode> children;
41  
42      private Dependency dependency;
43  
44      private Artifact artifact;
45  
46      private List<? extends Artifact> relocations;
47  
48      private Collection<? extends Artifact> aliases;
49  
50      private VersionConstraint versionConstraint;
51  
52      private Version version;
53  
54      private byte managedBits;
55  
56      private List<RemoteRepository> repositories;
57  
58      private String context;
59  
60      private Map<Object, Object> data;
61  
62      /**
63       * Creates a new node with the specified dependency.
64       *
65       * @param dependency The dependency associated with this node, may be {@code null} for a root node.
66       */
67      public DefaultDependencyNode(Dependency dependency) {
68          this.dependency = dependency;
69          artifact = (dependency != null) ? dependency.getArtifact() : null;
70          children = new ArrayList<>(0);
71          aliases = Collections.emptyList();
72          relocations = Collections.emptyList();
73          repositories = Collections.emptyList();
74          context = "";
75          data = Collections.emptyMap();
76      }
77  
78      /**
79       * Creates a new root node with the specified artifact as its label. Note that the new node has no dependency, i.e.
80       * {@link #getDependency()} will return {@code null}. Put differently, the specified artifact will not be subject to
81       * dependency collection/resolution.
82       *
83       * @param artifact The artifact to use as label for this node, may be {@code null}.
84       */
85      public DefaultDependencyNode(Artifact artifact) {
86          this.artifact = artifact;
87          children = new ArrayList<>(0);
88          aliases = Collections.emptyList();
89          relocations = Collections.emptyList();
90          repositories = Collections.emptyList();
91          context = "";
92          data = Collections.emptyMap();
93      }
94  
95      /**
96       * Creates a mostly shallow clone of the specified node. The new node has its own copy of any custom data and
97       * initially no children.
98       *
99       * @param node The node to copy, must not be {@code null}.
100      */
101     public DefaultDependencyNode(DependencyNode node) {
102         dependency = node.getDependency();
103         artifact = node.getArtifact();
104         children = new ArrayList<>(0);
105         setAliases(node.getAliases());
106         setRequestContext(node.getRequestContext());
107         setManagedBits(node.getManagedBits());
108         setRelocations(node.getRelocations());
109         setRepositories(node.getRepositories());
110         setVersion(node.getVersion());
111         setVersionConstraint(node.getVersionConstraint());
112         Map<?, ?> data = node.getData();
113         setData(data.isEmpty() ? null : new HashMap<>(data));
114     }
115 
116     public List<DependencyNode> getChildren() {
117         return children;
118     }
119 
120     public void setChildren(List<DependencyNode> children) {
121         if (children == null) {
122             this.children = new ArrayList<>(0);
123         } else {
124             this.children = children;
125         }
126     }
127 
128     public Dependency getDependency() {
129         return dependency;
130     }
131 
132     public Artifact getArtifact() {
133         return artifact;
134     }
135 
136     public void setArtifact(Artifact artifact) {
137         if (dependency == null) {
138             throw new IllegalStateException("node does not have a dependency");
139         }
140         dependency = dependency.setArtifact(artifact);
141         this.artifact = dependency.getArtifact();
142     }
143 
144     public List<? extends Artifact> getRelocations() {
145         return relocations;
146     }
147 
148     /**
149      * Sets the sequence of relocations that was followed to resolve this dependency's artifact.
150      *
151      * @param relocations The sequence of relocations, may be {@code null}.
152      */
153     public void setRelocations(List<? extends Artifact> relocations) {
154         if (relocations == null || relocations.isEmpty()) {
155             this.relocations = Collections.emptyList();
156         } else {
157             this.relocations = relocations;
158         }
159     }
160 
161     public Collection<? extends Artifact> getAliases() {
162         return aliases;
163     }
164 
165     /**
166      * Sets the known aliases for this dependency's artifact.
167      *
168      * @param aliases The known aliases, may be {@code null}.
169      */
170     public void setAliases(Collection<? extends Artifact> aliases) {
171         if (aliases == null || aliases.isEmpty()) {
172             this.aliases = Collections.emptyList();
173         } else {
174             this.aliases = aliases;
175         }
176     }
177 
178     public VersionConstraint getVersionConstraint() {
179         return versionConstraint;
180     }
181 
182     /**
183      * Sets the version constraint that was parsed from the dependency's version declaration.
184      *
185      * @param versionConstraint The version constraint for this node, may be {@code null}.
186      */
187     public void setVersionConstraint(VersionConstraint versionConstraint) {
188         this.versionConstraint = versionConstraint;
189     }
190 
191     public Version getVersion() {
192         return version;
193     }
194 
195     /**
196      * Sets the version that was selected for the dependency's target artifact.
197      *
198      * @param version The parsed version, may be {@code null}.
199      */
200     public void setVersion(Version version) {
201         this.version = version;
202     }
203 
204     public void setScope(String scope) {
205         if (dependency == null) {
206             throw new IllegalStateException("node does not have a dependency");
207         }
208         dependency = dependency.setScope(scope);
209     }
210 
211     public void setOptional(Boolean optional) {
212         if (dependency == null) {
213             throw new IllegalStateException("node does not have a dependency");
214         }
215         dependency = dependency.setOptional(optional);
216     }
217 
218     public int getManagedBits() {
219         return managedBits;
220     }
221 
222     /**
223      * Sets a bit field indicating which attributes of this node were subject to dependency management.
224      *
225      * @param managedBits The bit field indicating the managed attributes or {@code 0} if dependency management wasn't
226      *            applied.
227      */
228     public void setManagedBits(int managedBits) {
229         this.managedBits = (byte) (managedBits & 0x1F);
230     }
231 
232     public List<RemoteRepository> getRepositories() {
233         return repositories;
234     }
235 
236     /**
237      * Sets the remote repositories from which this node's artifact shall be resolved.
238      *
239      * @param repositories The remote repositories to use for artifact resolution, may be {@code null}.
240      */
241     public void setRepositories(List<RemoteRepository> repositories) {
242         if (repositories == null || repositories.isEmpty()) {
243             this.repositories = Collections.emptyList();
244         } else {
245             this.repositories = repositories;
246         }
247     }
248 
249     public String getRequestContext() {
250         return context;
251     }
252 
253     public void setRequestContext(String context) {
254         this.context = (context != null) ? context : "";
255     }
256 
257     public Map<Object, Object> getData() {
258         return data;
259     }
260 
261     public void setData(Map<Object, Object> data) {
262         if (data == null) {
263             this.data = Collections.emptyMap();
264         } else {
265             this.data = data;
266         }
267     }
268 
269     public void setData(Object key, Object value) {
270         requireNonNull(key, "key cannot be null");
271 
272         if (value == null) {
273             if (!data.isEmpty()) {
274                 data.remove(key);
275 
276                 if (data.isEmpty()) {
277                     data = Collections.emptyMap();
278                 }
279             }
280         } else {
281             if (data.isEmpty()) {
282                 data = new HashMap<>(1, 2); // nodes can be numerous so let's be space conservative
283             }
284             data.put(key, value);
285         }
286     }
287 
288     public boolean accept(DependencyVisitor visitor) {
289         if (Thread.currentThread().isInterrupted()) {
290             throw new RuntimeException(new InterruptedException("Thread interrupted"));
291         }
292         if (visitor.visitEnter(this)) {
293             for (DependencyNode child : children) {
294                 if (!child.accept(visitor)) {
295                     break;
296                 }
297             }
298         }
299 
300         return visitor.visitLeave(this);
301     }
302 
303     @Override
304     public String toString() {
305         Dependency dep = getDependency();
306         if (dep == null) {
307             return String.valueOf(getArtifact());
308         }
309         return dep.toString();
310     }
311 }