1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.util; 19 20import java.io.IOException; 21import java.io.ObjectInputStream; 22import java.io.Serializable; 23import java.nio.ByteOrder; 24import java.security.MessageDigest; 25import java.security.NoSuchAlgorithmException; 26import java.security.SecureRandom; 27import libcore.io.Memory; 28 29/** 30 * UUID is an immutable representation of a 128-bit universally unique 31 * identifier (UUID). 32 * <p> 33 * There are multiple, variant layouts of UUIDs, but this class is based upon 34 * variant 2 of <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>, the 35 * Leach-Salz variant. This class can be used to model alternate variants, but 36 * most of the methods will be unsupported in those cases; see each method for 37 * details. 38 * 39 * @since 1.5 40 */ 41public final class UUID implements Serializable, Comparable<UUID> { 42 43 private static final long serialVersionUID = -4856846361193249489L; 44 45 private static SecureRandom rng; 46 47 private long mostSigBits; 48 private long leastSigBits; 49 50 private transient int variant; 51 private transient int version; 52 private transient long timestamp; 53 private transient int clockSequence; 54 private transient long node; 55 private transient int hash; 56 57 /** 58 * <p> 59 * Constructs an instance with the specified bits. 60 * 61 * @param mostSigBits 62 * The 64 most significant bits of the UUID. 63 * @param leastSigBits 64 * The 64 least significant bits of the UUID. 65 */ 66 public UUID(long mostSigBits, long leastSigBits) { 67 this.mostSigBits = mostSigBits; 68 this.leastSigBits = leastSigBits; 69 init(); 70 } 71 72 /** 73 * <p> 74 * Sets up the transient fields of this instance based on the current values 75 * of the {@code mostSigBits} and {@code leastSigBits} fields. 76 */ 77 private void init() { 78 // setup hash field 79 int msbHash = (int) (mostSigBits ^ (mostSigBits >>> 32)); 80 int lsbHash = (int) (leastSigBits ^ (leastSigBits >>> 32)); 81 hash = msbHash ^ lsbHash; 82 83 // setup variant field 84 if ((leastSigBits & 0x8000000000000000L) == 0) { 85 // MSB0 not set, NCS backwards compatibility variant 86 variant = 0; 87 } else if ((leastSigBits & 0x4000000000000000L) != 0) { 88 // MSB1 set, either MS reserved or future reserved 89 variant = (int) ((leastSigBits & 0xE000000000000000L) >>> 61); 90 } else { 91 // MSB1 not set, RFC 4122 variant 92 variant = 2; 93 } 94 95 // setup version field 96 version = (int) ((mostSigBits & 0x000000000000F000) >>> 12); 97 98 if (variant != 2 && version != 1) { 99 return; 100 } 101 102 // setup timestamp field 103 long timeLow = (mostSigBits & 0xFFFFFFFF00000000L) >>> 32; 104 long timeMid = (mostSigBits & 0x00000000FFFF0000L) << 16; 105 long timeHigh = (mostSigBits & 0x0000000000000FFFL) << 48; 106 timestamp = timeLow | timeMid | timeHigh; 107 108 // setup clock sequence field 109 clockSequence = (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); 110 111 // setup node field 112 node = (leastSigBits & 0x0000FFFFFFFFFFFFL); 113 } 114 115 /** 116 * <p> 117 * Generates a variant 2, version 4 (randomly generated number) UUID as per 118 * <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 119 * 120 * @return an UUID instance. 121 */ 122 public static UUID randomUUID() { 123 byte[] data = new byte[16]; 124 // lock on the class to protect lazy init 125 synchronized (UUID.class) { 126 if (rng == null) { 127 rng = new SecureRandom(); 128 } 129 } 130 rng.nextBytes(data); 131 return makeUuid(data, 4); 132 } 133 134 /** 135 * <p> 136 * Generates a variant 2, version 3 (name-based, MD5-hashed) UUID as per <a 137 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 138 * 139 * @param name 140 * the name used as byte array to create an UUID. 141 * @return an UUID instance. 142 */ 143 public static UUID nameUUIDFromBytes(byte[] name) { 144 if (name == null) { 145 throw new NullPointerException("name == null"); 146 } 147 try { 148 MessageDigest md = MessageDigest.getInstance("MD5"); 149 return makeUuid(md.digest(name), 3); 150 } catch (NoSuchAlgorithmException e) { 151 throw new AssertionError(e); 152 } 153 } 154 155 private static UUID makeUuid(byte[] hash, int version) { 156 long msb = Memory.peekLong(hash, 0, ByteOrder.BIG_ENDIAN); 157 long lsb = Memory.peekLong(hash, 8, ByteOrder.BIG_ENDIAN); 158 // Set the version field. 159 msb &= ~(0xfL << 12); 160 msb |= ((long) version) << 12; 161 // Set the variant field to 2. Note that the variant field is variable-width, 162 // so supporting other variants is not just a matter of changing the constant 2 below! 163 lsb &= ~(0x3L << 62); 164 lsb |= 2L << 62; 165 return new UUID(msb, lsb); 166 } 167 168 /** 169 * <p> 170 * Parses a UUID string with the format defined by {@link #toString()}. 171 * 172 * @param uuid 173 * the UUID string to parse. 174 * @return an UUID instance. 175 * @throws NullPointerException 176 * if {@code uuid} is {@code null}. 177 * @throws IllegalArgumentException 178 * if {@code uuid} is not formatted correctly. 179 */ 180 public static UUID fromString(String uuid) { 181 if (uuid == null) { 182 throw new NullPointerException("uuid == null"); 183 } 184 185 String[] parts = uuid.split("-"); 186 if (parts.length != 5) { 187 throw new IllegalArgumentException("Invalid UUID: " + uuid); 188 } 189 190 long m1 = Long.parsePositiveLong(parts[0], 16); 191 long m2 = Long.parsePositiveLong(parts[1], 16); 192 long m3 = Long.parsePositiveLong(parts[2], 16); 193 194 long lsb1 = Long.parsePositiveLong(parts[3], 16); 195 long lsb2 = Long.parsePositiveLong(parts[4], 16); 196 197 long msb = (m1 << 32) | (m2 << 16) | m3; 198 long lsb = (lsb1 << 48) | lsb2; 199 200 return new UUID(msb, lsb); 201 } 202 203 /** 204 * <p> 205 * The 64 least significant bits of the UUID. 206 * 207 * @return the 64 least significant bits. 208 */ 209 public long getLeastSignificantBits() { 210 return leastSigBits; 211 } 212 213 /** 214 * <p> 215 * The 64 most significant bits of the UUID. 216 * 217 * @return the 64 most significant bits. 218 */ 219 public long getMostSignificantBits() { 220 return mostSigBits; 221 } 222 223 /** 224 * <p> 225 * The version of the variant 2 UUID as per <a 226 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. If the variant 227 * is not 2, then the version will be 0. 228 * <ul> 229 * <li>1 - Time-based UUID</li> 230 * <li>2 - DCE Security UUID</li> 231 * <li>3 - Name-based with MD5 hashing UUID ({@link #nameUUIDFromBytes(byte[])})</li> 232 * <li>4 - Randomly generated UUID ({@link #randomUUID()})</li> 233 * <li>5 - Name-based with SHA-1 hashing UUID</li> 234 * </ul> 235 * 236 * @return an {@code int} value. 237 */ 238 public int version() { 239 return version; 240 } 241 242 /** 243 * <p> 244 * The variant of the UUID as per <a 245 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 246 * <ul> 247 * <li>0 - Reserved for NCS compatibility</li> 248 * <li>2 - RFC 4122/Leach-Salz</li> 249 * <li>6 - Reserved for Microsoft Corporation compatibility</li> 250 * <li>7 - Reserved for future use</li> 251 * </ul> 252 * 253 * @return an {@code int} value. 254 */ 255 public int variant() { 256 return variant; 257 } 258 259 /** 260 * <p> 261 * The timestamp value of the version 1, variant 2 UUID as per <a 262 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 263 * 264 * @return a {@code long} value. 265 * @throws UnsupportedOperationException 266 * if {@link #version()} is not 1. 267 */ 268 public long timestamp() { 269 if (version != 1) { 270 throw new UnsupportedOperationException(); 271 } 272 return timestamp; 273 } 274 275 /** 276 * <p> 277 * The clock sequence value of the version 1, variant 2 UUID as per <a 278 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 279 * 280 * @return a {@code long} value. 281 * @throws UnsupportedOperationException 282 * if {@link #version()} is not 1. 283 */ 284 public int clockSequence() { 285 if (version != 1) { 286 throw new UnsupportedOperationException(); 287 } 288 return clockSequence; 289 } 290 291 /** 292 * <p> 293 * The node value of the version 1, variant 2 UUID as per <a 294 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 295 * 296 * @return a {@code long} value. 297 * @throws UnsupportedOperationException 298 * if {@link #version()} is not 1. 299 */ 300 public long node() { 301 if (version != 1) { 302 throw new UnsupportedOperationException(); 303 } 304 return node; 305 } 306 307 /** 308 * <p> 309 * Compares this UUID to the specified UUID. The natural ordering of UUIDs 310 * is based upon the value of the bits from most significant to least 311 * significant. 312 * 313 * @param uuid 314 * the UUID to compare to. 315 * @return a value of -1, 0 or 1 if this UUID is less than, equal to or 316 * greater than {@code uuid}. 317 */ 318 public int compareTo(UUID uuid) { 319 if (uuid == this) { 320 return 0; 321 } 322 323 if (this.mostSigBits != uuid.mostSigBits) { 324 return this.mostSigBits < uuid.mostSigBits ? -1 : 1; 325 } 326 327 // assert this.mostSigBits == uuid.mostSigBits; 328 329 if (this.leastSigBits != uuid.leastSigBits) { 330 return this.leastSigBits < uuid.leastSigBits ? -1 : 1; 331 } 332 333 // assert this.leastSigBits == uuid.leastSigBits; 334 335 return 0; 336 } 337 338 /** 339 * <p> 340 * Compares this UUID to another object for equality. If {@code object} 341 * is not {@code null}, is a UUID instance, and all bits are equal, then 342 * {@code true} is returned. 343 * 344 * @param object 345 * the {@code Object} to compare to. 346 * @return {@code true} if this UUID is equal to {@code object} 347 * or {@code false} if not. 348 */ 349 @Override 350 public boolean equals(Object object) { 351 if (object == null) { 352 return false; 353 } 354 355 if (this == object) { 356 return true; 357 } 358 359 if (!(object instanceof UUID)) { 360 return false; 361 } 362 363 UUID that = (UUID) object; 364 365 return (this.leastSigBits == that.leastSigBits) 366 && (this.mostSigBits == that.mostSigBits); 367 } 368 369 /** 370 * <p> 371 * Returns a hash value for this UUID that is consistent with the 372 * {@link #equals(Object)} method. 373 * 374 * @return an {@code int} value. 375 */ 376 @Override 377 public int hashCode() { 378 return hash; 379 } 380 381 /** 382 * <p> 383 * Returns a string representation of this UUID in the following format, as 384 * per <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 385 * 386 * <pre> 387 * UUID = time-low "-" time-mid "-" 388 * time-high-and-version "-" 389 * clock-seq-and-reserved 390 * clock-seq-low "-" node 391 * time-low = 4hexOctet 392 * time-mid = 2hexOctet 393 * time-high-and-version = 2hexOctet 394 * clock-seq-and-reserved = hexOctet 395 * clock-seq-low = hexOctet 396 * node = 6hexOctet 397 * hexOctet = hexDigit hexDigit 398 * hexDigit = 399 * "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / 400 * "a" / "b" / "c" / "d" / "e" / "f" / 401 * "A" / "B" / "C" / "D" / "E" / "F" 402 * </pre> 403 * 404 * @return a String instance. 405 */ 406 @Override 407 public String toString() { 408 StringBuilder builder = new StringBuilder(36); 409 String msbStr = Long.toHexString(mostSigBits); 410 if (msbStr.length() < 16) { 411 int diff = 16 - msbStr.length(); 412 for (int i = 0; i < diff; i++) { 413 builder.append('0'); 414 } 415 } 416 builder.append(msbStr); 417 builder.insert(8, '-'); 418 builder.insert(13, '-'); 419 builder.append('-'); 420 String lsbStr = Long.toHexString(leastSigBits); 421 if (lsbStr.length() < 16) { 422 int diff = 16 - lsbStr.length(); 423 for (int i = 0; i < diff; i++) { 424 builder.append('0'); 425 } 426 } 427 builder.append(lsbStr); 428 builder.insert(23, '-'); 429 return builder.toString(); 430 } 431 432 /** 433 * <p> 434 * Resets the transient fields to match the behavior of the constructor. 435 * 436 * @param in 437 * the {@code InputStream} to read from. 438 * @throws IOException 439 * if {@code in} throws it. 440 * @throws ClassNotFoundException 441 * if {@code in} throws it. 442 */ 443 private void readObject(ObjectInputStream in) throws IOException, 444 ClassNotFoundException { 445 // read in non-transient fields 446 in.defaultReadObject(); 447 // setup transient fields 448 init(); 449 } 450} 451