/* * sulky-modules - several general-purpose modules. * Copyright (C) 2007-2015 Joern Huxhorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright 2007-2015 Joern Huxhorn * * 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 de.huxhorn.sulky.version; import java.io.Serializable; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * This class handles parsing and comparison of * <a href="http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html">Java version numbers</a>. * * The static JVM attribute contains the version retrieved from the "java.version" system property. * If parsing that property fails (because security prevents access or the content is invalid) then * "java.specification.version" is used as a fallback. If parsing that property also fails (for similar reasons) * then the JVM attribute is initialized with MIN_VALUE, i.e. new JavaVersion(0,0,0,0,"!"). * * This class does not handle the proposed version string suggested in http://openjdk.java.net/jeps/223 */ public final class YeOldeJavaVersion extends JavaVersion implements Comparable<YeOldeJavaVersion>, Serializable { private static final long serialVersionUID = 7704440212288750937L; private static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)(\\.(\\d+)([_](\\d+))?)?(-(.+))?"); private static final int HUGE_GROUP_INDEX = 1; private static final int MAJOR_GROUP_INDEX = 2; private static final int MINOR_GROUP_INDEX = 4; private static final int PATCH_GROUP_INDEX = 6; private static final int IDENTIFIER_GROUP_INDEX = 8; /** * Smallest possible version is JavaVersion(0,0,0,0,"!"). */ public static final YeOldeJavaVersion MIN_VALUE = new YeOldeJavaVersion(0,0,0,0,"!"); /** * Parses a Java version and returns the corresponding JavaVersion instance. * * @param versionString the String to be parsed * @return the JavaVersion corresponding to the given versionString * @throws java.lang.NullPointerException if versionString is null. * @throws java.lang.IllegalArgumentException if versionString is invalid. */ public static YeOldeJavaVersion parse(String versionString) { if(versionString == null) { throw new NullPointerException("versionString must not be null!"); } Matcher matcher = VERSION_PATTERN.matcher(versionString); if(!matcher.matches()) { throw new IllegalArgumentException("versionString '"+versionString+"' is invalid."); } /* for (int i=0; i<=matcher.groupCount(); i++) { System.out.println("Index #"+i+": "+matcher.group(i)); } */ int huge = Integer.parseInt(matcher.group(HUGE_GROUP_INDEX)); int major = Integer.parseInt(matcher.group(MAJOR_GROUP_INDEX)); int minor = 0; int patch = 0; String minorString = matcher.group(MINOR_GROUP_INDEX); if(minorString != null) { minor = Integer.parseInt(minorString); } String patchString = matcher.group(PATCH_GROUP_INDEX); if(patchString != null) { patch = Integer.parseInt(patchString); } String identifier = matcher.group(IDENTIFIER_GROUP_INDEX); return new YeOldeJavaVersion(huge, major, minor, patch, identifier); } private final int huge; private final int major; private final int minor; private final int patch; private final String preReleaseIdentifier; /** * Creates a JavaVersion. * * @param huge the "huge" part of the version. * @param major the "major" part of the version. * @throws IllegalArgumentException if huge or major are negative. */ public YeOldeJavaVersion(int huge, int major) { this(huge, major, 0, 0, null); } /** * Creates a JavaVersion. * * @param huge the "huge" part of the version. * @param major the "major" part of the version. * @param minor the "minor" part of the version. * @throws IllegalArgumentException if huge, major or minor are negative. */ public YeOldeJavaVersion(int huge, int major, int minor) { this(huge, major, minor, 0, null); } /** * Creates a JavaVersion. * * @param huge the "huge" part of the version. * @param major the "major" part of the version. * @param minor the "minor" part of the version. * @param patch the "patch" part of the version. * @throws IllegalArgumentException if huge, major, minor or patch are negative. */ public YeOldeJavaVersion(int huge, int major, int minor, int patch) { this(huge, major, minor, patch, null); } /** * Creates a JavaVersion. * * @param huge the "huge" part of the version. * @param major the "major" part of the version. * @param minor the "minor" part of the version. * @param patch the "patch" part of the version. * @param preReleaseIdentifier the "preReleaseIdentifier" part of the version. * @throws IllegalArgumentException if huge, major, minor or patch are negative or if preReleaseIdentifier is invalid. */ public YeOldeJavaVersion(int huge, int major, int minor, int patch, String preReleaseIdentifier) { if(huge < 0) { throw new IllegalArgumentException("huge must not be negative!"); } if(major < 0) { throw new IllegalArgumentException("major must not be negative!"); } if(minor < 0) { throw new IllegalArgumentException("minor must not be negative!"); } if(patch < 0) { throw new IllegalArgumentException("patch must not be negative!"); } if(preReleaseIdentifier != null) { preReleaseIdentifier = preReleaseIdentifier.trim(); if(preReleaseIdentifier.length() == 0) { throw new IllegalArgumentException("preReleaseIdentifier must not be empty string!"); } if(preReleaseIdentifier.indexOf('*') != -1) { throw new IllegalArgumentException("preReleaseIdentifier must not contain the '*' character!"); } if(preReleaseIdentifier.indexOf('+') != -1) { throw new IllegalArgumentException("preReleaseIdentifier must not contain the '+' character!"); } } this.huge = huge; this.major = major; this.minor = minor; this.patch = patch; this.preReleaseIdentifier = preReleaseIdentifier; } /** * Returns the "huge" part of this version, e.g. 1 in case of 1.8.0_25. * * @return the "huge" part of this version. */ public int getHuge() { return huge; } /** * Returns the "major" part of this version, e.g. 8 in case of 1.8.0_25. * * @return the "major" part of this version. */ public int getMajor() { return major; } /** * Returns the "minor" part of this version, e.g. 0 in case of 1.8.0_25. * * @return the "minor" part of this version. */ public int getMinor() { return minor; } /** * Returns the "patch" (or update) part of this version, e.g. 25 in case of 1.8.0_25. * * @return the "patch" (or update) part of this version. */ public int getPatch() { return patch; } /** * Returns the "preReleaseIdentifier" part of this version, e.g. "ea" in case of 1.8.0_25-ea. * * @return the "preReleaseIdentifier" part of this version. */ public String getPreReleaseIdentifier() { return preReleaseIdentifier; } /** * Returns the full version string of this version, e.g. "1.8.0_25-ea" in case of YeOldeJavaVersion(1,8,0,25,"ea"). * * @return the full version string of this version. */ public String toVersionString() { StringBuilder result = new StringBuilder(); result.append(huge).append('.').append(major).append('.').append(minor); if(patch != 0) { result.append('_'); if(patch < 10) { result.append('0'); } result.append(patch); } if(preReleaseIdentifier != null) { result.append('-'); result.append(preReleaseIdentifier); } return result.toString(); } /** * Returns the short version string of this version, e.g. "1.8" in case of YeOldeJavaVersion(1,8,0,25,"ea"). * * @return the short version string of this version. */ @Override public String toShortVersionString() { return ""+huge+"."+major; } @Override public YeOldeJavaVersion withoutPreReleaseIdentifier() { if(preReleaseIdentifier == null) { return this; } return new YeOldeJavaVersion(huge, major, minor, patch); } @SuppressWarnings("RedundantIfStatement") @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; YeOldeJavaVersion that = (YeOldeJavaVersion) o; if (huge != that.huge) return false; if (major != that.major) return false; if (minor != that.minor) return false; if (patch != that.patch) return false; if (preReleaseIdentifier != null ? !preReleaseIdentifier.equals(that.preReleaseIdentifier) : that.preReleaseIdentifier != null) return false; return true; } @Override public int hashCode() { int result = huge; result = 31 * result + major; result = 31 * result + minor; result = 31 * result + patch; result = 31 * result + (preReleaseIdentifier != null ? preReleaseIdentifier.hashCode() : 0); return result; } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append("YeOldeJavaVersion{huge=").append(huge).append(", major=").append(major); result.append(", minor=").append(minor).append(", patch=").append(patch); result.append(", preReleaseIdentifier="); if(preReleaseIdentifier == null) { result.append("null"); } else { result.append('"').append(preReleaseIdentifier).append('"'); } result.append('}'); return result.toString(); } @SuppressWarnings("NullableProblems") @Override public int compareTo(YeOldeJavaVersion other) { if(other == null) { throw new NullPointerException("other must not be null!"); } if(huge < other.huge) { return -1; } if(huge > other.huge) { return 1; } 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(preReleaseIdentifier == null) { // this is a release if(other.preReleaseIdentifier != null) { // other is rc/ea, i.e. non-GA/non-FCS => this is greater. return 1; } return 0; } // this is rc/ea, i.e. non-GA/non-FCS. if(other.preReleaseIdentifier == null) { // other is a release => other is greater. return -1; } // both this and other are rc/ea, i.e. non-GA/non-FCS. // the code below is only an approximation. return preReleaseIdentifier.compareTo(other.preReleaseIdentifier); } }