| /********************************************************************* |
| * Copyright (c) 2007, 2012 SpringSource |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| **********************************************************************/ |
| |
| package org.eclipse.virgo.ide.bundlerepository.domain; |
| |
| /** |
| * Represents a version range as specified in an import package header |
| * |
| */ |
| public class VersionRange { |
| |
| public static final OsgiVersion INFINITY = new OsgiVersion(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, ""); |
| |
| private transient OsgiVersion lowerBound; |
| |
| private transient OsgiVersion upperBound; |
| |
| private boolean isInclusiveLowerBound = true; // if true then the a version |
| // == lowerBound will |
| // satisfy this range |
| |
| private boolean isInclusiveUpperBound = false; // if true then a version == |
| // upperBound will satisfy |
| // this range |
| |
| // these next shenanigans are because JPA can't persist an embeddable type |
| // nested in an embeddable type |
| // therefore we have to either fudge things in the database (by storing |
| // version ranges in their own table), or |
| // fudge things in the domain model (to allow version range and import |
| // package information to be stored in |
| // the same table). We've chosen the latter option here as we never want to |
| // retrieve PackageImports without their |
| // version ranges. |
| private int lowerBoundMajor; |
| |
| private int lowerBoundMinor; |
| |
| private int lowerBoundService; |
| |
| private String lowerBoundQualifier; |
| |
| private int upperBoundMajor; |
| |
| private int upperBoundMinor; |
| |
| private int upperBoundService; |
| |
| private String upperBoundQualifier; |
| |
| protected VersionRange() { |
| } |
| |
| /** |
| * Construct a version range from the String format found in the version attribute of an import package header |
| * |
| * @param osgiRangeSpecification range specification |
| */ |
| public VersionRange(String osgiRangeSpecification) { |
| if (osgiRangeSpecification == null || osgiRangeSpecification.equals("")) { |
| osgiRangeSpecification = "0.0.0"; |
| } |
| // strip any surrounding quotes |
| if (osgiRangeSpecification.startsWith("\"")) { |
| osgiRangeSpecification = osgiRangeSpecification.substring(1, osgiRangeSpecification.length() - 1); |
| } |
| |
| osgiRangeSpecification = extractLowerBoundCriteria(osgiRangeSpecification); |
| |
| osgiRangeSpecification = extractUpperBoundCriteria(osgiRangeSpecification); |
| |
| boolean isRange = osgiRangeSpecification.indexOf(",") != -1; |
| if (isRange) { |
| int splitIndex = osgiRangeSpecification.indexOf(","); |
| setLowerBound(new OsgiVersion(osgiRangeSpecification.substring(0, splitIndex))); |
| try { |
| setUpperBound(new OsgiVersion(osgiRangeSpecification.substring(splitIndex + 1))); |
| } catch (IllegalArgumentException e) { |
| // default to infinity |
| setUpperBound(INFINITY); |
| } |
| } else { |
| setLowerBound(new OsgiVersion(osgiRangeSpecification)); |
| setUpperBound(INFINITY); |
| } |
| } |
| |
| /** |
| * Create a version range object |
| * |
| * @param lowerBound lower bound of range |
| * @param lowerInclusive whether the lower bound is inclusive (true) or exclusive (false) |
| * @param upperBound upper bound of range |
| * @param upperInclusive whether the upper bound is inclusive (true) or exclusive (false) |
| */ |
| public VersionRange(OsgiVersion lowerBound, boolean lowerInclusive, OsgiVersion upperBound, boolean upperInclusive) { |
| setLowerBound(lowerBound); |
| setUpperBound(upperBound); |
| this.isInclusiveLowerBound = lowerInclusive; |
| this.isInclusiveUpperBound = upperInclusive; |
| } |
| |
| /* shenanigans with version fields are because of JPA limitation */ |
| public OsgiVersion getLowerBound() { |
| if (this.lowerBound == null) { |
| this.lowerBound = new OsgiVersion(this.lowerBoundMajor, this.lowerBoundMinor, this.lowerBoundService, this.lowerBoundQualifier); |
| } |
| return this.lowerBound; |
| } |
| |
| /* shenanigans with version fields are because of JPA limitation */ |
| public void setLowerBound(OsgiVersion bound) { |
| this.lowerBound = bound; |
| this.lowerBoundMajor = bound.getMajor(); |
| this.lowerBoundMinor = bound.getMinor(); |
| this.lowerBoundService = bound.getService(); |
| this.lowerBoundQualifier = bound.getQualifier(); |
| } |
| |
| /* shenanigans with version fields are because of JPA limitation */ |
| public OsgiVersion getUpperBound() { |
| if (this.upperBound == null) { |
| this.upperBound = new OsgiVersion(this.upperBoundMajor, this.upperBoundMinor, this.upperBoundService, this.upperBoundQualifier); |
| } |
| return this.upperBound; |
| } |
| |
| public boolean isUpperBoundInfinity() { |
| return INFINITY.equals(this.upperBound); |
| } |
| |
| /* shenanigans with version fields are because of JPA limitation */ |
| public void setUpperBound(OsgiVersion bound) { |
| this.upperBound = bound; |
| this.upperBoundMajor = bound.getMajor(); |
| this.upperBoundMinor = bound.getMinor(); |
| this.upperBoundService = bound.getService(); |
| this.upperBoundQualifier = bound.getQualifier(); |
| } |
| |
| public boolean isInclusiveLowerBound() { |
| return this.isInclusiveLowerBound; |
| } |
| |
| public boolean isInclusiveUpperBound() { |
| return this.isInclusiveUpperBound; |
| } |
| |
| /** |
| * Return true if the given version falls within this range |
| */ |
| public boolean contains(OsgiVersion version) { |
| // check lower bound |
| int lowerBoundComparison = version.compareTo(getLowerBound()); |
| if (lowerBoundComparison < 0) { |
| return false; |
| } else if (lowerBoundComparison == 0 && !this.isInclusiveLowerBound) { |
| return false; |
| } |
| // we've passed the lower bound test, check the upper bound |
| int upperBoundComparison = version.compareTo(getUpperBound()); |
| if (upperBoundComparison > 0) { |
| return false; |
| } else if (upperBoundComparison == 0 && !this.isInclusiveUpperBound) { |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append(this.isInclusiveLowerBound ? "[" : "("); |
| sb.append(getLowerBound().toString()); |
| sb.append(", "); |
| if (getUpperBound().equals(INFINITY)) { |
| sb.append("infinity)"); |
| } else { |
| sb.append(getUpperBound().toString()); |
| sb.append(this.isInclusiveUpperBound ? "]" : ")"); |
| } |
| return sb.toString(); |
| } |
| |
| /* generated */ |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + (this.isInclusiveLowerBound ? 1231 : 1237); |
| result = prime * result + (this.isInclusiveUpperBound ? 1231 : 1237); |
| result = prime * result + this.lowerBoundMajor; |
| result = prime * result + this.lowerBoundMinor; |
| result = prime * result + (this.lowerBoundQualifier == null ? 0 : this.lowerBoundQualifier.hashCode()); |
| result = prime * result + this.lowerBoundService; |
| result = prime * result + this.upperBoundMajor; |
| result = prime * result + this.upperBoundMinor; |
| result = prime * result + (this.upperBoundQualifier == null ? 0 : this.upperBoundQualifier.hashCode()); |
| result = prime * result + this.upperBoundService; |
| return result; |
| } |
| |
| /* generated */ |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (getClass() != obj.getClass()) { |
| return false; |
| } |
| final VersionRange other = (VersionRange) obj; |
| if (this.isInclusiveLowerBound != other.isInclusiveLowerBound) { |
| return false; |
| } |
| if (this.isInclusiveUpperBound != other.isInclusiveUpperBound) { |
| return false; |
| } |
| if (this.lowerBoundMajor != other.lowerBoundMajor) { |
| return false; |
| } |
| if (this.lowerBoundMinor != other.lowerBoundMinor) { |
| return false; |
| } |
| if (this.lowerBoundQualifier == null) { |
| if (other.lowerBoundQualifier != null) { |
| return false; |
| } |
| } else if (!this.lowerBoundQualifier.equals(other.lowerBoundQualifier)) { |
| return false; |
| } |
| if (this.lowerBoundService != other.lowerBoundService) { |
| return false; |
| } |
| if (this.upperBoundMajor != other.upperBoundMajor) { |
| return false; |
| } |
| if (this.upperBoundMinor != other.upperBoundMinor) { |
| return false; |
| } |
| if (this.upperBoundQualifier == null) { |
| if (other.upperBoundQualifier != null) { |
| return false; |
| } |
| } else if (!this.upperBoundQualifier.equals(other.upperBoundQualifier)) { |
| return false; |
| } |
| if (this.upperBoundService != other.upperBoundService) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Parse any inclusive "]" or exclusive ")" upper bound postfix and return the input string with them stripped |
| */ |
| private String extractUpperBoundCriteria(String osgiRangeSpecification) { |
| // parse any ending inclusive / exclusive brackets |
| if (osgiRangeSpecification.endsWith(")")) { |
| this.isInclusiveUpperBound = false; |
| osgiRangeSpecification = osgiRangeSpecification.substring(0, osgiRangeSpecification.length() - 1); |
| } else if (osgiRangeSpecification.endsWith("]")) { |
| this.isInclusiveUpperBound = true; |
| osgiRangeSpecification = osgiRangeSpecification.substring(0, osgiRangeSpecification.length() - 1); |
| } else { |
| this.isInclusiveUpperBound = true; |
| } |
| return osgiRangeSpecification; |
| } |
| |
| /** |
| * Parse any inclusive "[" or exclusive "(" lower bound prefix and return the input string with them stripped. |
| */ |
| private String extractLowerBoundCriteria(String osgiRangeSpecification) { |
| // parse any opening inclusive / exclusive brackets |
| if (osgiRangeSpecification.startsWith("(")) { |
| this.isInclusiveLowerBound = false; |
| osgiRangeSpecification = osgiRangeSpecification.substring(1); |
| } else if (osgiRangeSpecification.startsWith("[")) { |
| osgiRangeSpecification = osgiRangeSpecification.substring(1); |
| this.isInclusiveLowerBound = true; |
| } else { |
| this.isInclusiveLowerBound = true; |
| } |
| return osgiRangeSpecification; |
| } |
| |
| } |