]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.repo/src/org/eclipse/aether/graph/Dependency.java
Merge remote-tracking branch 'origin/master' into testing
[gpl/argeo-slc.git] / org.argeo.slc.repo / src / org / eclipse / aether / graph / Dependency.java
1 /*******************************************************************************
2 * Copyright (c) 2010, 2013 Sonatype, Inc.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Sonatype, Inc. - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.aether.graph;
12
13 import java.util.AbstractSet;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.Iterator;
17 import java.util.LinkedHashSet;
18 import java.util.NoSuchElementException;
19 import java.util.Set;
20
21 import org.eclipse.aether.artifact.Artifact;
22
23 /**
24 * A dependency to some artifact. <em>Note:</em> Instances of this class are immutable and the exposed mutators return
25 * new objects rather than changing the current instance.
26 */
27 public final class Dependency
28 {
29
30 private final Artifact artifact;
31
32 private final String scope;
33
34 private final Boolean optional;
35
36 private final Set<Exclusion> exclusions;
37
38 /**
39 * Creates a mandatory dependency on the specified artifact with the given scope.
40 *
41 * @param artifact The artifact being depended on, must not be {@code null}.
42 * @param scope The scope of the dependency, may be {@code null}.
43 */
44 public Dependency( Artifact artifact, String scope )
45 {
46 this( artifact, scope, false );
47 }
48
49 /**
50 * Creates a dependency on the specified artifact with the given scope.
51 *
52 * @param artifact The artifact being depended on, must not be {@code null}.
53 * @param scope The scope of the dependency, may be {@code null}.
54 * @param optional A flag whether the dependency is optional or mandatory, may be {@code null}.
55 */
56 public Dependency( Artifact artifact, String scope, Boolean optional )
57 {
58 this( artifact, scope, optional, null );
59 }
60
61 /**
62 * Creates a dependency on the specified artifact with the given scope and exclusions.
63 *
64 * @param artifact The artifact being depended on, must not be {@code null}.
65 * @param scope The scope of the dependency, may be {@code null}.
66 * @param optional A flag whether the dependency is optional or mandatory, may be {@code null}.
67 * @param exclusions The exclusions that apply to transitive dependencies, may be {@code null} if none.
68 */
69 public Dependency( Artifact artifact, String scope, Boolean optional, Collection<Exclusion> exclusions )
70 {
71 this( artifact, scope, Exclusions.copy( exclusions ), optional );
72 }
73
74 private Dependency( Artifact artifact, String scope, Set<Exclusion> exclusions, Boolean optional )
75 {
76 // NOTE: This constructor assumes immutability of the provided exclusion collection, for internal use only
77 if ( artifact == null )
78 {
79 throw new IllegalArgumentException( "no artifact specified for dependency" );
80 }
81 this.artifact = artifact;
82 this.scope = ( scope != null ) ? scope : "";
83 this.optional = optional;
84 this.exclusions = exclusions;
85 }
86
87 /**
88 * Gets the artifact being depended on.
89 *
90 * @return The artifact, never {@code null}.
91 */
92 public Artifact getArtifact()
93 {
94 return artifact;
95 }
96
97 /**
98 * Sets the artifact being depended on.
99 *
100 * @param artifact The artifact, must not be {@code null}.
101 * @return The new dependency, never {@code null}.
102 */
103 public Dependency setArtifact( Artifact artifact )
104 {
105 if ( this.artifact.equals( artifact ) )
106 {
107 return this;
108 }
109 return new Dependency( artifact, scope, exclusions, optional );
110 }
111
112 /**
113 * Gets the scope of the dependency. The scope defines in which context this dependency is relevant.
114 *
115 * @return The scope or an empty string if not set, never {@code null}.
116 */
117 public String getScope()
118 {
119 return scope;
120 }
121
122 /**
123 * Sets the scope of the dependency, e.g. "compile".
124 *
125 * @param scope The scope of the dependency, may be {@code null}.
126 * @return The new dependency, never {@code null}.
127 */
128 public Dependency setScope( String scope )
129 {
130 if ( this.scope.equals( scope ) || ( scope == null && this.scope.length() <= 0 ) )
131 {
132 return this;
133 }
134 return new Dependency( artifact, scope, exclusions, optional );
135 }
136
137 /**
138 * Indicates whether this dependency is optional or not. Optional dependencies can be ignored in some contexts.
139 *
140 * @return {@code true} if the dependency is (definitively) optional, {@code false} otherwise.
141 */
142 public boolean isOptional()
143 {
144 return Boolean.TRUE.equals( optional );
145 }
146
147 /**
148 * Gets the optional flag for the dependency. Note: Most clients will usually call {@link #isOptional()} to
149 * determine the optional flag, this method is for advanced use cases where three-valued logic is required.
150 *
151 * @return The optional flag or {@code null} if unspecified.
152 */
153 public Boolean getOptional()
154 {
155 return optional;
156 }
157
158 /**
159 * Sets the optional flag for the dependency.
160 *
161 * @param optional {@code true} if the dependency is optional, {@code false} if the dependency is mandatory, may be
162 * {@code null} if unspecified.
163 * @return The new dependency, never {@code null}.
164 */
165 public Dependency setOptional( Boolean optional )
166 {
167 if ( eq( this.optional, optional ) )
168 {
169 return this;
170 }
171 return new Dependency( artifact, scope, exclusions, optional );
172 }
173
174 /**
175 * Gets the exclusions for this dependency. Exclusions can be used to remove transitive dependencies during
176 * resolution.
177 *
178 * @return The (read-only) exclusions, never {@code null}.
179 */
180 public Collection<Exclusion> getExclusions()
181 {
182 return exclusions;
183 }
184
185 /**
186 * Sets the exclusions for the dependency.
187 *
188 * @param exclusions The exclusions, may be {@code null}.
189 * @return The new dependency, never {@code null}.
190 */
191 public Dependency setExclusions( Collection<Exclusion> exclusions )
192 {
193 if ( hasEquivalentExclusions( exclusions ) )
194 {
195 return this;
196 }
197 return new Dependency( artifact, scope, optional, exclusions );
198 }
199
200 private boolean hasEquivalentExclusions( Collection<Exclusion> exclusions )
201 {
202 if ( exclusions == null || exclusions.isEmpty() )
203 {
204 return this.exclusions.isEmpty();
205 }
206 if ( exclusions instanceof Set )
207 {
208 return this.exclusions.equals( exclusions );
209 }
210 return exclusions.size() >= this.exclusions.size() && this.exclusions.containsAll( exclusions )
211 && exclusions.containsAll( this.exclusions );
212 }
213
214 @Override
215 public String toString()
216 {
217 return String.valueOf( getArtifact() ) + " (" + getScope() + ( isOptional() ? "?" : "" ) + ")";
218 }
219
220 @Override
221 public boolean equals( Object obj )
222 {
223 if ( obj == this )
224 {
225 return true;
226 }
227 else if ( obj == null || !getClass().equals( obj.getClass() ) )
228 {
229 return false;
230 }
231
232 Dependency that = (Dependency) obj;
233
234 return artifact.equals( that.artifact ) && scope.equals( that.scope ) && eq( optional, that.optional )
235 && exclusions.equals( that.exclusions );
236 }
237
238 private static <T> boolean eq( T o1, T o2 )
239 {
240 return ( o1 != null ) ? o1.equals( o2 ) : o2 == null;
241 }
242
243 @Override
244 public int hashCode()
245 {
246 int hash = 17;
247 hash = hash * 31 + artifact.hashCode();
248 hash = hash * 31 + scope.hashCode();
249 hash = hash * 31 + ( optional != null ? optional.hashCode() : 0 );
250 hash = hash * 31 + exclusions.size();
251 return hash;
252 }
253
254 private static class Exclusions
255 extends AbstractSet<Exclusion>
256 {
257
258 private final Exclusion[] exclusions;
259
260 public static Set<Exclusion> copy( Collection<Exclusion> exclusions )
261 {
262 if ( exclusions == null || exclusions.isEmpty() )
263 {
264 return Collections.emptySet();
265 }
266 return new Exclusions( exclusions );
267 }
268
269 private Exclusions( Collection<Exclusion> exclusions )
270 {
271 if ( exclusions.size() > 1 && !( exclusions instanceof Set ) )
272 {
273 exclusions = new LinkedHashSet<Exclusion>( exclusions );
274 }
275 this.exclusions = exclusions.toArray( new Exclusion[exclusions.size()] );
276 }
277
278 @Override
279 public Iterator<Exclusion> iterator()
280 {
281 return new Iterator<Exclusion>()
282 {
283
284 private int cursor = 0;
285
286 public boolean hasNext()
287 {
288 return cursor < exclusions.length;
289 }
290
291 public Exclusion next()
292 {
293 try
294 {
295 Exclusion exclusion = exclusions[cursor];
296 cursor++;
297 return exclusion;
298 }
299 catch ( IndexOutOfBoundsException e )
300 {
301 throw new NoSuchElementException();
302 }
303 }
304
305 public void remove()
306 {
307 throw new UnsupportedOperationException();
308 }
309
310 };
311 }
312
313 @Override
314 public int size()
315 {
316 return exclusions.length;
317 }
318
319 }
320
321 }