/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun * Microsystems, Inc. All Rights Reserved. */ package org.openide.modules; // THIS CLASS OUGHT NOT USE NbBundle NOR org.openide CLASSES // OUTSIDE OF openide-util.jar! UI AND FILESYSTEM/DATASYSTEM // INTERACTIONS SHOULD GO ELSEWHERE. import java.util.*; /** Utility class representing a specification version. * @author Jesse Glick * @since 1.24 */ public final class SpecificationVersion implements Comparable { // Might be a bit wasteful of memory, but many SV's are created during // startup, so best to not have to reparse them each time! // In fact sharing the int arrays might save a bit of memory overall, // since it is unusual for a module to be deleted. private static final Map parseCache = new HashMap(200); // Map<String,int[]> private final int[] digits; /** Parse from string. Must be Dewey-decimal. */ public SpecificationVersion(String version) throws NumberFormatException { synchronized (parseCache) { int[] d = (int[])parseCache.get(version); if (d == null) { d = parse(version); parseCache.put(version.intern(), d); } digits = d; } } private static int[] parse(String version) throws NumberFormatException { List l = new ArrayList(version.length()); StringTokenizer tok = new StringTokenizer(version, ".", true); // NOI18N if (tok.countTokens() % 2 == 0) { throw new NumberFormatException("Even number of pieces in a spec version: `" + version + "'"); // NOI18N } boolean expectingNumber = true; while (tok.hasMoreTokens()) { if (expectingNumber) { expectingNumber = false; int piece = Integer.parseInt(tok.nextToken()); if (piece < 0) throw new NumberFormatException("Spec version component <0: " + piece); // NOI18N l.add(new Integer(piece)); } else { if (! ".".equals(tok.nextToken())) { // NOI18N throw new NumberFormatException("Expected dot in spec version: `" + version + "'"); // NOI18N } expectingNumber = true; } } int size = l.size(); int[] digits = new int[size]; for (int i = 0; i < size; i++) { digits[i] = ((Integer) l.get(i)).intValue(); } return digits; } /** Perform a Dewey-decimal comparison. */ public int compareTo(Object o) { int[] od = ((SpecificationVersion) o).digits; int len1 = digits.length; int len2 = od.length; int max = Math.max(len1, len2); for (int i = 0; i < max; i++) { int d1 = (i < len1 ? digits[i] : 0); int d2 = (i < len2 ? od[i] : 0); if (d1 != d2) { return d1 - d2; } } return 0; } /** Overridden to compare contents. */ public boolean equals(Object o) { if (! (o instanceof SpecificationVersion)) return false; int[] d = ((SpecificationVersion) o).digits; int len = digits.length; if (len != d.length) return false; for (int i = 0; i < len; i++) { if (digits[i] != d[i]) return false; } return true; } /** Overridden to hash by contents. */ public int hashCode() { int hash = 925295; int len = digits.length; for (int i = 0; i < len; i++) { hash ^= (digits[i] << i); } return hash; } /** String representation (Dewey-decimal). */ public String toString() { StringBuffer buf = new StringBuffer(digits.length * 3 + 1); for (int i = 0; i < digits.length; i++) { if (i > 0) buf.append('.'); // NOI18N buf.append(digits[i]); } return buf.toString(); } }