View Javadoc

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 }