src/java/org/apache/ivy/osgi/util/VersionRange.java (264 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 * * https://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 org.apache.ivy.osgi.util; import java.text.ParseException; import static org.apache.ivy.util.StringUtils.isNullOrEmpty; /** * Provides version range support. */ public class VersionRange { private boolean startExclusive; private Version startVersion; private boolean endExclusive; private Version endVersion; public VersionRange(String versionStr) throws ParseException { if (isNullOrEmpty(versionStr)) { startExclusive = false; startVersion = new Version(0, 0, 0, null); endExclusive = true; endVersion = null; } else { new VersionRangeParser(versionStr).parse(); } } class VersionRangeParser { /** * value to parse */ private final String version; /** * the length of the source */ private int length; /** * position in the source */ private int pos = 0; /** * last read character */ private char c; /** * Default constructor * * @param version * the version to parse */ VersionRangeParser(String version) { this.version = version; this.length = version.length(); } /** * Do the parsing * * @throws ParseException if something goes wrong */ void parse() throws ParseException { boolean range = parseStart(); startVersion = parseVersion(); if (startVersion == null) { throw new ParseException("Expecting a number", pos); } if (parseVersionSeparator()) { endVersion = parseVersion(); parseEnd(); } else if (range) { throw new ParseException("Expecting ,", pos); } else { // simple number endVersion = null; startExclusive = false; endExclusive = false; } } private char readNext() { if (pos == length) { c = '\0'; } else { c = version.charAt(pos++); } return c; } private void unread() { if (pos > 0) { pos--; } } private boolean parseStart() { skipWhiteSpace(); switch (readNext()) { case '[': startExclusive = false; return true; case '(': startExclusive = true; return true; default: unread(); return false; } } private void skipWhiteSpace() { do { switch (readNext()) { case ' ': continue; default: unread(); return; } } while (pos < length); } private Version parseVersion() { Integer major = parseNumber(); if (major == null) { return null; } Integer minor = 0; Integer patch = 0; String qualifier = null; if (parseNumberSeparator()) { minor = parseNumber(); if (minor == null) { minor = 0; } else if (parseNumberSeparator()) { patch = parseNumber(); if (patch == null) { patch = 0; } else if (parseNumberSeparator()) { qualifier = parseQualifier(); } } } return new Version(major, minor, patch, qualifier); } private Integer parseNumber() { skipWhiteSpace(); Integer n = null; do { switch (readNext()) { case '\0': return n; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = (n == null ? 0 : n * 10) + c - '0'; break; default: unread(); return n; } } while (pos < length); return n; } private boolean parseNumberSeparator() { switch (readNext()) { case '.': return true; default: unread(); return false; } } private boolean parseVersionSeparator() { skipWhiteSpace(); switch (readNext()) { case ',': return true; default: unread(); return false; } } private String parseQualifier() { StringBuilder q = new StringBuilder(); do { readNext(); if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '-' || c == '_') { q.append(c); } else { unread(); break; } } while (pos < length); if (q.length() == 0) { return null; } return q.toString(); } private void parseEnd() throws ParseException { skipWhiteSpace(); switch (readNext()) { case ']': endExclusive = false; break; case ')': endExclusive = true; break; default: unread(); throw new ParseException("Expecting ] or )", pos); } } } public VersionRange(boolean startExclusive, Version startVersion, boolean endExclusive, Version endVersion) { this.startExclusive = startExclusive; this.startVersion = startVersion; this.endExclusive = endExclusive; this.endVersion = endVersion; } public VersionRange(Version startVersion) { this.startExclusive = false; this.startVersion = startVersion; this.endExclusive = true; this.endVersion = null; } public String toString() { return (startExclusive ? "(" : "[") + startVersion.toString() + "," + (endVersion == null ? "" : endVersion.toString()) + (endExclusive ? ")" : "]"); } public String toIvyRevision() { StringBuilder buffer = new StringBuilder(); buffer.append(startExclusive ? "(" : "[").append(startVersion).append(","); if (endVersion != null) { if (!endExclusive || startVersion.equals(endVersion)) { buffer.append(endVersion.withNudgedPatch()); } else { buffer.append(endVersion); } } return buffer.append(")").toString(); } public boolean isEndExclusive() { return this.endExclusive; } public Version getEndVersion() { return this.endVersion; } public boolean isStartExclusive() { return this.startExclusive; } public Version getStartVersion() { return this.startVersion; } public boolean isClosedRange() { return startVersion.equals(endVersion); } public boolean contains(String versionStr) { return contains(new Version(versionStr)); } public boolean contains(Version version) { return (startExclusive ? version.compareUnqualified(startVersion) > 0 : version.compareUnqualified(startVersion) >= 0) && (endVersion == null || (endExclusive ? version.compareUnqualified(endVersion) < 0 : version.compareUnqualified(endVersion) <= 0)); } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (endExclusive ? 1231 : 1237); result = prime * result + ((endVersion == null) ? 0 : endVersion.hashCode()); result = prime * result + (startExclusive ? 1231 : 1237); result = prime * result + ((startVersion == null) ? 0 : startVersion.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || !(obj instanceof VersionRange)) { return false; } VersionRange other = (VersionRange) obj; if (endExclusive != other.endExclusive) { return false; } if (endVersion == null) { if (other.endVersion != null) { return false; } } else if (!endVersion.equals(other.endVersion)) { return false; } return startExclusive == other.startExclusive && (startVersion == null ? other.startVersion == null : startVersion.equals(other.startVersion)); } }