001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2015 ForgeRock AS. 015 */ 016 017package org.forgerock.http.routing; 018 019import java.util.Objects; 020import java.util.regex.Matcher; 021import java.util.regex.Pattern; 022 023/** 024 * Represents some version in the form majorNumber.minorNumber, 025 * for instance 2.4. 026 */ 027public final class Version implements Comparable<Version> { 028 029 private static final Version[] DOT_ZERO_CACHE = new Version[10]; 030 private static final Pattern REGEX = Pattern.compile("(\\d+)(\\.(\\d+))?"); 031 032 static { 033 for (int i = 0; i < DOT_ZERO_CACHE.length; i++) { 034 DOT_ZERO_CACHE[i] = new Version(i, 0); 035 } 036 } 037 038 private final int major; 039 private final int minor; 040 041 /** 042 * Creates a new version using the provided version information. 043 * 044 * @param major 045 * Major version number. 046 * @param minor 047 * Minor version number. 048 * 049 * @return The version. 050 */ 051 public static Version version(final int major, final int minor) { 052 if (minor == 0 && major >= 0 && major < DOT_ZERO_CACHE.length) { 053 return DOT_ZERO_CACHE[major]; 054 } 055 return new Version(major, minor); 056 } 057 058 /** 059 * Creates a new version using the provided version information and a minor. 060 * 061 * @param major 062 * Major version number. 063 * 064 * @return The version. 065 */ 066 public static Version version(final int major) { 067 return version(major, 0); 068 } 069 070 private Version(final int major, final int minor) { 071 this.major = major; 072 this.minor = minor; 073 } 074 075 /** 076 * Parses the string argument as a version. The string must be one of the 077 * following forms: 078 * <pre> 079 * major 080 * major.minor 081 * </pre> 082 * 083 * @param s 084 * The non-{@code null} string to be parsed as a version. 085 * 086 * @return The parsed version. 087 * 088 * @throws IllegalArgumentException 089 * If the string does not contain a parsable version. 090 */ 091 public static Version version(final String s) { 092 Matcher matcher = REGEX.matcher(s); 093 if (matcher.matches()) { 094 if (matcher.group(3) == null) { 095 return version(Integer.parseInt(matcher.group(1))); 096 } else { 097 return version(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(3))); 098 } 099 } else { 100 throw new IllegalArgumentException("Invalid version string " + s); 101 } 102 } 103 104 /** 105 * Returns the major version number. 106 * 107 * @return The major version number. 108 */ 109 public int getMajor() { 110 return major; 111 } 112 113 /** 114 * Returns the minor version number. 115 * 116 * @return The minor version number. 117 */ 118 public int getMinor() { 119 return minor; 120 } 121 122 @Override 123 public boolean equals(Object o) { 124 if (this == o) { 125 return true; 126 } 127 if (o == null || getClass() != o.getClass()) { 128 return false; 129 } 130 Version version = (Version) o; 131 return Objects.equals(major, version.major) 132 && Objects.equals(minor, version.minor); 133 } 134 135 @Override 136 public int hashCode() { 137 return Objects.hash(major, minor); 138 } 139 140 @Override 141 public int compareTo(final Version that) { 142 if (major != that.major) { 143 return major - that.major; 144 } 145 if (minor != that.minor) { 146 return minor - that.minor; 147 } 148 return 0; 149 } 150 151 @Override 152 public String toString() { 153 return major + "." + minor; 154 } 155 156 /** 157 * Returns {@code false} if: 158 * <ul> 159 * <li> 160 * the MAJOR version numbers are not the same. 161 * </li> 162 * <li> 163 * the MAJOR version numbers are the same but {@code this} MINOR 164 * version number is LOWER than {@code that} MINOR version number. 165 * </li> 166 * </ul> 167 * 168 * <p>i.e. this version number - "2.0", that version number - "2.1" WILL 169 * NOT match, but this version number - "2.4", that version number - "2.1" 170 * WILL match. In other words, verifies ascending compatibility.</p> 171 * 172 * @param that The {@code Version} to match against. 173 * @return {@code true} if both MAJOR version numbers are the same and if 174 * {@code this} MINOR version number is HIGHER than {@code that} MINOR 175 * version number. 176 */ 177 public boolean isCompatibleWith(Version that) { 178 return that != null && this.major == that.major && this.minor >= that.minor; 179 } 180}