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
9 * Sonatype, Inc. - initial API and implementation
10 *******************************************************************************/
11 package org
.eclipse
.aether
.graph
;
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
;
21 import org
.eclipse
.aether
.artifact
.Artifact
;
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.
27 public final class Dependency
30 private final Artifact artifact
;
32 private final String scope
;
34 private final Boolean optional
;
36 private final Set
<Exclusion
> exclusions
;
39 * Creates a mandatory dependency on the specified artifact with the given scope.
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}.
44 public Dependency( Artifact artifact
, String scope
)
46 this( artifact
, scope
, false );
50 * Creates a dependency on the specified artifact with the given scope.
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}.
56 public Dependency( Artifact artifact
, String scope
, Boolean optional
)
58 this( artifact
, scope
, optional
, null );
62 * Creates a dependency on the specified artifact with the given scope and exclusions.
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.
69 public Dependency( Artifact artifact
, String scope
, Boolean optional
, Collection
<Exclusion
> exclusions
)
71 this( artifact
, scope
, Exclusions
.copy( exclusions
), optional
);
74 private Dependency( Artifact artifact
, String scope
, Set
<Exclusion
> exclusions
, Boolean optional
)
76 // NOTE: This constructor assumes immutability of the provided exclusion collection, for internal use only
77 if ( artifact
== null )
79 throw new IllegalArgumentException( "no artifact specified for dependency" );
81 this.artifact
= artifact
;
82 this.scope
= ( scope
!= null ) ? scope
: "";
83 this.optional
= optional
;
84 this.exclusions
= exclusions
;
88 * Gets the artifact being depended on.
90 * @return The artifact, never {@code null}.
92 public Artifact
getArtifact()
98 * Sets the artifact being depended on.
100 * @param artifact The artifact, must not be {@code null}.
101 * @return The new dependency, never {@code null}.
103 public Dependency
setArtifact( Artifact artifact
)
105 if ( this.artifact
.equals( artifact
) )
109 return new Dependency( artifact
, scope
, exclusions
, optional
);
113 * Gets the scope of the dependency. The scope defines in which context this dependency is relevant.
115 * @return The scope or an empty string if not set, never {@code null}.
117 public String
getScope()
123 * Sets the scope of the dependency, e.g. "compile".
125 * @param scope The scope of the dependency, may be {@code null}.
126 * @return The new dependency, never {@code null}.
128 public Dependency
setScope( String scope
)
130 if ( this.scope
.equals( scope
) || ( scope
== null && this.scope
.length() <= 0 ) )
134 return new Dependency( artifact
, scope
, exclusions
, optional
);
138 * Indicates whether this dependency is optional or not. Optional dependencies can be ignored in some contexts.
140 * @return {@code true} if the dependency is (definitively) optional, {@code false} otherwise.
142 public boolean isOptional()
144 return Boolean
.TRUE
.equals( optional
);
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.
151 * @return The optional flag or {@code null} if unspecified.
153 public Boolean
getOptional()
159 * Sets the optional flag for the dependency.
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}.
165 public Dependency
setOptional( Boolean optional
)
167 if ( eq( this.optional
, optional
) )
171 return new Dependency( artifact
, scope
, exclusions
, optional
);
175 * Gets the exclusions for this dependency. Exclusions can be used to remove transitive dependencies during
178 * @return The (read-only) exclusions, never {@code null}.
180 public Collection
<Exclusion
> getExclusions()
186 * Sets the exclusions for the dependency.
188 * @param exclusions The exclusions, may be {@code null}.
189 * @return The new dependency, never {@code null}.
191 public Dependency
setExclusions( Collection
<Exclusion
> exclusions
)
193 if ( hasEquivalentExclusions( exclusions
) )
197 return new Dependency( artifact
, scope
, optional
, exclusions
);
200 private boolean hasEquivalentExclusions( Collection
<Exclusion
> exclusions
)
202 if ( exclusions
== null || exclusions
.isEmpty() )
204 return this.exclusions
.isEmpty();
206 if ( exclusions
instanceof Set
)
208 return this.exclusions
.equals( exclusions
);
210 return exclusions
.size() >= this.exclusions
.size() && this.exclusions
.containsAll( exclusions
)
211 && exclusions
.containsAll( this.exclusions
);
215 public String
toString()
217 return String
.valueOf( getArtifact() ) + " (" + getScope() + ( isOptional() ?
"?" : "" ) + ")";
221 public boolean equals( Object obj
)
227 else if ( obj
== null || !getClass().equals( obj
.getClass() ) )
232 Dependency that
= (Dependency
) obj
;
234 return artifact
.equals( that
.artifact
) && scope
.equals( that
.scope
) && eq( optional
, that
.optional
)
235 && exclusions
.equals( that
.exclusions
);
238 private static <T
> boolean eq( T o1
, T o2
)
240 return ( o1
!= null ) ? o1
.equals( o2
) : o2
== null;
244 public int hashCode()
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();
254 private static class Exclusions
255 extends AbstractSet
<Exclusion
>
258 private final Exclusion
[] exclusions
;
260 public static Set
<Exclusion
> copy( Collection
<Exclusion
> exclusions
)
262 if ( exclusions
== null || exclusions
.isEmpty() )
264 return Collections
.emptySet();
266 return new Exclusions( exclusions
);
269 private Exclusions( Collection
<Exclusion
> exclusions
)
271 if ( exclusions
.size() > 1 && !( exclusions
instanceof Set
) )
273 exclusions
= new LinkedHashSet
<Exclusion
>( exclusions
);
275 this.exclusions
= exclusions
.toArray( new Exclusion
[exclusions
.size()] );
279 public Iterator
<Exclusion
> iterator()
281 return new Iterator
<Exclusion
>()
284 private int cursor
= 0;
286 public boolean hasNext()
288 return cursor
< exclusions
.length
;
291 public Exclusion
next()
295 Exclusion exclusion
= exclusions
[cursor
];
299 catch ( IndexOutOfBoundsException e
)
301 throw new NoSuchElementException();
307 throw new UnsupportedOperationException();
316 return exclusions
.length
;