1 /* 2 Copyright (C) 2000 - 2007 Grid Systems, S.A. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License, version 2, as 6 published by the Free Software Foundation. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program; if not, write to the Free Software 15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 package com.gridsystems.utils; 18 19 import java.util.ArrayList; 20 21 import org.apache.commons.logging.Log; 22 import org.apache.commons.logging.LogFactory; 23 24 /** 25 * General Utilities. 26 * 27 * @author nporcel 28 * @version 1.0 29 */ 30 public class Version implements Comparable<Version> { 31 32 /** 33 * List of values. 34 */ 35 private ArrayList<Integer> values = new ArrayList<Integer>(); 36 37 /** 38 * Logger for this class. 39 */ 40 private static Log log = LogFactory.getLog(Version.class); 41 42 /** 43 * Constructor. 44 * 45 * @param version the String from which the version information is obtained. 46 * It is interpreted as an arbitrarily long series of integers separated by 47 * non-digit characters. 48 */ 49 public Version(String version) { 50 if (version == null) { 51 version = ""; 52 } 53 final int v10 = 10; 54 int length = version.length(); 55 int value = 0; 56 boolean valueSet = false; 57 for (int i = 0; i < length; i++) { 58 char versionChar = version.charAt(i); 59 if (Character.isDigit(versionChar)) { 60 value = value * v10 + Integer.parseInt(Character.toString(versionChar)); 61 valueSet = true; 62 } else { 63 if (valueSet) { 64 this.values.add(new Integer(value)); 65 valueSet = false; 66 value = 0; 67 } 68 } 69 } 70 if (value != 0) { 71 this.values.add(new Integer(value)); 72 } 73 } 74 75 /** 76 * Creates an instance. 77 * 78 * @param values version numbers (major, minor, release, build, etc.) 79 */ 80 public Version(int... values) { 81 for (int v : values) { 82 if (v < 0) { 83 break; 84 } else { 85 this.values.add(v); 86 } 87 } 88 } 89 90 /** 91 * Gets a slice of the version numbers. 92 * 93 * @param i an int with the position (ranging from 0 to 94 * <code>this.getSize() - 1</code> of the part of the version number wanted; 95 * 0 means the major version number; 1 the minor version number and so on. 96 * 97 * @return an int with the value of that part of the version number or, if 98 * the index is out of the valid range, 0. 99 */ 100 public int getValue(int i) { 101 if ((i >= 0) && (i < this.values.size())) { 102 return ((Integer) this.values.get(i)).intValue(); 103 } 104 return 0; 105 } 106 107 /** 108 * Get the size (number of elements) of the version. 109 * 110 * @return an int with the size (number of elements) of the version. 111 */ 112 public int getSize() { 113 return this.values.size(); 114 } 115 116 /** 117 * Compares this object to another JavaVersion. 118 * 119 * Compares this object to another JavaVersion. Objects related to older 120 * versions are minor that objects related to newer versions. 121 * 122 * @param v the instance to compare to 123 * @return an int that is -1 if <code>this</code> is minor than 124 * <code>obj</code>, 0 if both objects represent the same version and 1 125 * otherwise. 126 */ 127 public int compareTo(Version v) { 128 129 int sizeA = v.getSize(); 130 int sizeB = this.getSize(); 131 132 if (sizeA < sizeB) { 133 sizeA = sizeB; 134 } 135 136 for (int i = 0; i < sizeA; i++) { 137 int valueThis = this.getValue(i); 138 int valueObj = v.getValue(i); 139 if (valueThis < valueObj) { 140 return -1; 141 } else { 142 if (valueThis > valueObj) { 143 return 1; 144 } 145 } 146 } 147 return 0; 148 } 149 150 /** 151 * {@inheritDoc} 152 */ 153 @Override public boolean equals(Object obj) { 154 if (obj == null) { 155 return false; 156 } else if (obj instanceof Version) { 157 return this.compareTo((Version)obj) == 0; 158 } else { 159 return false; 160 } 161 } 162 163 /** 164 * {@inheritDoc} 165 */ 166 @Override public int hashCode() { 167 final int factor = 37; 168 final int initial = 17; 169 170 int hash = initial; 171 for (int v : this.values) { 172 hash = hash * factor + v; 173 } 174 return hash; 175 } 176 177 /** 178 * Gets the major version. 179 * 180 * @return an int with the major number of the version. 181 * 182 * @deprecated Use #getValue(int) instead. 183 */ 184 public int getMajorVersion() { 185 return this.getValue(0); 186 } 187 188 /** 189 * Gets the minor version. 190 * 191 * @return an int with the the minor number of the version. 192 * 193 * @deprecated Use #getValue(int) instead. 194 */ 195 public int getMinorVersion() { 196 return this.getValue(1); 197 } 198 199 /** 200 * Gets the release version. 201 * 202 * @return an int with the release number of the minor version. 203 * 204 * @deprecated Use #getValue(int) instead. 205 */ 206 public int getRelease() { 207 return this.getValue(2); 208 } 209 210 211 /** 212 * Returns a String representation of this object. 213 * 214 * @return a String representation of this version number as a series of 215 * integers separated with dots ".". 216 */ 217 @Override public String toString() { 218 219 StringBuffer returnValue = new StringBuffer(); 220 221 int size = this.getSize(); 222 for (int i = 0; i < size; i++) { 223 if (i != 0) { 224 returnValue.append("."); 225 } 226 returnValue.append(((Integer) this.values.get(i)).toString()); 227 } 228 return returnValue.toString(); 229 } 230 231 /** 232 * Gets the representation as a double of a version String. 233 * 234 * Gets the representation as a double of a version String. The String is 235 * parsed in the same way it is when invoking #Version(String). The return 236 * value is in the form of {d0}.{d1}{d2}{d3}..., being d0 the value of the 237 * first part of the version number and d1, d2 and remainders are two-digits 238 * representation of the other parts of the version number. If any of the 239 * later is greater than 99 (and thus, it cannot be written with two digits) 240 * it is converted to 99. Examples<br> 241 * <ul> 242 * <li>5.8.10.66 -> 5.081066</li> 243 * <li>216.14.3.108 -> 216.140399</li> 244 * </ul> 245 * 246 * @param version the String with the version description. 247 * 248 * @return a double with a representation of <code>version</code>. 249 * 250 * @warning Due to the nature of the representation of numbers using 251 * fixed-size types, it can happen that 252 * getDoubleRepresentation(getStringRepresentation(x)) != x. 253 * 254 * @see #Version(String) 255 * @deprecated For comparisons, use #compare(Object) 256 */ 257 public static double getDoubleRepresentation(String version) { 258 double returnValue = 0d; 259 260 Version tmpVersion = new Version(version); 261 final int v99 = 99; 262 final int v100 = 100; 263 double divider = 1; 264 for (int i = 0; i <= tmpVersion.getSize(); i++) { 265 int versionPart = tmpVersion.getValue(i); 266 if ((versionPart > v99) && (i != 0)) { 267 log.warn("The element at position " + i + " of the version number " 268 + "is greater than 99; replacing it with 99"); 269 versionPart = v99; 270 } 271 returnValue += ((double)versionPart) / divider; 272 divider = divider * v100; 273 } 274 275 return returnValue; 276 } 277 278 /** 279 * Gets the representation as a string of a version double. 280 * 281 * Gets the representation as a string of a version double. This is the 282 * opposite process to #getDoubleRepresentation(String), splicing the double 283 * value in groups of two digits and using the values as parts of the version 284 * number. Parts are separated using an underscore "_" character. 285 * Examples:<br> 286 * <ul> 287 * <li>5.081066 -> 5_8_10_66</li> 288 * <li>216.140399 -> 216_14_3_99</li> 289 * </ul> 290 * 291 * @param version a double with the version data. 292 * @param fields an int with the number of fields that the resulting String 293 * is expected to have. Setting this value properly allows avoiding rounding 294 * errors due to the use of double. 295 * 296 * @return a String with a representation of <code>version</code>. 297 * @deprecated Use #toString() 298 */ 299 public static String getStringRepresentation(double version, int fields) { 300 StringBuffer returnValue = new StringBuffer(); 301 302 // To pow and other uses, we need the number of fields - 1 303 fields--; 304 final int v100 = 100; 305 double factor = Math.pow(v100, fields); 306 long validVersionDigits = Math.round(version * factor); 307 308 for (int i = 0; i <= fields; i++) { 309 long part = validVersionDigits % v100; 310 returnValue.insert(0, part); 311 validVersionDigits = validVersionDigits / v100; 312 if (i != fields) { 313 returnValue.insert(0, "_"); 314 } 315 } 316 return returnValue.toString(); 317 } 318 319 /** 320 * Gets the representation as a string (three fields) of a version double. 321 * 322 * Gets the representation as a string of a version double. This is the 323 * opposite process to #getDoubleRepresentation(String), splicing the double 324 * value in groups of two digits and using the values as parts of the version 325 * number. Parts are separated using an underscore "_" character. 326 * Examples:<br> 327 * <ul> 328 * <li>5.0810 -> 5_8_10</li> 329 * <li>216.1403 -> 216_14_3</li> 330 * </ul> 331 * This method always return a String representation that contains the three 332 * first fields. 333 * 334 * @param version a double with the version data. 335 * 336 * @return a String with a representation of <code>version</code>. 337 * 338 * @see #getStringRepresentation(double, int) 339 * @deprecated Use #toString() 340 */ 341 public static String getStringRepresentation(double version) { 342 final int v3 = 3; 343 return getStringRepresentation(version, v3); 344 } 345 }