Frames | No Frames |
1: /* UUID.java -- Class that represents a UUID object. 2: Copyright (C) 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.util; 40: 41: import java.io.Serializable; 42: import java.security.MessageDigest; 43: import java.security.NoSuchAlgorithmException; 44: 45: /** 46: * This class represents a 128-bit UUID value. 47: * 48: * There are several types of UUID, and while this class can be used to store 49: * them, only the Leach-Salz (variant 2) UUID specified in RFC-4122 will 50: * give meaningful results from the method calls. 51: * See: http://tools.ietf.org/html/4122 for the details 52: * 53: * The format of a Leach-Salz (variant 2) time-based (version 1) UUID 54: * is as follows: 55: * time_low - upper 32 bits of the most significant 64 bits, 56: * this is the least-significant part of the timestamp. 57: * 58: * time_mid - bits 16-31 of the most significant 64 bits, 59: * this is the middle portion of the timestamp. 60: * 61: * version - bits 8-15 of the most significant 64 bits. 62: * 63: * time_hi - bits 0-7 of the most significant 64 bits, 64: * the most significant portion of the timestamp. 65: * 66: * clock_and_reserved - bits 48-63 of the least significant 64 bits. 67: * a variable number of bits hold the variant 68: * (see the spec) 69: * 70: * node identifier - bits 0-47 of the least signficant 64 bits. 71: * 72: * These fields are valid only for version 1, in the remaining versions, 73: * only the version and variant fields are set, all others are used for data. 74: * 75: * @since 1.5 76: * @author Sven de Marothy 77: */ 78: public final class UUID 79: extends Object 80: implements Serializable, Comparable // genericizeme! 81: { 82: private static final long serialVersionUID = -4856846361193249489L; 83: 84: /** 85: * Serialized field - most significant 64 bits. 86: */ 87: private long mostSigBits; 88: 89: /** 90: * Serialized field - least significant 64 bits. 91: */ 92: private long leastSigBits; 93: 94: /** 95: * Random-number generator. 96: */ 97: private static transient Random r = new Random(); 98: 99: /** 100: * Constructs a new UUID. 101: * 102: * @since 1.5 103: */ 104: public UUID(long mostSigBits, long leastSigBits) 105: { 106: this.mostSigBits = mostSigBits; 107: this.leastSigBits = leastSigBits; 108: } 109: 110: /** 111: * Returns the clock-sequence value of this UUID. 112: * This field only exists in a time-based (version 1) UUID. 113: * 114: * @throws UnsupportedOperationException if the UUID type is not 1. 115: * @returns an int containing the clock-sequence value. 116: */ 117: public int clockSequence() 118: { 119: if( version() != 1 ) 120: throw new UnsupportedOperationException("Not a type 1 UUID"); 121: return (int)((leastSigBits & 0x3FFF000000000000L) >> 48); 122: } 123: 124: /** 125: * Compare this UUID to another. 126: * The comparison is performed as between two 128-bit integers. 127: * 128: * @return -1 if this < val, 0 if they are equal, 1 if this > val. 129: */ 130: public int compareTo(Object val) 131: { 132: return compareTo((UUID)val); 133: } 134: 135: /** 136: * Compare this UUID to another. 137: * The comparison is performed as between two 128-bit integers. 138: * 139: * @return -1 if this < val, 0 if they are equal, 1 if this > val. 140: */ 141: public int compareTo(UUID o) 142: { 143: if( mostSigBits < o.mostSigBits ) 144: return -1; 145: if( mostSigBits > o.mostSigBits ) 146: return 1; 147: if( leastSigBits < o.leastSigBits ) 148: return -1; 149: if( leastSigBits > o.mostSigBits ) 150: return 1; 151: return 0; 152: } 153: 154: /** 155: * Compare a (UUID) object to this one 156: */ 157: public boolean equals(Object obj) 158: { 159: if( !(obj instanceof UUID ) ) 160: return false; 161: return ( ((UUID)obj).mostSigBits == mostSigBits && 162: ((UUID)obj).leastSigBits == leastSigBits ); 163: } 164: 165: /** 166: * Creates a UUID object from a Sting representation. 167: * 168: * For the format of the string, 169: * @see #toString() 170: * 171: * @return a new UUID object. 172: */ 173: public static UUID fromString(String name) 174: { 175: StringTokenizer st = new StringTokenizer( name.trim(), "-" ); 176: if( st.countTokens() < 5 ) 177: throw new IllegalArgumentException( "Incorrect UUID string"+ 178: " representation:"+name ); 179: 180: long msb = (Long.parseLong(st.nextToken(), 16) << 32); // time low 181: msb |= (Long.parseLong(st.nextToken(), 16) << 16); // time mid 182: msb |= Long.parseLong(st.nextToken(), 16); // time high 183: 184: long lsb = (Long.parseLong(st.nextToken(), 16) << 48); // clock 185: lsb |= Long.parseLong(st.nextToken(), 16); // node 186: 187: return new UUID(msb, lsb); 188: } 189: 190: /** 191: * Returns a String representation of the UUID. 192: * 193: * The format of the standard string representation (given in RFC4122) is: 194: * 195: * time-low "-" time-mid "-" 196: * time-high-and-version "-" 197: * clock-seq-and-reserved 198: * clock-seq-low "-" node 199: * 200: * Where each field is represented as a hex string. 201: * 202: * @return the String representation. 203: */ 204: public String toString() 205: { 206: return // time-low first 207: padHex( (( mostSigBits & 0xFFFFFFFF00000000L) >> 32) & 0xFFFFFFFFL, 8) 208: + "-" + // then time-mid 209: padHex( (( mostSigBits & 0xFFFF0000L ) >> 16), 4 ) 210: + "-" + // time-high 211: padHex( ( mostSigBits & 0x0000000000000000FFFFL ), 4 ) 212: + "-" + // clock (note - no reason to separate high and low here) 213: padHex( (((leastSigBits & 0xFFFF000000000000L) >> 48) & 0xFFFF), 4 ) 214: + "-" + // finally the node value. 215: padHex(leastSigBits & 0xFFFFFFFFFFFFL, 12); 216: } 217: 218: /** 219: * Returns the least significant 64 bits of the UUID as a <code>long</code>. 220: */ 221: public long getLeastSignificantBits() 222: { 223: return leastSigBits; 224: } 225: 226: /** 227: * Returns the most significant 64 bits of the UUID as a <code>long</code>. 228: */ 229: public long getMostSignificantBits() 230: { 231: return mostSigBits; 232: } 233: 234: /** 235: * Returns a hash of this UUID. 236: */ 237: public int hashCode() 238: { 239: int l1 = (int)(leastSigBits & 0xFFFFFFFFL); 240: int l2 = (int)((leastSigBits & 0xFFFFFFFF00000000L) >> 32); 241: int m1 = (int)(mostSigBits & 0xFFFFFFFFL); 242: int m2 = (int)((mostSigBits & 0xFFFFFFFF00000000L) >> 32); 243: 244: return (l1 ^ l2) ^ (m1 ^ m2); 245: } 246: 247: /** 248: * Creates a UUID version 3 object (name based with MD5 hashing) 249: * from a series of bytes representing a name. 250: */ 251: public static UUID nameUUIDFromBytes(byte[] name) 252: { 253: long msb, lsb; 254: byte[] hash; 255: 256: try 257: { 258: MessageDigest md5 = MessageDigest.getInstance("MD5"); 259: hash = md5.digest( name ); 260: } 261: catch (NoSuchAlgorithmException e) 262: { 263: throw new UnsupportedOperationException("No MD5 algorithm available."); 264: } 265: 266: msb = ((hash[0] & 0xFFL) << 56) | ((hash[1] & 0xFFL) << 48) | 267: ((hash[2] & 0xFFL) << 40) | ((hash[3] & 0xFFL) << 32) | 268: ((hash[4] & 0xFFL) << 24) | ((hash[5] & 0xFFL) << 16) | 269: ((hash[6] & 0xFFL) << 8) | (hash[7] & 0xFFL); 270: 271: lsb = ((hash[8] & 0xFFL) << 56) | ((hash[9] & 0xFFL) << 48) | 272: ((hash[10] & 0xFFL) << 40) | ((hash[11] & 0xFFL) << 32) | 273: ((hash[12] & 0xFFL) << 24) | ((hash[13] & 0xFFL) << 16) | 274: ((hash[14] & 0xFFL) << 8) | (hash[15] & 0xFFL); 275: 276: lsb &= 0x3FFFFFFFFFFFFFFFL; 277: lsb |= 0x8000000000000000L; // set top two bits to variant 2 278: 279: msb &= 0xFFFFFFFFFFFF0FFFL; 280: msb |= 0x3000; // Version 3; 281: 282: return new UUID(msb, lsb); 283: } 284: 285: /** 286: * Returns the 48-bit node value in a long. 287: * This field only exists in a time-based (version 1) UUID. 288: * 289: * @throws UnsupportedOperationException if the UUID type is not 1. 290: * @returns a long with the node value in the lower 48 bits. 291: */ 292: public long node() 293: { 294: if( version() != 1 ) 295: throw new UnsupportedOperationException("Not a type 1 UUID"); 296: return (leastSigBits & 0xFFFFFFFFFFFFL); 297: } 298: 299: /** 300: * Returns the 60-bit timestamp value of the UUID in a long. 301: * This field only exists in a time-based (version 1) UUID. 302: * 303: * @throws UnsupportedOperationException if the UUID type is not 1. 304: * @returns a long with the timestamp value. 305: */ 306: public long timestamp() 307: { 308: if( version() != 1 ) 309: throw new UnsupportedOperationException("Not a type 1 UUID"); 310: long time = (( mostSigBits & 0xFFFFFFFF00000000L) >> 32); 311: time |= (( mostSigBits & 0xFFFF0000L ) << 16); 312: long time_hi = ( mostSigBits & 0xFFFL ); 313: time |= (time_hi << 48); 314: return time; 315: } 316: 317: /** 318: * Generate a Leach-Salz (Variant 2) randomly generated (version 4) 319: * UUID. 320: * 321: */ 322: public static UUID randomUUID() 323: { 324: long lsb = r.nextLong(); 325: long msb = r.nextLong(); 326: 327: lsb &= 0x3FFFFFFFFFFFFFFFL; 328: lsb |= 0x8000000000000000L; // set top two bits to variant 2 329: 330: msb &= 0xFFFFFFFFFFFF0FFFL; 331: msb |= 0x4000; // Version 4; 332: 333: return new UUID( msb, lsb ); 334: } 335: 336: /** 337: * Returns a hex String from l, padded to n spaces. 338: */ 339: private String padHex( long l, int n ) 340: { 341: String s = Long.toHexString( l ); 342: while( s.length() < n ) 343: s = "0" + s; 344: return s; 345: } 346: 347: /** 348: * Returns the variant of the UUID 349: * 350: * This may be: 351: * 0 = Reserved for NCS backwards-compatibility 352: * 2 = Leach-Salz (supports the other methods in this class) 353: * 6 = Reserved for Microsoft backwards-compatibility 354: * 7 = (reserved for future use) 355: */ 356: public int variant() 357: { 358: // Get the top 3 bits (not all may be part of the variant) 359: int v = (int)((leastSigBits & 0xE000000000000000L) >> 61); 360: if( (v & 0x04) == 0 ) // msb of the variant is 0 361: return 0; 362: if( (v & 0x02) == 0 ) // variant is 0 1 (Leach-Salz) 363: return 2; 364: return v; // 6 or 7 365: } 366: 367: /** 368: * Returns the version # of the UUID. 369: * 370: * Valid version numbers for a variant 2 UUID are: 371: * 1 = Time based UUID 372: * 2 = DCE security UUID 373: * 3 = Name-based UUID using MD5 hashing 374: * 4 = Randomly generated UUID 375: * 5 = Name-based UUID using SHA-1 hashing 376: * 377: * @return the version number 378: */ 379: public int version() 380: { 381: return (int)((mostSigBits & 0xF000L) >> 12); 382: } 383: }