| 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