All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.oss.driver.api.core.Version Maven / Gradle / Ivy

/*
 * Copyright DataStax, 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 com.datastax.oss.driver.api.core;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.jcip.annotations.Immutable;

/**
 * A structured version number.
 *
 * 

It is in the form X.Y.Z, with optional pre-release labels and build metadata. * *

Version numbers compare the usual way, the major number (X) is compared first, then the minor * one (Y) and then the patch level one (Z). Lastly, versions with pre-release sorts before the * versions that don't have one, and labels are sorted alphabetically if necessary. Build metadata * are ignored for sorting versions. */ @Immutable public class Version implements Comparable, Serializable { private static final long serialVersionUID = 1; private static final String VERSION_REGEXP = "(\\d+)\\.(\\d+)(\\.\\d+)?(\\.\\d+)?([~\\-]\\w[.\\w]*(?:-\\w[.\\w]*)*)?(\\+[.\\w]+)?"; private static final Pattern pattern = Pattern.compile(VERSION_REGEXP); @NonNull public static final Version V2_1_0 = Objects.requireNonNull(parse("2.1.0")); @NonNull public static final Version V2_2_0 = Objects.requireNonNull(parse("2.2.0")); @NonNull public static final Version V3_0_0 = Objects.requireNonNull(parse("3.0.0")); @NonNull public static final Version V4_0_0 = Objects.requireNonNull(parse("4.0.0")); @NonNull public static final Version V5_0_0 = Objects.requireNonNull(parse("5.0.0")); @NonNull public static final Version V6_7_0 = Objects.requireNonNull(parse("6.7.0")); @NonNull public static final Version V6_8_0 = Objects.requireNonNull(parse("6.8.0")); private final int major; private final int minor; private final int patch; private final int dsePatch; private final String[] preReleases; private final String build; private Version( int major, int minor, int patch, int dsePatch, String[] preReleases, String build) { this.major = major; this.minor = minor; this.patch = patch; this.dsePatch = dsePatch; this.preReleases = preReleases; this.build = build; } /** * Parses a version from a string. * *

The version string should have primarily the form X.Y.Z to which can be appended one or more * pre-release label after dashes (2.0.1-beta1, 2.1.4-rc1-SNAPSHOT) and an optional build label * (2.1.0-beta1+a20ba.sha). Out of convenience, the "patch" version number, Z, can be omitted, in * which case it is assumed to be 0. * * @param version the string to parse. * @return the parsed version number. * @throws IllegalArgumentException if the provided string does not represent a valid version. */ @Nullable public static Version parse(@Nullable String version) { if (version == null) { return null; } Matcher matcher = pattern.matcher(version); if (!matcher.matches()) { throw new IllegalArgumentException("Invalid version number: " + version); } try { int major = Integer.parseInt(matcher.group(1)); int minor = Integer.parseInt(matcher.group(2)); String pa = matcher.group(3); int patch = pa == null || pa.isEmpty() ? 0 : Integer.parseInt( pa.substring(1)); // dropping the initial '.' since it's included this time String dse = matcher.group(4); int dsePatch = dse == null || dse.isEmpty() ? -1 : Integer.parseInt( dse.substring(1)); // dropping the initial '.' since it's included this time String pr = matcher.group(5); String[] preReleases = pr == null || pr.isEmpty() ? null : pr.substring(1) .split("-"); // drop initial '-' or '~' then split on the remaining ones String bl = matcher.group(6); String build = bl == null || bl.isEmpty() ? null : bl.substring(1); // drop the initial '+' return new Version(major, minor, patch, dsePatch, preReleases, build); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid version number: " + version); } } /** * The major version number. * * @return the major version number, i.e. X in X.Y.Z. */ public int getMajor() { return major; } /** * The minor version number. * * @return the minor version number, i.e. Y in X.Y.Z. */ public int getMinor() { return minor; } /** * The patch version number. * * @return the patch version number, i.e. Z in X.Y.Z. */ public int getPatch() { return patch; } /** * The DSE patch version number (will only be present for version of Cassandra in DSE). * *

DataStax Entreprise (DSE) adds a fourth number to the version number to track potential hot * fixes and/or DSE specific patches that may have been applied to the Cassandra version. In that * case, this method returns that fourth number. * * @return the DSE patch version number, i.e. D in X.Y.Z.D, or -1 if the version number is not * from DSE. */ public int getDSEPatch() { return dsePatch; } /** * The pre-release labels if relevant, i.e. label1 and label2 in X.Y.Z-label1-lable2. * * @return the pre-release labels. The return list will be {@code null} if the version number * doesn't have any. */ public List getPreReleaseLabels() { return preReleases == null ? null : Collections.unmodifiableList(Arrays.asList(preReleases)); } /** * The build label if there is one. * * @return the build label or {@code null} if the version number doesn't have one. */ public String getBuildLabel() { return build; } /** * The next stable version, i.e. the version stripped of its pre-release labels and build * metadata. * *

This is mostly used during our development stage, where we test the driver against * pre-release versions of Cassandra like 2.1.0-rc7-SNAPSHOT, but need to compare to the stable * version 2.1.0 when testing for native protocol compatibility, etc. * * @return the next stable version. */ public Version nextStable() { return new Version(major, minor, patch, dsePatch, null, null); } @Override public int compareTo(@NonNull Version other) { if (major < other.major) { return -1; } if (major > other.major) { return 1; } if (minor < other.minor) { return -1; } if (minor > other.minor) { return 1; } if (patch < other.patch) { return -1; } if (patch > other.patch) { return 1; } if (dsePatch < 0) { if (other.dsePatch >= 0) { return -1; } } else { if (other.dsePatch < 0) { return 1; } // Both are >= 0 if (dsePatch < other.dsePatch) { return -1; } if (dsePatch > other.dsePatch) { return 1; } } if (preReleases == null) { return other.preReleases == null ? 0 : 1; } if (other.preReleases == null) { return -1; } for (int i = 0; i < Math.min(preReleases.length, other.preReleases.length); i++) { int cmp = preReleases[i].compareTo(other.preReleases[i]); if (cmp != 0) { return cmp; } } return Integer.compare(preReleases.length, other.preReleases.length); } @Override public boolean equals(Object other) { if (other == this) { return true; } else if (other instanceof Version) { Version that = (Version) other; return this.major == that.major && this.minor == that.minor && this.patch == that.patch && this.dsePatch == that.dsePatch && (this.preReleases == null ? that.preReleases == null : Arrays.equals(this.preReleases, that.preReleases)) && Objects.equals(this.build, that.build); } else { return false; } } @Override public int hashCode() { return Objects.hash(major, minor, patch, dsePatch, Arrays.hashCode(preReleases), build); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(major).append('.').append(minor).append('.').append(patch); if (dsePatch >= 0) { sb.append('.').append(dsePatch); } if (preReleases != null) { for (String preRelease : preReleases) { sb.append('-').append(preRelease); } } if (build != null) { sb.append('+').append(build); } return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy