restrictions = Collections.emptyList();
return new VersionRange( new DefaultArtifactVersion( version ), restrictions );
}
/**
* Creates and returns a new VersionRange
that is a restriction of this
* version range and the specified version range.
*
* Note: Precedence is given to the recommended version from this version range over the
* recommended version from the specified version range.
*
*
* @param restriction the VersionRange
that will be used to restrict this version
* range.
* @return the VersionRange
that is a restriction of this version range and the
* specified version range.
*
* The restrictions of the returned version range will be an intersection of the restrictions
* of this version range and the specified version range if both version ranges have
* restrictions. Otherwise, the restrictions on the returned range will be empty.
*
*
* The recommended version of the returned version range will be the recommended version of
* this version range, provided that ranges falls within the intersected restrictions. If
* the restrictions are empty, this version range's recommended version is used if it is not
* null
. If it is null
, the specified version range's recommended
* version is used (provided it is non-null
). If no recommended version can be
* obtained, the returned version range's recommended version is set to null
.
*
* @throws NullPointerException if the specified VersionRange
is
* null
.
*/
public VersionRange restrict( VersionRange restriction )
{
List r1 = this.restrictions;
List r2 = restriction.restrictions;
List restrictions;
if ( r1.isEmpty() || r2.isEmpty() )
{
restrictions = Collections.emptyList();
}
else
{
restrictions = intersection( r1, r2 );
}
ArtifactVersion version = null;
if ( restrictions.size() > 0 )
{
for ( Restriction r : restrictions )
{
if ( recommendedVersion != null && r.containsVersion( recommendedVersion ) )
{
// if we find the original, use that
version = recommendedVersion;
break;
}
else if ( version == null && restriction.getRecommendedVersion() != null
&& r.containsVersion( restriction.getRecommendedVersion() ) )
{
// use this if we can, but prefer the original if possible
version = restriction.getRecommendedVersion();
}
}
}
// Either the original or the specified version ranges have no restrictions
else if ( recommendedVersion != null )
{
// Use the original recommended version since it exists
version = recommendedVersion;
}
else if ( restriction.recommendedVersion != null )
{
// Use the recommended version from the specified VersionRange since there is no
// original recommended version
version = restriction.recommendedVersion;
}
/* TODO: should throw this immediately, but need artifact
else
{
throw new OverConstrainedVersionException( "Restricting incompatible version ranges" );
}
*/
return new VersionRange( version, restrictions );
}
private List intersection( List r1, List r2 )
{
List restrictions = new ArrayList( r1.size() + r2.size() );
Iterator i1 = r1.iterator();
Iterator i2 = r2.iterator();
Restriction res1 = i1.next();
Restriction res2 = i2.next();
boolean done = false;
while ( !done )
{
if ( res1.getLowerBound() == null || res2.getUpperBound() == null
|| res1.getLowerBound().compareTo( res2.getUpperBound() ) <= 0 )
{
if ( res1.getUpperBound() == null || res2.getLowerBound() == null
|| res1.getUpperBound().compareTo( res2.getLowerBound() ) >= 0 )
{
ArtifactVersion lower;
ArtifactVersion upper;
boolean lowerInclusive;
boolean upperInclusive;
// overlaps
if ( res1.getLowerBound() == null )
{
lower = res2.getLowerBound();
lowerInclusive = res2.isLowerBoundInclusive();
}
else if ( res2.getLowerBound() == null )
{
lower = res1.getLowerBound();
lowerInclusive = res1.isLowerBoundInclusive();
}
else
{
int comparison = res1.getLowerBound().compareTo( res2.getLowerBound() );
if ( comparison < 0 )
{
lower = res2.getLowerBound();
lowerInclusive = res2.isLowerBoundInclusive();
}
else if ( comparison == 0 )
{
lower = res1.getLowerBound();
lowerInclusive = res1.isLowerBoundInclusive() && res2.isLowerBoundInclusive();
}
else
{
lower = res1.getLowerBound();
lowerInclusive = res1.isLowerBoundInclusive();
}
}
if ( res1.getUpperBound() == null )
{
upper = res2.getUpperBound();
upperInclusive = res2.isUpperBoundInclusive();
}
else if ( res2.getUpperBound() == null )
{
upper = res1.getUpperBound();
upperInclusive = res1.isUpperBoundInclusive();
}
else
{
int comparison = res1.getUpperBound().compareTo( res2.getUpperBound() );
if ( comparison < 0 )
{
upper = res1.getUpperBound();
upperInclusive = res1.isUpperBoundInclusive();
}
else if ( comparison == 0 )
{
upper = res1.getUpperBound();
upperInclusive = res1.isUpperBoundInclusive() && res2.isUpperBoundInclusive();
}
else
{
upper = res2.getUpperBound();
upperInclusive = res2.isUpperBoundInclusive();
}
}
// don't add if they are equal and one is not inclusive
if ( lower == null || upper == null || lower.compareTo( upper ) != 0 )
{
restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) );
}
else if ( lowerInclusive && upperInclusive )
{
restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) );
}
//noinspection ObjectEquality
if ( upper == res2.getUpperBound() )
{
// advance res2
if ( i2.hasNext() )
{
res2 = i2.next();
}
else
{
done = true;
}
}
else
{
// advance res1
if ( i1.hasNext() )
{
res1 = i1.next();
}
else
{
done = true;
}
}
}
else
{
// move on to next in r1
if ( i1.hasNext() )
{
res1 = i1.next();
}
else
{
done = true;
}
}
}
else
{
// move on to next in r2
if ( i2.hasNext() )
{
res2 = i2.next();
}
else
{
done = true;
}
}
}
return restrictions;
}
public ArtifactVersion getSelectedVersion( Artifact artifact )
throws OverConstrainedVersionException
{
ArtifactVersion version;
if ( recommendedVersion != null )
{
version = recommendedVersion;
}
else
{
if ( restrictions.size() == 0 )
{
throw new OverConstrainedVersionException( "The artifact has no valid ranges", artifact );
}
version = null;
}
return version;
}
public boolean isSelectedVersionKnown( Artifact artifact )
throws OverConstrainedVersionException
{
boolean value = false;
if ( recommendedVersion != null )
{
value = true;
}
else
{
if ( restrictions.size() == 0 )
{
throw new OverConstrainedVersionException( "The artifact has no valid ranges", artifact );
}
}
return value;
}
public String toString()
{
if ( recommendedVersion != null )
{
return recommendedVersion.toString();
}
else
{
StringBuilder buf = new StringBuilder();
for ( Iterator i = restrictions.iterator(); i.hasNext(); )
{
Restriction r = i.next();
buf.append( r.toString() );
if ( i.hasNext() )
{
buf.append( ',' );
}
}
return buf.toString();
}
}
public ArtifactVersion matchVersion( List versions )
{
// TODO: could be more efficient by sorting the list and then moving along the restrictions in order?
ArtifactVersion matched = null;
for ( ArtifactVersion version : versions )
{
if ( containsVersion( version ) )
{
// valid - check if it is greater than the currently matched version
if ( matched == null || version.compareTo( matched ) > 0 )
{
matched = version;
}
}
}
return matched;
}
public boolean containsVersion( ArtifactVersion version )
{
for ( Restriction restriction : restrictions )
{
if ( restriction.containsVersion( version ) )
{
return true;
}
}
return false;
}
public boolean hasRestrictions()
{
return !restrictions.isEmpty() && recommendedVersion == null;
}
public boolean equals( Object obj )
{
if ( this == obj )
{
return true;
}
if ( !( obj instanceof VersionRange ) )
{
return false;
}
VersionRange other = (VersionRange) obj;
boolean equals =
recommendedVersion == other.recommendedVersion
|| ( ( recommendedVersion != null ) && recommendedVersion.equals( other.recommendedVersion ) );
equals &=
restrictions == other.restrictions
|| ( ( restrictions != null ) && restrictions.equals( other.restrictions ) );
return equals;
}
public int hashCode()
{
int hash = 7;
hash = 31 * hash + ( recommendedVersion == null ? 0 : recommendedVersion.hashCode() );
hash = 31 * hash + ( restrictions == null ? 0 : restrictions.hashCode() );
return hash;
}
}