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 int[] position = new int[5]; 186 int lastPosition = 1; 187 int startPosition = 0; 188 189 int i = 0; 190 for (; i < position.length && lastPosition > 0; i++) { 191 position[i] = uuid.indexOf("-", startPosition); 192 lastPosition = position[i]; 193 startPosition = position[i] + 1; 194 } 195 196 // should have and only can have four "-" in UUID 197 if (i != position.length || lastPosition != -1) { 198 throw new IllegalArgumentException("Invalid UUID: " + uuid); 199 } 200 201 long m1 = Long.parseLong(uuid.substring(0, position[0]), 16); 202 long m2 = Long.parseLong(uuid.substring(position[0] + 1, position[1]), 16); 203 long m3 = Long.parseLong(uuid.substring(position[1] + 1, position[2]), 16); 204 205 long lsb1 = Long.parseLong(uuid.substring(position[2] + 1, position[3]), 16); 206 long lsb2 = Long.parseLong(uuid.substring(position[3] + 1), 16); 207 208 long msb = (m1 << 32) | (m2 << 16) | m3; 209 long lsb = (lsb1 << 48) | lsb2; 210 211 return new UUID(msb, lsb); 212 } 213 214 /** 215 * <p> 216 * The 64 least significant bits of the UUID. 217 * 218 * @return the 64 least significant bits. 219 */ 220 public long getLeastSignificantBits() { 221 return leastSigBits; 222 } 223 224 /** 225 * <p> 226 * The 64 most significant bits of the UUID. 227 * 228 * @return the 64 most significant bits. 229 */ 230 public long getMostSignificantBits() { 231 return mostSigBits; 232 } 233 234 /** 235 * <p> 236 * The version of the variant 2 UUID as per <a 237 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. If the variant 238 * is not 2, then the version will be 0. 239 * <ul> 240 * <li>1 - Time-based UUID</li> 241 * <li>2 - DCE Security UUID</li> 242 * <li>3 - Name-based with MD5 hashing UUID ({@link #nameUUIDFromBytes(byte[])})</li> 243 * <li>4 - Randomly generated UUID ({@link #randomUUID()})</li> 244 * <li>5 - Name-based with SHA-1 hashing UUID</li> 245 * </ul> 246 * 247 * @return an {@code int} value. 248 */ 249 public int version() { 250 return version; 251 } 252 253 /** 254 * <p> 255 * The variant of the UUID as per <a 256 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 257 * <ul> 258 * <li>0 - Reserved for NCS compatibility</li> 259 * <li>2 - RFC 4122/Leach-Salz</li> 260 * <li>6 - Reserved for Microsoft Corporation compatibility</li> 261 * <li>7 - Reserved for future use</li> 262 * </ul> 263 * 264 * @return an {@code int} value. 265 */ 266 public int variant() { 267 return variant; 268 } 269 270 /** 271 * <p> 272 * The timestamp value of the version 1, variant 2 UUID as per <a 273 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 274 * 275 * @return a {@code long} value. 276 * @throws UnsupportedOperationException 277 * if {@link #version()} is not 1. 278 */ 279 public long timestamp() { 280 if (version != 1) { 281 throw new UnsupportedOperationException(); 282 } 283 return timestamp; 284 } 285 286 /** 287 * <p> 288 * The clock sequence value of the version 1, variant 2 UUID as per <a 289 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 290 * 291 * @return a {@code long} value. 292 * @throws UnsupportedOperationException 293 * if {@link #version()} is not 1. 294 */ 295 public int clockSequence() { 296 if (version != 1) { 297 throw new UnsupportedOperationException(); 298 } 299 return clockSequence; 300 } 301 302 /** 303 * <p> 304 * The node value of the version 1, variant 2 UUID as per <a 305 * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 306 * 307 * @return a {@code long} value. 308 * @throws UnsupportedOperationException 309 * if {@link #version()} is not 1. 310 */ 311 public long node() { 312 if (version != 1) { 313 throw new UnsupportedOperationException(); 314 } 315 return node; 316 } 317 318 /** 319 * <p> 320 * Compares this UUID to the specified UUID. The natural ordering of UUIDs 321 * is based upon the value of the bits from most significant to least 322 * significant. 323 * 324 * @param uuid 325 * the UUID to compare to. 326 * @return a value of -1, 0 or 1 if this UUID is less than, equal to or 327 * greater than {@code uuid}. 328 */ 329 public int compareTo(UUID uuid) { 330 if (uuid == this) { 331 return 0; 332 } 333 334 if (this.mostSigBits != uuid.mostSigBits) { 335 return this.mostSigBits < uuid.mostSigBits ? -1 : 1; 336 } 337 338 assert this.mostSigBits == uuid.mostSigBits; 339 340 if (this.leastSigBits != uuid.leastSigBits) { 341 return this.leastSigBits < uuid.leastSigBits ? -1 : 1; 342 } 343 344 assert this.leastSigBits == uuid.leastSigBits; 345 346 return 0; 347 } 348 349 /** 350 * <p> 351 * Compares this UUID to another object for equality. If {@code object} 352 * is not {@code null}, is a UUID instance, and all bits are equal, then 353 * {@code true} is returned. 354 * 355 * @param object 356 * the {@code Object} to compare to. 357 * @return {@code true} if this UUID is equal to {@code object} 358 * or {@code false} if not. 359 */ 360 @Override 361 public boolean equals(Object object) { 362 if (object == null) { 363 return false; 364 } 365 366 if (this == object) { 367 return true; 368 } 369 370 if (!(object instanceof UUID)) { 371 return false; 372 } 373 374 UUID that = (UUID) object; 375 376 return (this.leastSigBits == that.leastSigBits) 377 && (this.mostSigBits == that.mostSigBits); 378 } 379 380 /** 381 * <p> 382 * Returns a hash value for this UUID that is consistent with the 383 * {@link #equals(Object)} method. 384 * 385 * @return an {@code int} value. 386 */ 387 @Override 388 public int hashCode() { 389 return hash; 390 } 391 392 /** 393 * <p> 394 * Returns a string representation of this UUID in the following format, as 395 * per <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. 396 * 397 * <pre> 398 * UUID = time-low "-" time-mid "-" 399 * time-high-and-version "-" 400 * clock-seq-and-reserved 401 * clock-seq-low "-" node 402 * time-low = 4hexOctet 403 * time-mid = 2hexOctet 404 * time-high-and-version = 2hexOctet 405 * clock-seq-and-reserved = hexOctet 406 * clock-seq-low = hexOctet 407 * node = 6hexOctet 408 * hexOctet = hexDigit hexDigit 409 * hexDigit = 410 * "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / 411 * "a" / "b" / "c" / "d" / "e" / "f" / 412 * "A" / "B" / "C" / "D" / "E" / "F" 413 * </pre> 414 * 415 * @return a String instance. 416 */ 417 @Override 418 public String toString() { 419 StringBuilder builder = new StringBuilder(36); 420 String msbStr = Long.toHexString(mostSigBits); 421 if (msbStr.length() < 16) { 422 int diff = 16 - msbStr.length(); 423 for (int i = 0; i < diff; i++) { 424 builder.append('0'); 425 } 426 } 427 builder.append(msbStr); 428 builder.insert(8, '-'); 429 builder.insert(13, '-'); 430 builder.append('-'); 431 String lsbStr = Long.toHexString(leastSigBits); 432 if (lsbStr.length() < 16) { 433 int diff = 16 - lsbStr.length(); 434 for (int i = 0; i < diff; i++) { 435 builder.append('0'); 436 } 437 } 438 builder.append(lsbStr); 439 builder.insert(23, '-'); 440 return builder.toString(); 441 } 442 443 /** 444 * <p> 445 * Resets the transient fields to match the behavior of the constructor. 446 * 447 * @param in 448 * the {@code InputStream} to read from. 449 * @throws IOException 450 * if {@code in} throws it. 451 * @throws ClassNotFoundException 452 * if {@code in} throws it. 453 */ 454 private void readObject(ObjectInputStream in) throws IOException, 455 ClassNotFoundException { 456 // read in non-transient fields 457 in.defaultReadObject(); 458 // setup transient fields 459 init(); 460 } 461} 462