/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui.tools; import java.util.Locale; /** * Contains information about the different parts of a version number. * * @author Ingo Mierswa, Marcel Michel */ public class VersionNumber implements Comparable<VersionNumber> { public class VersionNumberExcpetion extends RuntimeException { private static final long serialVersionUID = 1L; public VersionNumberExcpetion(String message) { super(message); } } private static final String CLASSIFIER_TAG = "-"; private static final String ALPHA_TAG = "alpha"; private static final String BETA_TAG = "beta"; private static final String RELEASE_CANDIDATE = "rc"; private static final String SNAPSHOT = "snapshot"; private int majorNumber; private int minorNumber; private int patchLevel; private final String classifier; /** * Constructs a new VersionNumber object with the given versionString. The versionString should * use the format major.minor.patchlevel-classifier. Examples: 6.0 or 6.0.005-SNAPSHOT. Throws a * {@link VersionNumberExcpetion} if the given versionString is malformed. */ public VersionNumber(String versionString) { String version = versionString.toLowerCase().trim(); String[] numbers; int classifierIndex = version.indexOf(CLASSIFIER_TAG); if (classifierIndex >= 0) { numbers = version.substring(0, classifierIndex).split("\\."); } else { numbers = version.split("\\."); } // extract major, minor and patch level version if (numbers.length > 0) { try { majorNumber = Integer.parseInt(numbers[0]); } catch (NumberFormatException e) { throw new VersionNumberExcpetion("Malformed major version!"); } } else { throw new VersionNumberExcpetion("No major version given!"); } if (numbers.length > 1) { try { minorNumber = Integer.parseInt(numbers[1]); } catch (NumberFormatException e) { throw new VersionNumberExcpetion("Malformed minor version!"); } } else { minorNumber = 0; } if (numbers.length > 2) { try { patchLevel = Integer.parseInt(numbers[2]); } catch (NumberFormatException e) { throw new VersionNumberExcpetion("Malformed patch level!"); } } else { patchLevel = 0; } if (classifierIndex >= 0) { classifier = CLASSIFIER_TAG + version.substring(classifierIndex + 1, version.length()); } else { classifier = null; } } /** * Constructs a new VersionNumber object with the given major and minor version. */ public VersionNumber(int majorNumber, int minorNumber) { this(majorNumber, minorNumber, 0, null); } /** * Constructs a new VersionNumber object with the given major, minor version and patch level. */ public VersionNumber(int majorNumber, int minorNumber, int patchLevel) { this(majorNumber, minorNumber, patchLevel, null); } /** * Constructs a new VersionNumber object with the given major, minor version, patch level and * classifier. Note: A {@link #CLASSIFIER_TAG} will be added as prefix to the given classifier. */ public VersionNumber(int majorNumber, int minorNumber, int patchLevel, String classifier) { this.majorNumber = majorNumber; this.minorNumber = minorNumber; this.patchLevel = patchLevel; if (classifier != null) { this.classifier = CLASSIFIER_TAG + classifier; } else { this.classifier = null; } } /** * @deprecated Use {@link #VersionNumber(int, int, int, String)} instead. */ @Deprecated public VersionNumber(int majorNumber, int minorNumber, int patchLevel, boolean alpha, int alphaNumber, boolean beta, int betaNumber) { this.majorNumber = majorNumber; this.minorNumber = minorNumber; this.patchLevel = patchLevel; if (alpha) { this.classifier = CLASSIFIER_TAG + ALPHA_TAG + (alphaNumber >= 2 ? alphaNumber : ""); } else if (beta) { this.classifier = CLASSIFIER_TAG + BETA_TAG + (betaNumber >= 2 ? betaNumber : ""); } else { this.classifier = null; } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (classifier == null ? 0 : classifier.hashCode()); result = prime * result + majorNumber; result = prime * result + minorNumber; result = prime * result + patchLevel; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } VersionNumber other = (VersionNumber) obj; if (classifier == null) { if (other.classifier != null) { return false; } } else if (!classifier.equals(other.classifier)) { return false; } if (majorNumber != other.majorNumber) { return false; } if (minorNumber != other.minorNumber) { return false; } if (patchLevel != other.patchLevel) { return false; } return true; } /** * Returns if this number is at least as high as the given arguments. */ public boolean isAtLeast(int major, int minor, int buildNumber) { return this.compareTo(new VersionNumber(major, minor, buildNumber)) >= 0; } /** * Returns if this number is at least as high as the given version number object. */ public boolean isAtLeast(VersionNumber other) { return this.compareTo(other) >= 0; } /** * Returns <code>true</code> if this number is at most as high as the given arguments. */ public boolean isAtMost(int major, int minor, int buildNumber) { return this.compareTo(new VersionNumber(major, minor, buildNumber)) <= 0; } /** * Returns <code>true</code> if this VersionNumber is at most as high as the given argument. */ public boolean isAtMost(VersionNumber other) { return this.compareTo(other) <= 0; } /** * Returns <code>true</code> if this VersionNumber is above (greater than) the given argument. */ public boolean isAbove(VersionNumber other) { return !isAtMost(other); } @Override public int compareTo(VersionNumber o) { int index = Double.compare(this.majorNumber, o.majorNumber); if (index != 0) { return index; } else { index = Double.compare(this.minorNumber, o.minorNumber); if (index != 0) { return index; } else { index = Double.compare(this.patchLevel, o.patchLevel); if (index != 0) { return index; } // prefer release versions over development builds return Boolean.compare(!isDevelopmentBuild(), !o.isDevelopmentBuild()); } } } @Override public String toString() { return majorNumber + "." + minorNumber + "." + "000".substring((patchLevel + "").length()) + patchLevel + (classifier != null ? classifier.toUpperCase(Locale.ENGLISH) : ""); } /** * Returns the RapidMiner version in the format major.minor.patchlevel-classifier, with 3 digits * for patchlevel. Example: 6.0.005-SNAPSHOT */ public String getLongVersion() { return toString(); } /** * Return the RapidMiner short version in the format major.minor. Example: 6.0 */ public String getShortVersion() { return majorNumber + "." + minorNumber; } /** * Return the RapidMiner major version. */ public int getMajorNumber() { return majorNumber; } /** * Return the RapidMiner minor version. */ public int getMinorNumber() { return minorNumber; } /** * Return the RapidMiner path level. */ public int getPatchLevel() { return patchLevel; } /** * @return <code>true</code> if the current version is a development build (i.e. it has a * classifier named SNAPSHOT or ALPHA or BETA or RC). */ public final boolean isDevelopmentBuild() { return isSnapshot() || isPreview(ALPHA_TAG) || isPreview(BETA_TAG) || isPreview(RELEASE_CANDIDATE); } /** * @return {@code true} if the current version is a snapshot build (exactly if it has a * classifier named SNAPSHOT). */ public final boolean isSnapshot() { return classifier != null && classifier.equalsIgnoreCase(CLASSIFIER_TAG + SNAPSHOT); } private boolean isPreview(String tagName) { if (classifier != null) { String lowerCase = classifier.toLowerCase(Locale.ENGLISH); if (lowerCase.contains(CLASSIFIER_TAG)) { String suffix = lowerCase.substring(lowerCase.lastIndexOf(CLASSIFIER_TAG) + 1); return suffix.startsWith(tagName); } else { return false; } } return false; } }