001: /*
002: * $Header: /cvsroot/eclipse/org.eclipse.pde.build/src_ant/org/eclipse/pde/internal/build/tasks/Version.java,v 1.1 2007/02/04 17:03:16 prapicau Exp $
003: *
004: * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: package org.eclipse.pde.internal.build.tasks;
020:
021: import java.util.NoSuchElementException;
022: import java.util.StringTokenizer;
023:
024: /**
025: * Version identifier for bundles and packages.
026: *
027: * <p>
028: * Version identifiers have four components.
029: * <ol>
030: * <li>Major version. A non-negative integer.</li>
031: * <li>Minor version. A non-negative integer.</li>
032: * <li>Micro version. A non-negative integer.</li>
033: * <li>Qualifier. A text string. See <code>Version(String)</code> for the
034: * format of the qualifier string.</li>
035: * </ol>
036: *
037: * <p>
038: * <code>Version</code> objects are immutable.
039: *
040: * @version $Revision: 1.1 $
041: * @since 1.3
042: */
043:
044: public class Version implements Comparable {
045: private final int major;
046: private final int minor;
047: private final int micro;
048: private final String qualifier;
049: private static final String SEPARATOR = "."; //$NON-NLS-1$
050:
051: /**
052: * The empty version "0.0.0". Equivalent to calling
053: * <code>new Version(0,0,0)</code>.
054: */
055: public static final Version emptyVersion = new Version(0, 0, 0);
056:
057: /**
058: * Creates a version identifier from the specified numerical components.
059: *
060: * <p>
061: * The qualifier is set to the empty string.
062: *
063: * @param major Major component of the version identifier.
064: * @param minor Minor component of the version identifier.
065: * @param micro Micro component of the version identifier.
066: * @throws IllegalArgumentException If the numerical components are
067: * negative.
068: */
069: public Version(int major, int minor, int micro) {
070: this (major, minor, micro, null);
071: }
072:
073: /**
074: * Creates a version identifier from the specifed components.
075: *
076: * @param major Major component of the version identifier.
077: * @param minor Minor component of the version identifier.
078: * @param micro Micro component of the version identifier.
079: * @param qualifier Qualifier component of the version identifier. If
080: * <code>null</code> is specified, then the qualifier will be set
081: * to the empty string.
082: * @throws IllegalArgumentException If the numerical components are negative
083: * or the qualifier string is invalid.
084: */
085: public Version(int major, int minor, int micro, String qualifier) {
086: if (qualifier == null) {
087: qualifier = ""; //$NON-NLS-1$
088: }
089:
090: this .major = major;
091: this .minor = minor;
092: this .micro = micro;
093: this .qualifier = qualifier;
094: validate();
095: }
096:
097: /**
098: * Created a version identifier from the specified string.
099: *
100: * <p>
101: * Here is the grammar for version strings.
102: *
103: * <pre>
104: * version ::= major('.'minor('.'micro('.'qualifier)?)?)?
105: * major ::= digit+
106: * minor ::= digit+
107: * micro ::= digit+
108: * qualifier ::= (alpha|digit|'_'|'-')+
109: * digit ::= [0..9]
110: * alpha ::= [a..zA..Z]
111: * </pre>
112: *
113: * There must be no whitespace in version.
114: *
115: * @param version String representation of the version identifier.
116: * @throws IllegalArgumentException If <code>version</code> is improperly
117: * formatted.
118: */
119: public Version(String version) {
120: int major = 0;
121: int minor = 0;
122: int micro = 0;
123: String qualifier = ""; //$NON-NLS-1$
124:
125: try {
126: StringTokenizer st = new StringTokenizer(version,
127: SEPARATOR, true);
128: major = Integer.parseInt(st.nextToken());
129:
130: if (st.hasMoreTokens()) {
131: st.nextToken(); // consume delimiter
132: minor = Integer.parseInt(st.nextToken());
133:
134: if (st.hasMoreTokens()) {
135: st.nextToken(); // consume delimiter
136: micro = Integer.parseInt(st.nextToken());
137:
138: if (st.hasMoreTokens()) {
139: st.nextToken(); // consume delimiter
140: qualifier = st.nextToken();
141:
142: if (st.hasMoreTokens()) {
143: throw new IllegalArgumentException(
144: "invalid format"); //$NON-NLS-1$
145: }
146: }
147: }
148: }
149: } catch (NoSuchElementException e) {
150: throw new IllegalArgumentException("invalid format"); //$NON-NLS-1$
151: }
152:
153: this .major = major;
154: this .minor = minor;
155: this .micro = micro;
156: this .qualifier = qualifier;
157: validate();
158: }
159:
160: /**
161: * Called by the Version constructors to validate the version components.
162: *
163: * @throws IllegalArgumentException If the numerical components are negative
164: * or the qualifier string is invalid.
165: */
166: private void validate() {
167: if (major < 0) {
168: throw new IllegalArgumentException("negative major"); //$NON-NLS-1$
169: }
170: if (minor < 0) {
171: throw new IllegalArgumentException("negative minor"); //$NON-NLS-1$
172: }
173: if (micro < 0) {
174: throw new IllegalArgumentException("negative micro"); //$NON-NLS-1$
175: }
176: int length = qualifier.length();
177: for (int i = 0; i < length; i++) {
178: if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".indexOf(qualifier.charAt(i)) == -1) { //$NON-NLS-1$
179: throw new IllegalArgumentException("invalid qualifier"); //$NON-NLS-1$
180: }
181: }
182: }
183:
184: /**
185: * Parses a version identifier from the specified string.
186: *
187: * <p>
188: * See <code>Version(String)</code> for the format of the version string.
189: *
190: * @param version String representation of the version identifier. Leading
191: * and trailing whitespace will be ignored.
192: * @return A <code>Version</code> object representing the version
193: * identifier. If <code>version</code> is <code>null</code> or
194: * the empty string then <code>emptyVersion</code> will be
195: * returned.
196: * @throws IllegalArgumentException If <code>version</code> is improperly
197: * formatted.
198: */
199: public static Version parseVersion(String version) {
200: if (version == null) {
201: return emptyVersion;
202: }
203:
204: version = version.trim();
205: if (version.length() == 0) {
206: return emptyVersion;
207: }
208:
209: return new Version(version);
210: }
211:
212: /**
213: * Returns the major component of this version identifier.
214: *
215: * @return The major component.
216: */
217: public int getMajor() {
218: return major;
219: }
220:
221: /**
222: * Returns the minor component of this version identifier.
223: *
224: * @return The minor component.
225: */
226: public int getMinor() {
227: return minor;
228: }
229:
230: /**
231: * Returns the micro component of this version identifier.
232: *
233: * @return The micro component.
234: */
235: public int getMicro() {
236: return micro;
237: }
238:
239: /**
240: * Returns the qualifier component of this version identifier.
241: *
242: * @return The qualifier component.
243: */
244: public String getQualifier() {
245: return qualifier;
246: }
247:
248: /**
249: * Returns the string representation of this version identifier.
250: *
251: * <p>
252: * The format of the version string will be <code>major.minor.micro</code>
253: * if qualifier is the empty string or
254: * <code>major.minor.micro.qualifier</code> otherwise.
255: *
256: * @return The string representation of this version identifier.
257: */
258: public String toString() {
259: String base = major + SEPARATOR + minor + SEPARATOR + micro;
260: if (qualifier.length() == 0) { //$NON-NLS-1$
261: return base;
262: } else {
263: return base + SEPARATOR + qualifier;
264: }
265: }
266:
267: /**
268: * Returns a hash code value for the object.
269: *
270: * @return An integer which is a hash code value for this object.
271: */
272: public int hashCode() {
273: return (major << 24) + (minor << 16) + (micro << 8)
274: + qualifier.hashCode();
275: }
276:
277: /**
278: * Compares this <code>Version</code> object to another object.
279: *
280: * <p>
281: * A version is considered to be <b>equal to </b> another version if the
282: * major, minor and micro components are equal and the qualifier component
283: * is equal (using <code>String.equals</code>).
284: *
285: * @param object The <code>Version</code> object to be compared.
286: * @return <code>true</code> if <code>object</code> is a
287: * <code>Version</code> and is equal to this object;
288: * <code>false</code> otherwise.
289: */
290: public boolean equals(Object object) {
291: if (object == this ) { // quicktest
292: return true;
293: }
294:
295: if (!(object instanceof Version)) {
296: return false;
297: }
298:
299: Version other = (Version) object;
300: return (major == other.major) && (minor == other.minor)
301: && (micro == other.micro)
302: && qualifier.equals(other.qualifier);
303: }
304:
305: /**
306: * Compares this <code>Version</code> object to another object.
307: *
308: * <p>
309: * A version is considered to be <b>less than </b> another version if its
310: * major component is less than the other version's major component, or the
311: * major components are equal and its minor component is less than the other
312: * version's minor component, or the major and minor components are equal
313: * and its micro component is less than the other version's micro component,
314: * or the major, minor and micro components are equal and it's qualifier
315: * component is less than the other version's qualifier component (using
316: * <code>String.compareTo</code>).
317: *
318: * <p>
319: * A version is considered to be <b>equal to</b> another version if the
320: * major, minor and micro components are equal and the qualifier component
321: * is equal (using <code>String.compareTo</code>).
322: *
323: * @param object The <code>Version</code> object to be compared.
324: * @return A negative integer, zero, or a positive integer if this object is
325: * less than, equal to, or greater than the specified
326: * <code>Version</code> object.
327: * @throws ClassCastException If the specified object is not a
328: * <code>Version</code>.
329: */
330: public int compareTo(Object object) {
331: if (object == this ) { // quicktest
332: return 0;
333: }
334:
335: Version other = (Version) object;
336:
337: int result = major - other.major;
338: if (result != 0) {
339: return result;
340: }
341:
342: result = minor - other.minor;
343: if (result != 0) {
344: return result;
345: }
346:
347: result = micro - other.micro;
348: if (result != 0) {
349: return result;
350: }
351:
352: return qualifier.compareTo(other.qualifier);
353: }
354: }
|