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<UUID> 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(UUID o) 131: { 132: if( mostSigBits < o.mostSigBits ) 133: return -1; 134: if( mostSigBits > o.mostSigBits ) 135: return 1; 136: if( leastSigBits < o.leastSigBits ) 137: return -1; 138: if( leastSigBits > o.mostSigBits ) 139: return 1; 140: return 0; 141: } 142: 143: /** 144: * Compare a (UUID) object to this one 145: */ 146: public boolean equals(Object obj) 147: { 148: if( !(obj instanceof UUID ) ) 149: return false; 150: return ( ((UUID)obj).mostSigBits == mostSigBits && 151: ((UUID)obj).leastSigBits == leastSigBits ); 152: } 153: 154: /** 155: * Creates a UUID object from a Sting representation. 156: * 157: * For the format of the string, 158: * @see #toString() 159: * 160: * @return a new UUID object. 161: */ 162: public static UUID fromString(String name) 163: { 164: StringTokenizer st = new StringTokenizer( name.trim(), "-" ); 165: if( st.countTokens() < 5 ) 166: throw new IllegalArgumentException( "Incorrect UUID string"+ 167: " representation:"+name ); 168: 169: long msb = (Long.parseLong(st.nextToken(), 16) << 32); // time low 170: msb |= (Long.parseLong(st.nextToken(), 16) << 16); // time mid 171: msb |= Long.parseLong(st.nextToken(), 16); // time high 172: 173: long lsb = (Long.parseLong(st.nextToken(), 16) << 48); // clock 174: lsb |= Long.parseLong(st.nextToken(), 16); // node 175: 176: return new UUID(msb, lsb); 177: } 178: 179: /** 180: * Returns a String representation of the UUID. 181: * 182: * The format of the standard string representation (given in RFC4122) is: 183: * 184: * time-low "-" time-mid "-" 185: * time-high-and-version "-" 186: * clock-seq-and-reserved 187: * clock-seq-low "-" node 188: * 189: * Where each field is represented as a hex string. 190: * 191: * @return the String representation. 192: */ 193: public String toString() 194: { 195: return // time-low first 196: padHex( (( mostSigBits & 0xFFFFFFFF00000000L) >> 32) & 0xFFFFFFFFL, 8) 197: + "-" + // then time-mid 198: padHex( (( mostSigBits & 0xFFFF0000L ) >> 16), 4 ) 199: + "-" + // time-high 200: padHex( ( mostSigBits & 0x0000000000000000FFFFL ), 4 ) 201: + "-" + // clock (note - no reason to separate high and low here) 202: padHex( (((leastSigBits & 0xFFFF000000000000L) >> 48) & 0xFFFF), 4 ) 203: + "-" + // finally the node value. 204: padHex(leastSigBits & 0xFFFFFFFFFFFFL, 12); 205: } 206: 207: /** 208: * Returns the least significant 64 bits of the UUID as a <code>long</code>. 209: */ 210: public long getLeastSignificantBits() 211: { 212: return leastSigBits; 213: } 214: 215: /** 216: * Returns the most significant 64 bits of the UUID as a <code>long</code>. 217: */ 218: public long getMostSignificantBits() 219: { 220: return mostSigBits; 221: } 222: 223: /** 224: * Returns a hash of this UUID. 225: */ 226: public int hashCode() 227: { 228: int l1 = (int)(leastSigBits & 0xFFFFFFFFL); 229: int l2 = (int)((leastSigBits & 0xFFFFFFFF00000000L) >> 32); 230: int m1 = (int)(mostSigBits & 0xFFFFFFFFL); 231: int m2 = (int)((mostSigBits & 0xFFFFFFFF00000000L) >> 32); 232: 233: return (l1 ^ l2) ^ (m1 ^ m2); 234: } 235: 236: /** 237: * Creates a UUID version 3 object (name based with MD5 hashing) 238: * from a series of bytes representing a name. 239: */ 240: public static UUID nameUUIDFromBytes(byte[] name) 241: { 242: long msb, lsb; 243: byte[] hash; 244: 245: try 246: { 247: MessageDigest md5 = MessageDigest.getInstance("MD5"); 248: hash = md5.digest( name ); 249: } 250: catch (NoSuchAlgorithmException e) 251: { 252: throw new UnsupportedOperationException("No MD5 algorithm available."); 253: } 254: 255: msb = ((hash[0] & 0xFFL) << 56) | ((hash[1] & 0xFFL) << 48) | 256: ((hash[2] & 0xFFL) << 40) | ((hash[3] & 0xFFL) << 32) | 257: ((hash[4] & 0xFFL) << 24) | ((hash[5] & 0xFFL) << 16) | 258: ((hash[6] & 0xFFL) << 8) | (hash[7] & 0xFFL); 259: 260: lsb = ((hash[8] & 0xFFL) << 56) | ((hash[9] & 0xFFL) << 48) | 261: ((hash[10] & 0xFFL) << 40) | ((hash[11] & 0xFFL) << 32) | 262: ((hash[12] & 0xFFL) << 24) | ((hash[13] & 0xFFL) << 16) | 263: ((hash[14] & 0xFFL) << 8) | (hash[15] & 0xFFL); 264: 265: lsb &= 0x3FFFFFFFFFFFFFFFL; 266: lsb |= 0x8000000000000000L; // set top two bits to variant 2 267: 268: msb &= 0xFFFFFFFFFFFF0FFFL; 269: msb |= 0x3000; // Version 3; 270: 271: return new UUID(msb, lsb); 272: } 273: 274: /** 275: * Returns the 48-bit node value in a long. 276: * This field only exists in a time-based (version 1) UUID. 277: * 278: * @throws UnsupportedOperationException if the UUID type is not 1. 279: * @returns a long with the node value in the lower 48 bits. 280: */ 281: public long node() 282: { 283: if( version() != 1 ) 284: throw new UnsupportedOperationException("Not a type 1 UUID"); 285: return (leastSigBits & 0xFFFFFFFFFFFFL); 286: } 287: 288: /** 289: * Returns the 60-bit timestamp value of the UUID in a long. 290: * This field only exists in a time-based (version 1) UUID. 291: * 292: * @throws UnsupportedOperationException if the UUID type is not 1. 293: * @returns a long with the timestamp value. 294: */ 295: public long timestamp() 296: { 297: if( version() != 1 ) 298: throw new UnsupportedOperationException("Not a type 1 UUID"); 299: long time = (( mostSigBits & 0xFFFFFFFF00000000L) >> 32); 300: time |= (( mostSigBits & 0xFFFF0000L ) << 16); 301: long time_hi = ( mostSigBits & 0xFFFL ); 302: time |= (time_hi << 48); 303: return time; 304: } 305: 306: /** 307: * Generate a Leach-Salz (Variant 2) randomly generated (version 4) 308: * UUID. 309: * 310: */ 311: public static UUID randomUUID() 312: { 313: long lsb = r.nextLong(); 314: long msb = r.nextLong(); 315: 316: lsb &= 0x3FFFFFFFFFFFFFFFL; 317: lsb |= 0x8000000000000000L; // set top two bits to variant 2 318: 319: msb &= 0xFFFFFFFFFFFF0FFFL; 320: msb |= 0x4000; // Version 4; 321: 322: return new UUID( msb, lsb ); 323: } 324: 325: /** 326: * Returns a hex String from l, padded to n spaces. 327: */ 328: private String padHex( long l, int n ) 329: { 330: String s = Long.toHexString( l ); 331: while( s.length() < n ) 332: s = "0" + s; 333: return s; 334: } 335: 336: /** 337: * Returns the variant of the UUID 338: * 339: * This may be: 340: * 0 = Reserved for NCS backwards-compatibility 341: * 2 = Leach-Salz (supports the other methods in this class) 342: * 6 = Reserved for Microsoft backwards-compatibility 343: * 7 = (reserved for future use) 344: */ 345: public int variant() 346: { 347: // Get the top 3 bits (not all may be part of the variant) 348: int v = (int)((leastSigBits & 0xE000000000000000L) >> 61); 349: if( (v & 0x04) == 0 ) // msb of the variant is 0 350: return 0; 351: if( (v & 0x02) == 0 ) // variant is 0 1 (Leach-Salz) 352: return 2; 353: return v; // 6 or 7 354: } 355: 356: /** 357: * Returns the version # of the UUID. 358: * 359: * Valid version numbers for a variant 2 UUID are: 360: * 1 = Time based UUID 361: * 2 = DCE security UUID 362: * 3 = Name-based UUID using MD5 hashing 363: * 4 = Randomly generated UUID 364: * 5 = Name-based UUID using SHA-1 hashing 365: * 366: * @return the version number 367: */ 368: public int version() 369: { 370: return (int)((mostSigBits & 0xF000L) >> 12); 371: } 372: }