1 45 46 package org.exolab.jms.common.uuid; 47 48 import java.security.SecureRandom ; 49 import java.util.HashSet ; 50 import java.util.Random ; 51 52 53 128 public final class UUIDGenerator { 129 130 137 public static final int RESOLUTION_BYTES = 16; 138 139 140 146 public static final int MAXIMUM_LENGTH = 64; 147 148 149 156 public static final int MAXIMUM_PREFIX = 28; 157 158 159 164 private static final int UUID_VARIANT_OCTET = 0x08; 165 166 167 172 private static final int UUID_VARIANT_BYTE = 0x80; 173 174 175 180 private static final int UUID_VERSION_CLOCK_OCTET = 0x01; 181 182 183 188 private static final int UUID_VERSION_CLOCK_BYTE = 0x10; 189 190 191 196 private static final int UUID_VERSION_NAME_OCTET = 0x03; 197 198 199 204 private static final int UUID_VERSION_NAME_BYTE = 0x30; 205 206 207 212 private static final int UUID_VERSION_RANDOM_CLOCK = 0x04; 213 214 215 220 private static final int UUID_VERSION_RANDOM_BYTE = 0x40; 221 222 223 228 private static final long JAVA_UUID_CLOCK_DIFF = 0x0b1d069b5400L; 229 230 231 234 private final static char[] HEX_DIGITS = new char[]{ 235 '0', '1', '2', '3', '4', '5', '6', '7', 236 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 237 238 239 246 private static int _uuidsPerTick; 247 248 249 255 private static int _uuidsThisTick; 256 257 258 263 private static long _lastClock; 264 265 266 270 private static char[] _clockSeqOctet; 271 272 273 279 private static byte[] _clockSeqByte; 280 281 282 287 private static char[] _nodeIdentifierOctet; 288 289 290 295 private static byte[] _nodeIdentifierByte; 296 297 298 303 public static String create() { 304 return String.valueOf(createTimeUUIDChars()); 305 } 306 307 308 316 public static String create(String prefix) { 317 StringBuffer buffer; 318 319 if (prefix == null) { 320 throw new IllegalArgumentException ("Argument 'prefix' is null"); 321 } 322 buffer = new StringBuffer (MAXIMUM_LENGTH - MAXIMUM_PREFIX + prefix.length()); 323 buffer.append(prefix); 324 buffer.append(createTimeUUIDChars()); 325 return buffer.toString(); 326 } 327 328 329 334 public static byte[] createBinary() { 335 return createTimeUUIDBytes(); 336 } 337 338 339 355 public static byte[] toBytes(String prefix, String identifier) 356 throws InvalidIDException { 357 358 int index; 359 char digit; 360 byte nibble; 361 byte[] bytes; 362 byte[] newBytes; 363 364 if (identifier == null) { 365 throw new IllegalArgumentException ("Argument identifier is null"); 366 } 367 if (prefix == null) { 368 throw new IllegalArgumentException ("Argument prefix is null"); 369 } 370 if (!identifier.startsWith(prefix)) { 371 throw new InvalidIDException( 372 "Invalid identifier: expected prefix " + prefix 373 + "in identifier " + identifier); 374 } 375 376 index = 0; 377 bytes = new byte[(identifier.length() - prefix.length()) / 2]; 378 for (int i = prefix.length(); i < identifier.length(); ++i) { 379 digit = identifier.charAt(i); 380 if (digit == '-') { 381 continue; 382 } 383 if (digit >= '0' && digit <= '9') { 384 nibble = (byte) ((digit - '0') << 4); 385 } else if (digit >= 'A' && digit <= 'F') { 386 nibble = (byte) ((digit - ('A' - 0x0A)) << 4); 387 } else if (digit >= 'a' && digit <= 'f') { 388 nibble = (byte) ((digit - ('a' - 0x0A)) << 4); 389 } else { 390 throw new InvalidIDException( 391 "character " + String.valueOf(digit) 392 + " encountered, expected hexadecimal digit in identifier " 393 + identifier); 394 } 395 ++i; 396 if (i == identifier.length()) { 397 throw new InvalidIDException( 398 "Invalid identifier: odd number of hexadecimal digits in " 399 + "identifier " + identifier); 400 } 401 digit = identifier.charAt(i); 402 if (digit >= '0' && digit <= '9') { 403 nibble = (byte) (nibble | (digit - '0')); 404 } else if (digit >= 'A' && digit <= 'F') { 405 nibble = (byte) (nibble | (digit - ('A' - 0x0A))); 406 } else if (digit >= 'a' && digit <= 'f') { 407 nibble = (byte) (nibble | (digit - ('a' - 0x0A))); 408 } else { 409 throw new InvalidIDException( 410 "character " + String.valueOf(digit) 411 + " encountered, expected hexadecimal digit in identifier " 412 + identifier); 413 } 414 bytes[index] = nibble; 415 ++index; 416 } 417 if (index == bytes.length) { 418 return bytes; 419 } 420 newBytes = new byte[index]; 421 while (index-- > 0) { 422 newBytes[index] = bytes[index]; 423 } 424 return newBytes; 425 } 426 427 428 443 public static byte[] toBytes(String identifier) throws InvalidIDException { 444 int index; 445 char digit; 446 byte nibble; 447 byte[] bytes; 448 byte[] newBytes; 449 450 if (identifier == null) { 451 throw new IllegalArgumentException ("Argument identifier is null"); 452 } 453 index = 0; 454 bytes = new byte[identifier.length() / 2]; 455 for (int i = 0; i < identifier.length(); ++i) { 456 digit = identifier.charAt(i); 457 if (digit == '-') 458 continue; 459 if (digit >= '0' && digit <= '9') 460 nibble = (byte) ((digit - '0') << 4); 461 else if (digit >= 'A' && digit <= 'F') 462 nibble = (byte) ((digit - ('A' - 0x0A)) << 4); 463 else if (digit >= 'a' && digit <= 'f') 464 nibble = (byte) ((digit - ('a' - 0x0A)) << 4); 465 else { 466 throw new InvalidIDException( 467 "character " + String.valueOf(digit) 468 + " encountered, expected hexadecimal digit in identifier " 469 + identifier); 470 } 471 ++i; 472 if (i == identifier.length()) { 473 throw new InvalidIDException( 474 "Invalid identifier: odd number of hexadecimal digits in " 475 + "identifier " + identifier); 476 } 477 digit = identifier.charAt(i); 478 if (digit >= '0' && digit <= '9') 479 nibble = (byte) (nibble | (digit - '0')); 480 else if (digit >= 'A' && digit <= 'F') 481 nibble = (byte) (nibble | (digit - ('A' - 0x0A))); 482 else if (digit >= 'a' && digit <= 'f') 483 nibble = (byte) (nibble | (digit - ('a' - 0x0A))); 484 else { 485 throw new InvalidIDException( 486 "character " + String.valueOf(digit) 487 + " encountered, expected hexadecimal digit in identifier " 488 + identifier); 489 } 490 bytes[index] = nibble; 491 ++index; 492 } 493 if (index == bytes.length) 494 return bytes; 495 newBytes = new byte[index]; 496 while (index-- > 0) 497 newBytes[index] = bytes[index]; 498 return newBytes; 499 } 500 501 502 513 public static String fromBytes(String prefix, byte[] bytes) { 514 StringBuffer buffer; 515 516 if (prefix == null) 517 throw new IllegalArgumentException ("Argument prefix is null"); 518 if (bytes == null || bytes.length == 0) 519 throw new IllegalArgumentException ("Argument bytes is null or an empty array"); 520 buffer = new StringBuffer (prefix); 521 for (int i = 0; i < bytes.length; ++i) { 522 buffer.append(HEX_DIGITS[(bytes[i] & 0xF0) >> 4]); 523 buffer.append(HEX_DIGITS[(bytes[i] & 0x0F)]); 524 } 525 return buffer.toString(); 526 } 527 528 529 539 public static String fromBytes(byte[] bytes) { 540 StringBuffer buffer; 541 542 if (bytes == null || bytes.length == 0) 543 throw new IllegalArgumentException ("Argument bytes is null or an empty array"); 544 buffer = new StringBuffer (); 545 for (int i = 0; i < bytes.length; ++i) { 546 buffer.append(HEX_DIGITS[(bytes[i] & 0xF0) >> 4]); 547 buffer.append(HEX_DIGITS[(bytes[i] & 0x0F)]); 548 } 549 return buffer.toString(); 550 } 551 552 553 560 public static String trim(String identifier) { 561 if (identifier == null) 562 throw new IllegalArgumentException ("Argument identifier is null"); 563 if (identifier.length() > MAXIMUM_LENGTH) 564 return identifier.substring(0, MAXIMUM_LENGTH); 565 return identifier; 566 } 567 568 569 575 public static char[] createTimeUUIDChars() { 576 long clock; 577 char[] chars; 578 long nextClock; 579 580 synchronized (UUID.class) { 582 clock = Clock.clock(); 583 while (true) { 584 if (clock > _lastClock) { 585 nextClock = _lastClock + (_uuidsThisTick / 100); 589 if (clock <= nextClock) 590 clock = Clock.synchronize(); 591 if (clock > nextClock) { 592 _uuidsThisTick = 0; 595 _lastClock = clock; 596 _uuidsPerTick = Clock.getUnsynchTicks() * 100; 599 break; 600 } 601 } 602 603 if (_uuidsThisTick + 1 < _uuidsPerTick) { 604 ++_uuidsThisTick; 607 break; 608 } 609 610 clock = Clock.synchronize(); 614 if (clock <= _lastClock) { 615 while (clock <= _lastClock) { 618 try { 620 Thread.currentThread().sleep(Clock.getUnsynchTicks()); 621 } catch (InterruptedException except) { 622 } 623 clock = Clock.synchronize(); 624 } 625 } 626 } 627 628 clock = (_lastClock + JAVA_UUID_CLOCK_DIFF) * 100 + _uuidsThisTick; 632 633 chars = new char[36]; 634 chars[0] = HEX_DIGITS[(int) ((clock >> 28) & 0x0F)]; 636 chars[1] = HEX_DIGITS[(int) ((clock >> 24) & 0x0F)]; 637 chars[2] = HEX_DIGITS[(int) ((clock >> 20) & 0x0F)]; 638 chars[3] = HEX_DIGITS[(int) ((clock >> 16) & 0x0F)]; 639 chars[4] = HEX_DIGITS[(int) ((clock >> 12) & 0x0F)]; 640 chars[5] = HEX_DIGITS[(int) ((clock >> 8) & 0x0F)]; 641 chars[6] = HEX_DIGITS[(int) ((clock >> 4) & 0x0F)]; 642 chars[7] = HEX_DIGITS[(int) (clock & 0x0F)]; 643 chars[8] = '-'; 644 chars[9] = HEX_DIGITS[(int) ((clock >> 44) & 0x0F)]; 646 chars[10] = HEX_DIGITS[(int) ((clock >> 40) & 0x0F)]; 647 chars[11] = HEX_DIGITS[(int) ((clock >> 36) & 0x0F)]; 648 chars[12] = HEX_DIGITS[(int) ((clock >> 32) & 0x0F)]; 649 chars[13] = '-'; 650 chars[14] = HEX_DIGITS[(int) (((clock >> 60) & 0x0F) | UUID_VERSION_CLOCK_OCTET)]; 652 chars[15] = HEX_DIGITS[(int) ((clock >> 56) & 0x0F)]; 653 chars[16] = HEX_DIGITS[(int) ((clock >> 52) & 0x0F)]; 654 chars[17] = HEX_DIGITS[(int) ((clock >> 48) & 0x0F)]; 655 chars[18] = '-'; 656 chars[19] = _clockSeqOctet[0]; 658 chars[20] = _clockSeqOctet[1]; 659 chars[21] = _clockSeqOctet[2]; 660 chars[22] = _clockSeqOctet[3]; 661 chars[23] = '-'; 662 chars[24] = _nodeIdentifierOctet[0]; 664 chars[25] = _nodeIdentifierOctet[1]; 665 chars[26] = _nodeIdentifierOctet[2]; 666 chars[27] = _nodeIdentifierOctet[3]; 667 chars[28] = _nodeIdentifierOctet[4]; 668 chars[29] = _nodeIdentifierOctet[5]; 669 chars[30] = _nodeIdentifierOctet[6]; 670 chars[31] = _nodeIdentifierOctet[7]; 671 chars[32] = _nodeIdentifierOctet[8]; 672 chars[33] = _nodeIdentifierOctet[9]; 673 chars[34] = _nodeIdentifierOctet[10]; 674 chars[35] = _nodeIdentifierOctet[11]; 675 } 676 return chars; 677 } 678 679 680 686 public static byte[] createTimeUUIDBytes() { 687 long clock; 688 byte[] bytes; 689 long nextClock; 690 691 synchronized (UUIDGenerator.class) { 693 clock = Clock.clock(); 694 while (true) { 695 if (clock > _lastClock) { 696 nextClock = _lastClock + (_uuidsThisTick / 100); 700 if (clock <= nextClock) { 701 clock = Clock.synchronize(); 702 } 703 if (clock > nextClock) { 704 _uuidsThisTick = 0; 707 _lastClock = clock; 708 _uuidsPerTick = Clock.getUnsynchTicks() * 100; 711 break; 712 } 713 } 714 715 if (_uuidsThisTick + 1 < _uuidsPerTick) { 716 ++_uuidsThisTick; 719 break; 720 } 721 722 clock = Clock.synchronize(); 726 if (clock <= _lastClock) { 727 while (clock <= _lastClock) { 730 try { 732 Thread.currentThread().sleep(Clock.getUnsynchTicks()); 733 } catch (InterruptedException ignore) { 734 } 735 clock = Clock.synchronize(); 736 } 737 } 738 } 739 740 clock = (_lastClock + JAVA_UUID_CLOCK_DIFF) * 100 + _uuidsThisTick; 744 745 bytes = new byte[16]; 746 bytes[0] = (byte) ((clock >> 24) & 0xFF); 748 bytes[1] = (byte) ((clock >> 16) & 0xFF); 749 bytes[2] = (byte) ((clock >> 8) & 0xFF); 750 bytes[3] = (byte) (clock & 0xFF); 751 bytes[4] = (byte) ((clock >> 40) & 0xFF); 753 bytes[5] = (byte) ((clock >> 32) & 0xFF); 754 bytes[6] = (byte) (((clock >> 60) & 0xFF) 757 | UUID_VERSION_CLOCK_BYTE); 758 bytes[7] = (byte) ((clock >> 48) & 0xFF); 759 bytes[8] = _clockSeqByte[0]; 761 bytes[9] = _clockSeqByte[1]; 762 bytes[10] = _nodeIdentifierByte[0]; 764 bytes[11] = _nodeIdentifierByte[1]; 765 bytes[12] = _nodeIdentifierByte[2]; 766 bytes[13] = _nodeIdentifierByte[3]; 767 bytes[14] = _nodeIdentifierByte[4]; 768 bytes[15] = _nodeIdentifierByte[5]; 769 } 770 return bytes; 771 } 772 773 774 782 public static boolean isLocal(byte[] uuid) { 783 if (uuid == null) 784 throw new IllegalArgumentException ("Argument uuid is null"); 785 if (uuid.length != 16) 786 return false; 787 return (uuid[10] == _nodeIdentifierByte[0] && 788 uuid[11] == _nodeIdentifierByte[1] && 789 uuid[12] == _nodeIdentifierByte[2] && 790 uuid[13] == _nodeIdentifierByte[3] && 791 uuid[14] == _nodeIdentifierByte[4] && 792 uuid[15] == _nodeIdentifierByte[5]); 793 } 794 795 802 private static void initialize() { 803 Random random = new Random (); 805 String nodeIdString; 806 long nodeIdLong; 807 String seqString; 808 int seqInt; 809 810 nodeIdLong = random.nextLong(); 814 nodeIdLong = nodeIdLong | (1 << 47); 815 816 seqInt = random.nextInt(1 << 12); 818 seqInt = seqInt & 0x1FFF; 819 820 _clockSeqOctet = new char[4]; 822 _clockSeqOctet[0] = HEX_DIGITS[(int) ((seqInt >> 12) & 0x0F)]; 823 _clockSeqOctet[1] = HEX_DIGITS[(int) ((seqInt >> 8) & 0x0F)]; 824 _clockSeqOctet[2] = HEX_DIGITS[(int) ((seqInt >> 4) & 0x0F)]; 825 _clockSeqOctet[3] = HEX_DIGITS[(int) (seqInt & 0x0F)]; 826 827 _clockSeqByte = new byte[2]; 828 _clockSeqByte[0] = (byte) ((seqInt >> 8) & 0xFF); 829 _clockSeqByte[1] = (byte) (seqInt & 0xFF); 830 831 _clockSeqOctet[0] = HEX_DIGITS[(int) ((seqInt >> 12) & 0x0F) 833 | UUID_VARIANT_OCTET]; 834 _clockSeqByte[0] = (byte) (((seqInt >> 8) & 0xFF) 835 | UUID_VARIANT_BYTE); 836 837 _nodeIdentifierOctet = new char[12]; 839 for (int i = 0; i < 12; ++i) { 840 _nodeIdentifierOctet[i] = 841 HEX_DIGITS[(int) ((nodeIdLong >> ((11 - i) * 4)) & 0x0F)]; 842 } 843 _nodeIdentifierByte = new byte[6]; 844 for (int i = 0; i < 6; ++i) { 845 _nodeIdentifierByte[i] = 846 (byte) ((nodeIdLong >> ((5 - i) * 8)) & 0xFF); 847 } 848 849 _uuidsPerTick = Clock.getUnsynchTicks() * 100; 853 } 854 855 static { 856 initialize(); 857 _uuidsThisTick = _uuidsPerTick; 859 _lastClock = Clock.clock(); 860 } 861 862 863 public static void main(String [] args) { 864 long clock; 865 HashSet hash; 866 String id; 867 int count = 1000000; 868 869 for (int i = 0; i < 10; ++i) { 870 System.out.println(create()); 871 } 872 clock = System.currentTimeMillis(); 873 hash = new HashSet (count / 100, 100); 874 for (int i = 0; i < count; ++i) { 875 if ((i % 10000) == 0) 876 System.out.println("Checked " + i); 877 id = create(); 878 if (hash.contains(id)) 879 System.out.println("Duplicate id " + id); 880 else 881 hash.add(id); 882 } 883 clock = System.currentTimeMillis() - clock; 884 System.out.println("Generated " + count + " UUIDs in " + clock + "ms"); 885 } 886 887 891 public static class InvalidIDException extends Exception { 892 893 public InvalidIDException(String message) { 894 super(message); 895 } 896 } 897 898 } 899 | Popular Tags |