package org.jboss.windup.config.metadata;
import org.apache.commons.lang3.StringUtils;
import org.jboss.forge.furnace.versions.MultipleVersionRange;
import org.jboss.forge.furnace.versions.VersionRange;
import org.jboss.forge.furnace.versions.Versions;
import org.jboss.windup.graph.model.TechnologyReferenceModel;
/**
* Represents a technology with a name (id) and {@link VersionRange}.
*
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*/
public class TechnologyReference
{
private String id;
private VersionRange versionRange;
/**
* DO NOT USE -- This is just here to make proxies possible
*/
public TechnologyReference()
{
}
public TechnologyReference(TechnologyReferenceModel model)
{
this(model.getTechnologyID(), model.getVersionRange());
}
/**
* Construct a new {@link TechnologyReference} using the given {@link String} ID and {@link String} version range.
*/
public TechnologyReference(String id, String versionRange)
{
this.id = id;
if (versionRange != null)
this.versionRange = Versions.parseVersionRange(versionRange);
}
/**
* Construct a new {@link TechnologyReference} using the given {@link String} ID and {@link VersionRange}.
*/
public TechnologyReference(String id, VersionRange versionRange)
{
this.id = id;
this.versionRange = versionRange;
}
/**
* Construct a new {@link TechnologyReference} using the given {@link String} ID.
*/
public TechnologyReference(String id)
{
this(id, (VersionRange) null);
}
/**
* Parses a {@link TechnologyReference} from a string that is formatted as either
* "id" or "id:versionRange".
*/
public static TechnologyReference parseFromIDAndVersion(String idAndVersion)
{
if (idAndVersion.contains(":"))
{
String tech = StringUtils.substringBefore(idAndVersion, ":");
String versionRangeString = StringUtils.substringAfter(idAndVersion, ":");
if (!versionRangeString.matches("^[(\\[].*[)\\]]"))
versionRangeString = "[" + versionRangeString + "]";
VersionRange versionRange = Versions.parseVersionRange(versionRangeString);
return new TechnologyReference(tech, versionRange);
}
return new TechnologyReference(idAndVersion);
}
/**
* Get the name/ID of this {@link TechnologyReference}.
*/
public String getId()
{
return id;
}
/**
* Get the {@link VersionRange} of this {@link TechnologyReference}.
*/
public VersionRange getVersionRange()
{
return versionRange;
}
/**
* Returns true if the other {@link TechnologyReference} has the same technology id and the two version ranges overlap.
*/
public boolean matches(TechnologyReference other)
{
return StringUtils.equals(getId(), other.getId()) && versionRangesOverlap(other.getVersionRange());
}
/**
* Takes the given {@link VersionRange} objects and returns true if there is any overlap between the two
* ranges.
*
* If either is null, then it is treated as overlapping.
*/
public boolean versionRangesOverlap(VersionRange otherRange)
{
if (this.getVersionRange() == null || otherRange == null)
return true;
/*
* FIXME HACK - The code in MultipleVersionRange works pretty well for this calculation, so we are reusing that.
*
* Some of the other range intersection algorithms have design flaws that make them return results incorrectly.
*
* This hack needs an extensive unit test to insure that it retains the behavior that we expect.
*/
MultipleVersionRange range1Multiple;
if (getVersionRange() instanceof MultipleVersionRange)
range1Multiple = (MultipleVersionRange)getVersionRange();
else
range1Multiple = new MultipleVersionRange(getVersionRange());
try
{
VersionRange intersection = range1Multiple.getIntersection(otherRange);
return intersection != null && !intersection.isEmpty();
} catch (Throwable t)
{
// This generally only occurs if there was no intersection
return false;
}
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((versionRange == null) ? 0 : versionRange.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TechnologyReference other = (TechnologyReference) obj;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
if (versionRange == null)
{
if (other.versionRange != null)
return false;
}
else if (!versionRange.equals(other.versionRange))
return false;
return true;
}
/**
* This provides a parsable version string based upon the current {@link VersionRange}. If the version
* range is null, this will return null.
*/
public String getVersionRangeAsString()
{
if (this.versionRange == null)
return null;
return this.versionRange.toString();
}
@Override
public String toString()
{
String rangeString = getVersionRangeAsString();
String range = rangeString== null ? "" : ":" + rangeString;
return id + range;
}
}