diff --git a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/UUIDFactory.java b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/UUIDFactory.java index d0e5b3f8..6c3b282f 100644 --- a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/UUIDFactory.java +++ b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/util/UUIDFactory.java @@ -38,21 +38,27 @@ import java.security.SecureRandom; import java.util.*; /** - * A factory for creating UUIDs not directly supported by {@link java.util.UUID}. + * A factory for creating {@code UUID}s not directly supported by {@link java.util.UUID java.util.UUID}. *
- * This class can create - * version 1 time based, using either IEEE 802 (mac) address or random "node" value - * and version 5 SHA1 hash based UUIDs. + * This class can create version 1 time based {@code UUID}s, using either IEEE 802 (mac) address or random "node" value + * as well as version 5 SHA1 hash based {@code UUID}s. *
*- * The node value for version 1 UUIDs will, by default, reflect the IEEE 802 (mac) address of one of + * The timestamp value for version 1 {@code UUID}s will use a high precision clock, when available to the Java VM. + * If the Java system clock does not offer the needed precision, the timestamps will fall back to 100-nanosecond + * increments, to avoid duplicates. + *
+ *+ * + * The node value for version 1 {@code UUID}s will, by default, reflect the IEEE 802 (mac) address of one of * the network interfaces of the local computer. * This node value can be manually overridden by setting * the system property {@code "com.twelvemonkeys.util.UUID.node"} to a valid IEEE 802 address, on the form * {@code 12:34:56:78:9a:bc} or {@code 12-34-45-78-9a-bc}. *
*- * The node value for the random "node" based version 1 UUIDs will be stable for the lifetime of the VM. + * + * The node value for the random "node" based version 1 {@code UUID}s will be stable for the lifetime of the VM. *
* * @author Harald Kuhr @@ -67,12 +73,12 @@ public final class UUIDFactory { private static final String NODE_PROPERTY = "com.twelvemonkeys.util.UUID.node"; /** - * Nil UUID: {@code "00000000-0000-0000-0000-000000000000"}. + * The Nil UUID: {@code "00000000-0000-0000-0000-000000000000"}. * * The nil UUID is special form of UUID that is specified to have all - * 128 bits set to zero. Not particularly useful. + * 128 bits set to zero. Not particularly useful, unless as a placeholder or template. * - * @see RFC 4122 + * @see RFC 4122 4.1.7. Nil UUID */ public static final UUID NIL = new UUID(0l, 0l); @@ -86,34 +92,7 @@ public final class UUIDFactory { static final long SECURE_RANDOM_NODE = getSecureRandomNode(); private static long getSecureRandomNode() { - /* - Obtain a 47-bit cryptographic quality random - number and use it as the low 47 bits of the node ID, with the least - significant bit of the first octet of the node ID set to one. This - bit is the unicast/multicast bit, which will never be set in IEEE 802 - addresses obtained from network cards. Hence, there can never be a - conflict between UUIDs generated by machines with and without network - cards. (Recall that the IEEE 802 spec talks about transmission - order) - */ - - /* - In addition, items such as the computer's name and the name of the - operating system, while not strictly speaking random, will help - differentiate the results from those obtained by other systems. - - The exact algorithm to generate a node ID using these data is system - specific, because both the data available and the functions to obtain - them are often very system specific. A generic approach, however, is - to accumulate as many sources as possible into a buffer, use a - message digest such as MD5 [4] or SHA-1 [8], take an arbitrary 6 - bytes from the hash value, and set the multicast bit as described - above. - */ - - // TODO: Verify that nextLong is still cryptographically strong after the bit masking - // TODO: Consider using the hashing approach above - + // Creates a completely random "node" value, with the unicast bit set to 1, as outlined in RFC 4122. return 1l << 40 | SECURE_RANDOM.nextLong() & 0xffffffffffffl; } @@ -171,11 +150,20 @@ public final class UUIDFactory { private UUIDFactory() {} - // See also http://tools.ietf.org/html/rfc4122#appendix-B - // See http://tools.ietf.org/html/rfc4122: 4.3. Algorithm for Creating a Name-Based UUID - // TODO: Naming (of the method) - // TODO: Read up on creating these UUIDs in RFC, mentions something about UUID for namespace as input..? - static UUID nameUUIDFromBytesSHA1(byte[] name) { + /** + * Creates a type 5 (name based) {@code UUID} based on the specified byte array. + * This method is effectively identical to {@link UUID#nameUUIDFromBytes}, except that this method + * uses a SHA1 hash instead of the MD5 hash used in the type 3 {@code UUID}s. + * RFC 4122 states that "SHA-1 is preferred" over MD5, without giving a reason for why. + * + * @param name a byte array to be used to construct a {@code UUID} + * @return a {@code UUID} generated from the specified array. + * + * @see RFC 4122 4.3. Algorithm for Creating a Name-Based UUID + * @see RFC 4122 appendix A + * @see UUID#nameUUIDFromBytes(byte[]) + */ + public static UUID nameUUIDv5FromBytes(byte[] name) { // Based on code from OpenJDK UUID#nameUUIDFromBytes + private byte[] constructor MessageDigest md; @@ -207,26 +195,39 @@ public final class UUIDFactory { return new UUID(msb, lsb); } - // Creatse version 1 node based UUIDs as specified in rfc422 - // See http://tools.ietf.org/html/rfc4122#appendix-B - // See http://en.wikipedia.org/wiki/MAC_address - // TODO: Naming (of the method) - static UUID timeNodeBasedV1() { + /** + * Creates a version 1 time (and node) based {@code UUID}. + * The node part is by default the IEE 802 (mac) address of one of the network cards of the current machine. + * + * @return a {@code UUID} based on the current time and the node address of this computer. + * @see RFC 4122 4.2. Algorithms for Creating a Time-Based UUID + * @see IEEE 802 (mac) address + * @see Overriding the node address + * + * @throws IllegalStateException if the IEEE 802 (mac) address of the computer (node) cannot be found. + */ + public static UUID timeNodeBasedUUID() { if (MAC_ADDRESS_NODE == -1) { - // TODO: OR fall back to Random?? throw new IllegalStateException("Could not determine IEEE 802 (mac) address for node"); } return new UUID(createTimeAndVersion(), createClockSeqAndNode(MAC_ADDRESS_NODE)); } - // Creates version 1 "node" based UUIDs, using 47 bit secure random number + lsb of first octet - // (unicast/multicast bit) set to 1 as described in rfc422: 4.5. Node IDs that Do Not Identify the Host - // See http://tools.ietf.org/html/rfc4122#appendix-B - // TODO: Naming (of the method) - // TODO: Document that these can never clash with node based v1 UUIDs due to unicast/multicast bit - // However, no uniqueness between multiple mavhines/vms/nodes can be guaranteed. - static UUID timeRandomBasedV1() { + /** + * Creates a version 1 time based {@code UUID} with the node part replaced by a random based value. + * The node part is computed using a 47 bit secure random number + lsb of first octet (unicast/multicast bit) set to 1. + * These {@code UUID}s can never clash with "real" node based version 1 {@code UUID}s due to the difference in + * the unicast/multicast bit, however, no uniqueness between multiple machines/vms/nodes can be guaranteed. + * + * @return a {@code UUID} based on the current time and a random generated "node" value. + * @see RFC 4122 4.5. Node IDs that Do Not Identify the Host + * @see RFC 4122 Appendix A + * @see Lifetime of random node value + * + * @throws IllegalStateException if the IEEE 802 (mac) address of the computer (node) cannot be found. + */ + public static UUID timeRandomBasedUUID() { return new UUID(createTimeAndVersion(), createClockSeqAndNode(SECURE_RANDOM_NODE)); } @@ -261,7 +262,7 @@ public final class UUIDFactory { * @return a comparator that compares UUIDs as 128 bit unsigned entities. * * @see java.lang.UUID compareTo() does not do an unsigned compare - * @see + * @see RFC 4122 Appendix A */ public static Comparator