KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > service > resolver > Version


1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.osgi.service.resolver;
12
13 import java.util.StringTokenizer JavaDoc;
14 import java.util.Vector JavaDoc;
15
16 /**
17  * <p>
18  * Version identifier for a plug-in. In its string representation,
19  * it consists of up to 4 tokens separated by a decimal point.
20  * The first 3 tokens are positive integer numbers, the last token
21  * is an uninterpreted string (no whitespace characters allowed).
22  * For example, the following are valid version identifiers
23  * (as strings):
24  * <ul>
25  * <li><code>0.0.0</code></li>
26  * <li><code>1.0.127564</code></li>
27  * <li><code>3.7.2.build-127J</code></li>
28  * <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>
29  * <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>
30  * </ul>
31  * </p>
32  * <p>
33  * The version identifier can be decomposed into a major, minor,
34  * micro level component and qualifier components. A difference
35  * in the major component is interpreted as an incompatible version
36  * change. A difference in the minor (and not the major) component
37  * is interpreted as a compatible version change. The micro
38  * level component is interpreted as a cumulative and compatible
39  * micro update of the minor version component. The qualifier is
40  * not interpreted, other than in version comparisons. The
41  * qualifiers are compared using lexicographical string comparison.
42  * </p>
43  * <p>
44  * Version identifiers can be matched as perfectly equal, equivalent,
45  * compatible or greaterOrEqual.
46  * </p>
47  * <p>
48  * Clients may instantiate; not intended to be subclassed by clients.
49  * </p>
50  * @see org.eclipse.core.runtime.IPluginDescriptor#getVersionIdentifier
51  * @see java.lang.String#compareTo
52  */

53 public final class Version implements Comparable JavaDoc {
54
55     private int major = 0;
56     private int minor = 0;
57     private int micro = 0;
58     private String JavaDoc qualifier = ""; //$NON-NLS-1$
59
private boolean inclusive = true;
60
61     private static final String JavaDoc SEPARATOR = "."; //$NON-NLS-1$
62

63     public static Version emptyVersion = new Version(0, 0, 0);
64     public static Version maxVersion = new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
65
66     /**
67      * Creates a plug-in version identifier from a given Version.
68      *
69      * @param version
70      */

71     public Version(Version version) {
72         this(version.major, version.minor, version.micro, version.qualifier, version.inclusive);
73     }
74
75     /**
76      * Creates a plug-in version identifier from its components.
77      *
78      * @param major major component of the version identifier
79      * @param minor minor component of the version identifier
80      * @param micro micro update component of the version identifier
81      */

82     public Version(int major, int minor, int micro) {
83         this(major, minor, micro, null);
84     }
85
86     /**
87      * Creates a plug-in version identifier from its components.
88      *
89      * @param major major component of the version identifier
90      * @param minor minor component of the version identifier
91      * @param micro micro update component of the version identifier
92      * @param qualifier qualifier component of the version identifier
93      * Qualifier characters that are not a letter or a digit are replaced.
94      */

95     public Version(int major, int minor, int micro, String JavaDoc qualifier) throws IllegalArgumentException JavaDoc {
96         this(major, minor, micro, qualifier, true);
97     }
98
99     /**
100      * Creates a plug-in version identifier from its components.
101      *
102      * @param major major component of the version identifier
103      * @param minor minor component of the version identifier
104      * @param micro micro update component of the version identifier
105      * @param qualifier qualifier component of the version identifier
106      * @param inclusive inclusive property of the version identifier
107      * Qualifier characters that are not a letter or a digit are replaced.
108      */

109     public Version(int major, int minor, int micro, String JavaDoc qualifier, boolean inclusive) throws IllegalArgumentException JavaDoc {
110
111         // Do the test outside of the assert so that they 'Policy.bind'
112
// will not be evaluated each time (including cases when we would
113
// have passed by the assert).
114

115         if (major < 0)
116             throw new IllegalArgumentException JavaDoc("Negative major"); //$NON-NLS-1$
117
if (minor < 0)
118             throw new IllegalArgumentException JavaDoc("Negative minor"); //$NON-NLS-1$
119
if (micro < 0)
120             throw new IllegalArgumentException JavaDoc("Negative micro"); //$NON-NLS-1$
121
if (qualifier == null)
122             qualifier = ""; //$NON-NLS-1$
123

124         this.major = major;
125         this.minor = minor;
126         this.micro = micro;
127         this.qualifier = verifyQualifier(qualifier);
128         this.inclusive = inclusive;
129     }
130
131     /**
132      * Creates a plug-in version identifier from the given string.
133      * The string represenation consists of up to 4 tokens
134      * separated by decimal point.
135      * For example, the following are valid version identifiers
136      * (as strings):
137      * <ul>
138      * <li><code>0.0.0</code></li>
139      * <li><code>1.0.127564</code></li>
140      * <li><code>3.7.2.build-127J</code></li>
141      * <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>
142      * <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>
143      * </ul>
144      *
145      * @param versionId string representation of the version identifier.
146      * Qualifier characters that are not a letter or a digit are replaced.
147      */

148     public Version(String JavaDoc versionId) {
149         this(versionId, true);
150     }
151
152     /**
153      * Creates a plug-in version identifier from the given string.
154      * The string represenation consists of up to 4 tokens
155      * separated by decimal point.
156      * For example, the following are valid version identifiers
157      * (as strings):
158      * <ul>
159      * <li><code>0.0.0</code></li>
160      * <li><code>1.0.127564</code></li>
161      * <li><code>3.7.2.build-127J</code></li>
162      * <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>
163      * <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>
164      * </ul>
165      *
166      * @param versionId string representation of the version identifier.
167      * Qualifier characters that are not a letter or a digit are replaced.
168      * @param inclusive inclusive property of the version identifier
169      */

170     public Version(String JavaDoc versionId, boolean inclusive) {
171         if (versionId == null)
172             versionId = "0.0.0"; //$NON-NLS-1$
173
Object JavaDoc[] parts = parseVersion(versionId);
174         this.major = ((Integer JavaDoc) parts[0]).intValue();
175         this.minor = ((Integer JavaDoc) parts[1]).intValue();
176         this.micro = ((Integer JavaDoc) parts[2]).intValue();
177         this.qualifier = (String JavaDoc) parts[3];
178         this.inclusive = inclusive;
179     }
180
181     private static Object JavaDoc[] parseVersion(String JavaDoc versionId) {
182         // Do the test outside of the assert so that they 'Policy.bind'
183
// will not be evaluated each time (including cases when we would
184
// have passed by the assert).
185
if (versionId == null)
186             throw new IllegalArgumentException JavaDoc("Null version string"); //$NON-NLS-1$
187

188         String JavaDoc s = versionId.trim();
189         if (s.equals("")) //$NON-NLS-1$
190
throw new IllegalArgumentException JavaDoc("Empty version string"); //$NON-NLS-1$
191
if (s.startsWith(SEPARATOR))
192             throw new IllegalArgumentException JavaDoc("Invalid version format"); //$NON-NLS-1$
193
if (s.endsWith(SEPARATOR))
194             throw new IllegalArgumentException JavaDoc("Invalid version format"); //$NON-NLS-1$
195
if (s.indexOf(SEPARATOR + SEPARATOR) != -1)
196             throw new IllegalArgumentException JavaDoc("Invalid version format"); //$NON-NLS-1$
197

198         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(s, SEPARATOR);
199         Vector JavaDoc elements = new Vector JavaDoc(4);
200
201         while (st.hasMoreTokens())
202             elements.addElement(st.nextToken());
203
204         int elementSize = elements.size();
205
206         if (elementSize <= 0)
207             throw new IllegalArgumentException JavaDoc("Invalid version format (no token)"); //$NON-NLS-1$
208
if (elementSize > 4)
209             throw new IllegalArgumentException JavaDoc("Invalid version format (more than 4 tokens)"); //$NON-NLS-1$
210

211         int[] numbers = new int[3];
212         try {
213             numbers[0] = Integer.parseInt((String JavaDoc) elements.elementAt(0));
214             if (numbers[0] < 0)
215                 throw new IllegalArgumentException JavaDoc("Negative major"); //$NON-NLS-1$
216
} catch (NumberFormatException JavaDoc nfe) {
217             throw new IllegalArgumentException JavaDoc("Invalid major"); //$NON-NLS-1$
218
}
219
220         try {
221             if (elementSize >= 2) {
222                 numbers[1] = Integer.parseInt((String JavaDoc) elements.elementAt(1));
223                 if (numbers[1] < 0)
224                     throw new IllegalArgumentException JavaDoc("Negative minor"); //$NON-NLS-1$
225
} else
226                 numbers[1] = 0;
227         } catch (NumberFormatException JavaDoc nfe) {
228             throw new IllegalArgumentException JavaDoc("Invalid minor"); //$NON-NLS-1$
229
}
230
231         try {
232             if (elementSize >= 3) {
233                 numbers[2] = Integer.parseInt((String JavaDoc) elements.elementAt(2));
234                 if (numbers[2] < 0)
235                     throw new IllegalArgumentException JavaDoc("Invalid micro"); //$NON-NLS-1$
236
} else
237                 numbers[2] = 0;
238         } catch (NumberFormatException JavaDoc nfe) {
239             throw new IllegalArgumentException JavaDoc("Invalid micro"); //$NON-NLS-1$
240
}
241
242         // "result" is a 4-element array with the major, minor, micro, and qualifier
243
Object JavaDoc[] result = new Object JavaDoc[4];
244         result[0] = new Integer JavaDoc(numbers[0]);
245         result[1] = new Integer JavaDoc(numbers[1]);
246         result[2] = new Integer JavaDoc(numbers[2]);
247         if (elementSize >= 4)
248             result[3] = verifyQualifier((String JavaDoc) elements.elementAt(3));
249         else
250             result[3] = ""; //$NON-NLS-1$
251
return result;
252     }
253
254     /**
255      * Compare version identifiers for equality. Identifiers are
256      * equal if all of their components are equal.
257      *
258      * @param object an object to compare
259      * @return whehter or not the two objects are equal
260      */

261     public boolean equals(Object JavaDoc object) {
262         if (!(object instanceof Version))
263             return false;
264         Version v = (Version) object;
265         return v.getMajorComponent() == major && v.getMinorComponent() == minor && v.getMicroComponent() == micro && v.getQualifierComponent().equals(qualifier);
266     }
267
268     /**
269      * Returns a hash code value for the object.
270      *
271      * @return an integer which is a hash code value for this object.
272      */

273     public int hashCode() {
274         int code = major + minor + micro; // R1.0 result
275
if (qualifier.equals("")) //$NON-NLS-1$
276
return code;
277         else
278             return code + qualifier.hashCode();
279     }
280
281     /**
282      * Returns the major (incompatible) component of this
283      * version identifier.
284      *
285      * @return the major version
286      */

287     public int getMajorComponent() {
288         return major;
289     }
290
291     /**
292      * Returns the minor (compatible) component of this
293      * version identifier.
294      *
295      * @return the minor version
296      */

297     public int getMinorComponent() {
298         return minor;
299     }
300
301     /**
302      * Returns the micro level component of this
303      * version identifier.
304      *
305      * @return the micro level
306      */

307     public int getMicroComponent() {
308         return micro;
309     }
310
311     /**
312      * Returns the qualifier component of this
313      * version identifier.
314      *
315      * @return the qualifier
316      */

317     public String JavaDoc getQualifierComponent() {
318         return qualifier;
319     }
320
321     /**
322      * Returns whether this Version is inclusive when used as a
323      * VersionRange minimum or maximum.
324      * @return <code>true</code> if this Version is inclusive,
325      * <code>false</code> otherwise
326      */

327     public boolean isInclusive() {
328         return inclusive;
329     }
330
331     /**
332      * Compares two version identifiers to see if this one is
333      * greater than or equal to the argument.
334      * <p>
335      * A version identifier is considered to be greater than or equal
336      * if its major component is greater than the argument major
337      * component, or the major components are equal and its minor component
338      * is greater than the argument minor component, or the
339      * major and minor components are equal and its micro component is
340      * greater than the argument micro component, or the major, minor and
341      * micro components are equal and the qualifier component is
342      * greated than the argument qualifier component (using lexicographic
343      * string comparison), or all components are equal.
344      * </p>
345      * @deprecated use {@link VersionRange}
346      * @param id the other version identifier
347      * @return <code>true</code> is this version identifier
348      * is compatible with the given version identifier, and
349      * <code>false</code> otherwise
350      */

351     public boolean matchGreaterOrEqualTo(Version id) {
352         if (id == null)
353             return false;
354         if (major > id.getMajorComponent())
355             return true;
356         if ((major == id.getMajorComponent()) && (minor > id.getMinorComponent()))
357             return true;
358         if ((major == id.getMajorComponent()) && (minor == id.getMinorComponent()) && (micro > id.getMicroComponent()))
359             return true;
360         if ((major == id.getMajorComponent()) && (minor == id.getMinorComponent()) && (micro == id.getMicroComponent()) && (qualifier.compareTo(id.getQualifierComponent()) >= 0))
361             return true;
362         else
363             return false;
364     }
365
366     /**
367      * Compares two version identifiers for major match.
368      * <p>
369      * A version identifier is considered to match on major if its major
370      * component equals to the argument major component, and its minor component
371      * is greater than or equal to the argument minor component.
372      * If the minor components are equal, than the micro level of the
373      * version identifier must be greater than or equal to the micro level
374      * of the argument identifier. If the micro levels are equal, the two
375      * version identifiers are considered to be equivalent if this qualifier is
376      * greated or equal to the qualifier of the argument (using lexicographic
377      * string comparison).
378      * </p>
379      * @deprecated use {@link VersionRange}
380      * @param id the other version identifier
381      * @return <code>true</code> is this version identifier
382      * is compatible with the given version identifier, and
383      * <code>false</code> otherwise
384      */

385     public boolean matchMajor(Version id) {
386         if (id == null)
387             return false;
388         if (major != id.getMajorComponent())
389             return false;
390         if (minor > id.getMinorComponent())
391             return true;
392         if (minor < id.getMinorComponent())
393             return false;
394         if (micro > id.getMicroComponent())
395             return true;
396         if (micro < id.getMicroComponent())
397             return false;
398         if (qualifier.compareTo(id.getQualifierComponent()) >= 0)
399             return true;
400         else
401             return false;
402     }
403
404     /**
405      * Compares two version identifiers for equivalency.
406      * <p>
407      * Two version identifiers are considered to be equivalent if their major
408      * and minor component equal and are at least at the same micro level
409      * as the argument. If the micro levels are equal, the two version
410      * identifiers are considered to be equivalent if this qualifier is
411      * greated or equal to the qualifier of the argument (using lexicographic
412      * string comparison).
413      * </p>
414      * @deprecated use {@link VersionRange}
415      * @param id the other version identifier
416      * @return <code>true</code> is this version identifier
417      * is equivalent to the given version identifier, and
418      * <code>false</code> otherwise
419      */

420     public boolean matchMinor(Version id) {
421         if (id == null)
422             return false;
423         if (major != id.getMajorComponent())
424             return false;
425         if (minor != id.getMinorComponent())
426             return false;
427         if (micro > id.getMicroComponent())
428             return true;
429         if (micro < id.getMicroComponent())
430             return false;
431         if (qualifier.compareTo(id.getQualifierComponent()) >= 0)
432             return true;
433         else
434             return false;
435     }
436
437     /**
438      * Compares two version identifiers for micro match.
439      * <p>
440      * Two version identifiers are considered to micro match if their major,
441      * minor and micro components equal and this qualifier is
442      * greated or equal to the qualifier of the argument (using lexicographic
443      * string comparison).
444      * </p>
445      * @deprecated use {@link VersionRange}
446      * @param id the other version identifier
447      * @return <code>true</code> is this version identifier
448      * matches on micro to the given version identifier, and
449      * <code>false</code> otherwise
450      */

451     public boolean matchMicro(Version id) {
452         if (id == null)
453             return false;
454         if (major != id.getMajorComponent() || minor != id.getMinorComponent() || micro != id.getMicroComponent())
455             return false;
456         if (qualifier.compareTo(id.getQualifierComponent()) >= 0)
457             return true;
458         else
459             return false;
460     }
461
462     /**
463      * Compares two version identifiers for perfect equality.
464      * <p>
465      * Two version identifiers are considered to be perfectly equal if their
466      * major, minor, micro and qualifier components are equal
467      * </p>
468      * @deprecated use {@link VersionRange}
469      * @param id the other version identifier
470      * @return <code>true</code> is this version identifier
471      * is perfectly equal to the given version identifier, and
472      * <code>false</code> otherwise
473      */

474     public boolean matchQualifier(Version id) {
475         return equals(id);
476     }
477
478     /**
479      * Compares two version identifiers for order using multi-decimal
480      * comparison.
481      *
482      * @param id the other version identifier
483      * @return <code>true</code> is this version identifier
484      * is greater than the given version identifier, and
485      * <code>false</code> otherwise
486      */

487     public boolean isGreaterThan(Version id) {
488
489         if (id == null) {
490             if (major == 0 && minor == 0 && micro == 0 && qualifier.equals("")) //$NON-NLS-1$
491
return false;
492             else
493                 return true;
494         }
495
496         if (major > id.getMajorComponent())
497             return true;
498         if (major < id.getMajorComponent())
499             return false;
500         if (minor > id.getMinorComponent())
501             return true;
502         if (minor < id.getMinorComponent())
503             return false;
504         if (micro > id.getMicroComponent())
505             return true;
506         if (micro < id.getMicroComponent())
507             return false;
508         if (qualifier.compareTo(id.getQualifierComponent()) > 0)
509             return true;
510         else
511             return false;
512
513     }
514
515     /**
516      * Returns the string representation of this version identifier.
517      * The result satisfies
518      * <code>vi.equals(new PluginVersionIdentifier(vi.toString()))</code>.
519      *
520      * @return the string representation of this plug-in version identifier
521      */

522     public String JavaDoc toString() {
523         String JavaDoc base = major + SEPARATOR + minor + SEPARATOR + micro;
524         // R1.0 result
525
if (qualifier.equals("")) //$NON-NLS-1$
526
return base;
527         else
528             return base + SEPARATOR + qualifier;
529     }
530
531     private static String JavaDoc verifyQualifier(String JavaDoc s) {
532         char[] chars = s.trim().toCharArray();
533         boolean whitespace = false;
534         for (int i = 0; i < chars.length; i++) {
535             char c = chars[i];
536             if (!(Character.isLetter(c) || Character.isDigit(c))) {
537                 chars[i] = '-';
538                 whitespace = true;
539             }
540         }
541         return whitespace ? new String JavaDoc(chars) : s;
542     }
543
544     /**
545      * Compares this Version object with the specified Version object for order.
546      * Returns a negative integer, zero, or a positive integer as this object is less
547      * than, equal to, or greater than the specified object.<p>
548      *
549      * @param o the Version object to be compared.
550      * @return a negative integer, zero, or a positive integer as this object
551      * is less than, equal to, or greater than the specified Version object.
552      *
553      * @throws ClassCastException if the specified object's type
554      * is not Version.
555      */

556     public int compareTo(Object JavaDoc o) {
557         if (!(o instanceof Version))
558             throw new ClassCastException JavaDoc();
559
560         if (equals(o))
561             return 0;
562
563         if (isGreaterThan((Version) o))
564             return 1;
565
566         return -1;
567     }
568 }
Popular Tags