/* * Copyright (C) 2013 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package interactivespaces.resource; import interactivespaces.SimpleInteractiveSpacesException; /** * A range of {@link Version}s. * * @author Keith M. Hughes */ public class VersionRange { /** * The symbol showing the upper part of the range is open. */ public static final String RANGE_UPPER_OPEN = ")"; /** * The symbol showing the upper part of the range is closed. */ public static final String RANGE_UPPER_CLOSED = "]"; /** * The symbol showing the lower part of the range is closed. */ public static final String RANGE_LOWER_CLOSED = "["; /** * The separator between the versions in the range. */ public static final String RANGE_SEPARATOR = ","; /** * The symbol to mark the range as exact. */ public static final String RANGE_EXACT = "="; /** * Parse a range string. * * @param minimumVersion * the minimum version * @param maximumVersion * the maximum version * * @return the range for the string * * @throws SimpleInteractiveSpacesException * improperly formatted range or a {@code null} string */ public static VersionRange parseVersionRange(String minimumVersion, String maximumVersion) throws SimpleInteractiveSpacesException { return new VersionRange(Version.parseVersion(minimumVersion), Version.parseVersion(maximumVersion), false); } /** * Parse a range string. * * @param range * the range string * * @return the range for the string * * @throws SimpleInteractiveSpacesException * improperly formatted range or a {@code null} string */ public static VersionRange parseVersionRange(String range) throws SimpleInteractiveSpacesException { if (range != null) { range = range.trim(); if (range.startsWith(RANGE_LOWER_CLOSED)) { int pos = range.indexOf(RANGE_SEPARATOR, 1); if (pos == -1) { throw new SimpleInteractiveSpacesException(String.format("Illegal version range %s, missing comma", range)); } Version minimum = Version.parseVersion(range.substring(1, pos)); Version maximum = null; boolean inclusive = false; if (range.endsWith(RANGE_UPPER_CLOSED)) { inclusive = true; } else if (!range.endsWith(RANGE_UPPER_OPEN)) { throw new SimpleInteractiveSpacesException(String.format( "Illegal version range %s, does not end with ] or )", range)); } maximum = Version.parseVersion(range.substring(pos + 1, range.length() - 1)); return new VersionRange(minimum, maximum, inclusive); } else if (range.startsWith(RANGE_EXACT)) { Version minimum = Version.parseVersion(range.substring(1)); return new VersionRange(minimum, minimum.incrementMicro(), false); } else { // Not a full range, but should be a single version return new VersionRange(Version.parseVersion(range)); } } else { throw new SimpleInteractiveSpacesException("Range is null"); } } /** * The minimum of the range. */ private Version minimum; /** * The maximum of the range. * * <p> * Can be {@code null} to represent infinity. */ private Version maximum; /** * Is the range inclusive? */ private boolean inclusive; /** * Construct a range which uses the version supplied as the minimum and sets the upper range to infinity. * * @param version * the minimum version */ public VersionRange(Version version) { this(version, null, true); } /** * Construct a range with a minimum and maximum. * * @param minimum * the minimum * @param maximum * the maximum, can be {@code null} to represent infinity * @param inclusive * {@code true} if should be inclusive */ public VersionRange(Version minimum, Version maximum, boolean inclusive) { this.minimum = minimum; this.maximum = maximum; this.inclusive = inclusive; } /** * Get the minimum. * * @return the minimum */ public Version getMinimum() { return minimum; } /** * Set the minimum. * * @param minimum * the new minimum */ public void setMinimum(Version minimum) { this.minimum = minimum; } /** * Get the maximum. * * @return the maximum, can be {@code null} to specify infinity */ public Version getMaximum() { return maximum; } /** * Set the maximum. * * @param maximum * the new maximum, can be {@code null} to specify infinity */ public void setMaximum(Version maximum) { this.maximum = maximum; } /** * Is the range inclusive of the maximum? * * @return {@code true} if inclusive */ public boolean isInclusive() { return inclusive; } /** * Set whether the range inclusive of the maximum. * * @param inclusive * {@code true} if inclusive */ public void setInclusive(boolean inclusive) { this.inclusive = inclusive; } /** * Does the range contain the given version? * * @param version * the version being checked * * @return {@code true} if the version is in the range */ public boolean contains(Version version) { if (version.lessThan(minimum)) { return false; } // The version is >= to the minimum if (maximum != null) { int maxComp = version.compareTo(maximum); return (maxComp < 0) || (maxComp == 0 && inclusive); } else { return true; } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (inclusive ? 1231 : 1237); result = prime * result + ((maximum == null) ? 0 : maximum.hashCode()); result = prime * result + ((minimum == null) ? 0 : minimum.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; } VersionRange other = (VersionRange) obj; if (inclusive != other.inclusive) { return false; } if (maximum == null) { if (other.maximum != null) { return false; } } else if (!maximum.equals(other.maximum)) { return false; } if (minimum == null) { if (other.minimum != null) { return false; } } else if (!minimum.equals(other.minimum)) { return false; } return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); if (maximum == null) { builder.append(minimum.toString()); } else { builder.append(RANGE_LOWER_CLOSED).append(minimum.toString()).append(", ").append(maximum.toString()) .append(inclusive ? RANGE_UPPER_CLOSED : RANGE_UPPER_OPEN); } return builder.toString(); } }