| /* |
| * 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; |
| |
| /** |
| * Provides OSGi version support. |
| */ |
| public class Version implements Comparable<Version> { |
| |
| private int major; |
| |
| private int minor; |
| |
| private int patch; |
| |
| private String qualifier; |
| |
| private String version; |
| |
| private String input; |
| |
| private volatile boolean split = false; |
| |
| private volatile boolean toString = false; |
| |
| public Version(String versionStr, String qualifier) { |
| this(qualifier == null ? versionStr : (versionStr + "." + qualifier)); |
| } |
| |
| public Version(String versionStr) { |
| this.input = versionStr; |
| split = false; |
| toString = false; |
| } |
| |
| public Version(int major, int minor, int patch, String qualifier) { |
| this.major = major; |
| this.minor = minor; |
| this.patch = patch; |
| this.qualifier = qualifier; |
| split = true; |
| toString = false; |
| } |
| |
| /** |
| * Build a version from another one while appending an extra qualifier |
| * |
| * @param baseVersion |
| * Version |
| * @param extraQualifier |
| * String |
| */ |
| public Version(Version baseVersion, String extraQualifier) { |
| this.major = baseVersion.major; |
| this.minor = baseVersion.minor; |
| this.patch = baseVersion.patch; |
| this.qualifier = (baseVersion.qualifier == null) ? extraQualifier |
| : (baseVersion.qualifier + extraQualifier); |
| split = true; |
| toString = false; |
| } |
| |
| private void ensureSplit() { |
| if (!split) { |
| synchronized (this) { |
| if (split) { |
| return; |
| } |
| String[] splits = input.split("\\."); |
| if (splits == null || splits.length == 0 || splits.length > 4) { |
| throw new RuntimeException(new ParseException("Ill-formed OSGi version", 0)); |
| } |
| try { |
| major = Integer.parseInt(splits[0]); |
| } catch (NumberFormatException e) { |
| throw new RuntimeException(new ParseException( |
| "Major part of an OSGi version should be an integer", 0)); |
| } |
| try { |
| minor = splits.length >= 2 ? Integer.parseInt(splits[1]) : 0; |
| } catch (NumberFormatException e) { |
| throw new RuntimeException(new ParseException( |
| "Minor part of an OSGi version should be an integer", 0)); |
| } |
| try { |
| patch = splits.length >= 3 ? Integer.parseInt(splits[2]) : 0; |
| } catch (NumberFormatException e) { |
| throw new RuntimeException(new ParseException( |
| "Patch part of an OSGi version should be an integer", 0)); |
| } |
| qualifier = splits.length == 4 ? splits[3] : null; |
| split = true; |
| } |
| } |
| } |
| |
| private void ensureToString() { |
| if (!toString) { |
| synchronized (this) { |
| if (toString) { |
| return; |
| } |
| ensureSplit(); |
| version = major + "." + minor + "." + patch |
| + (qualifier == null ? "" : "." + qualifier); |
| toString = true; |
| } |
| } |
| } |
| |
| public String toString() { |
| ensureToString(); |
| return version; |
| } |
| |
| public int hashCode() { |
| ensureSplit(); |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + major; |
| result = prime * result + minor; |
| result = prime * result + patch; |
| result = prime * result + ((qualifier == null) ? 0 : qualifier.hashCode()); |
| return result; |
| } |
| |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null || !(obj instanceof Version)) { |
| return false; |
| } |
| Version other = (Version) obj; |
| ensureSplit(); |
| other.ensureSplit(); |
| return major == other.major && minor == other.minor && patch == other.patch |
| && (qualifier == null ? other.qualifier == null : qualifier.equals(other.qualifier)); |
| } |
| |
| public Version withNudgedPatch() { |
| ensureSplit(); |
| return new Version(major, minor, patch + 1, null); |
| } |
| |
| public Version withoutQualifier() { |
| ensureSplit(); |
| return new Version(major, minor, patch, null); |
| } |
| |
| public String qualifier() { |
| ensureSplit(); |
| return (qualifier == null) ? "" : qualifier; |
| } |
| |
| public int compareUnqualified(Version other) { |
| ensureSplit(); |
| other.ensureSplit(); |
| int diff = major - other.major; |
| if (diff != 0) { |
| return diff; |
| } |
| diff = minor - other.minor; |
| if (diff != 0) { |
| return diff; |
| } |
| diff = patch - other.patch; |
| if (diff != 0) { |
| return diff; |
| } |
| return 0; |
| } |
| |
| public int compareTo(Version other) { |
| ensureSplit(); |
| other.ensureSplit(); |
| int diff = compareUnqualified(other); |
| if (diff != 0) { |
| return diff; |
| } |
| if (qualifier == null) { |
| return other.qualifier != null ? -1 : 0; |
| } |
| if (other.qualifier == null) { |
| return 1; |
| } |
| return qualifier.compareTo(other.qualifier); |
| } |
| |
| } |