Version.java |
1 /** 2 * Distribution License: 3 * JSword is free software; you can redistribute it and/or modify it under 4 * the terms of the GNU Lesser General Public License, version 2.1 or later 5 * as published by the Free Software Foundation. This program is distributed 6 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even 7 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 8 * See the GNU Lesser General Public License for more details. 9 * 10 * The License is available on the internet at: 11 * http://www.gnu.org/copyleft/lgpl.html 12 * or by writing to: 13 * Free Software Foundation, Inc. 14 * 59 Temple Place - Suite 330 15 * Boston, MA 02111-1307, USA 16 * 17 * © CrossWire Bible Society, 2011 - 2016 18 * 19 */ 20 package org.crosswire.common.util; 21 22 import java.util.regex.Matcher; 23 import java.util.regex.Pattern; 24 25 /** 26 * Version is an immutable representation of dotted "number" consisting of 1 to 4 parts. 27 * 28 * <p> 29 * Here is the grammar for version strings: 30 * </p> 31 * <pre> 32 * version ::= major('.'minor('.'micro('.'nano)?)?)? 33 * major ::= [0-9]+ 34 * minor ::= [0-9]+ 35 * micro ::= [0-9]+ 36 * nano ::= [0-9]+ 37 * </pre> 38 * 39 * @see gnu.lgpl.License The GNU Lesser General Public License for details. 40 * @author DM Smith 41 */ 42 public class Version implements Comparable<Version> { 43 public static final Pattern VERSION_PATTERN = Pattern.compile("^(\\d+)(?:.(\\d+))?(?:.(\\d+))?(?:.(\\d+))?$"); 44 45 /** 46 * Created a version identifier from the specified string. 47 * 48 * @param version String representation of the version identifier. 49 * @throws IllegalArgumentException If <code>version</code> is improperly 50 * formatted. 51 */ 52 public Version(String version) { 53 if (version == null) { 54 throw new IllegalArgumentException("Null version not allowed."); 55 } 56 this.original = version; 57 this.parts = new int[] { -1, -1, -1, -1 }; 58 Matcher matcher = VERSION_PATTERN.matcher(this.original); 59 if (matcher.matches()) { 60 int count = matcher.groupCount(); 61 for (int i = 1; i <= count; i++) { 62 String part = matcher.group(i); 63 if (part == null) { 64 break; 65 } 66 parts[i - 1] = Integer.parseInt(part); 67 } 68 } else { 69 throw new IllegalArgumentException("invalid: " + version); 70 } 71 } 72 73 /** 74 * Returns the original string representation of this version identifier. 75 * 76 * @return The original string representation of this version identifier. 77 */ 78 @Override 79 public String toString() { 80 return original; 81 } 82 83 @Override 84 public int hashCode() { 85 return original.hashCode(); 86 } 87 88 /** 89 * Compares this <code>Version</code> object to another object. 90 * 91 * <p> 92 * A version is considered to be equal to another version if all the 93 * parts are equal.</p> 94 * 95 * @param object The <code>Version</code> object to be compared. 96 * @return true if the two objects are equal. 97 */ 98 @Override 99 public boolean equals(Object object) { 100 if (!(object instanceof Version)) { 101 return false; 102 } 103 104 Version that = (Version) object; 105 if (that == this) { 106 return true; 107 } 108 109 for (int i = 0; i < parts.length; i++) { 110 if (parts[i] != that.parts[i]) { 111 return false; 112 } 113 } 114 115 return true; 116 } 117 118 /** 119 * Compares this <code>Version</code> object to another object. 120 * 121 * <p> 122 * The comparison considers each of the parts (major, minor, micro, nano) in turn, 123 * comparing like with like. At any point the comparison is not equal, a result is 124 * known. 125 * </p> 126 * 127 * @param object The <code>Version</code> object to be compared. 128 * @return A negative integer, zero, or a positive integer if this object is 129 * less than, equal to, or greater than the specified 130 * <code>Version</code> object. 131 * @throws ClassCastException If the specified object is not a <code>Version</code>. 132 */ 133 public int compareTo(Version object) { 134 if (object == this) { 135 return 0; 136 } 137 138 for (int i = 0; i < parts.length; i++) { 139 int result = parts[i] - object.parts[i]; 140 if (result != 0) { 141 return result; 142 } 143 } 144 145 return 0; 146 } 147 148 private final String original; 149 private final int[] parts; 150 151 } 152