--- /dev/null
+package org.argeo.api.uuid;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.util.Objects;
+import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.Supplier;
+
+/**
+ * A provider of RFC 4122 {@link UUID}s. Only the RFC 4122 variant (also known
+ * as Leach–Salz variant) is supported. The default, returned by the
+ * {@link Supplier#get()} method MUST be a v4 UUID (random).
+ *
+ * @see UUID
+ * @see https://datatracker.ietf.org/doc/html/rfc4122
+ */
+public interface UuidFactory extends Supplier<UUID> {
+ /*
+ * TIME-BASED (version 1)
+ */
+
+ UUID timeUUID();
+
+ UUID timeUUIDwithMacAddress();
+
+ /*
+ * NAME BASED (version 3 and 5)
+ */
+
+ UUID nameUUIDv5(UUID namespace, byte[] data);
+
+ UUID nameUUIDv3(UUID namespace, byte[] data);
+
+ default UUID nameUUIDv5(UUID namespace, String name) {
+ Objects.requireNonNull(name, "Name cannot be null");
+ return nameUUIDv5(namespace, name.getBytes(UTF_8));
+ }
+
+ default UUID nameUUIDv3(UUID namespace, String name) {
+ Objects.requireNonNull(name, "Name cannot be null");
+ return nameUUIDv3(namespace, name.getBytes(UTF_8));
+ }
+
+ /*
+ * RANDOM (version 4)
+ */
+ /** A random UUID at least as good as {@link UUID#randomUUID()}. */
+ UUID randomUUIDStrong();
+
+ /**
+ * An {@link UUID} generated based on {@link ThreadLocalRandom}. Implementations
+ * should always provide it synchronously.
+ */
+ UUID randomUUIDWeak();
+
+ /**
+ * The default random {@link UUID} (v4) generator to use. This default
+ * implementation returns {@link #randomUUIDStrong()}.
+ */
+ default UUID randomUUID() {
+ return randomUUIDStrong();
+ }
+
+ /**
+ * The default {@link UUID} to provide, either random (v4) or time based (v1).
+ * This default implementations returns {@link #randomUUID()}.
+ */
+ @Override
+ default UUID get() {
+ return randomUUID();
+ }
+
+ /*
+ * STANDARD UUIDs
+ */
+
+ /** Nil UUID (00000000-0000-0000-0000-000000000000). */
+ final static UUID NIL_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000");
+ /**
+ * Standard DNS namespace ID for type 3 or 5 UUID (as defined in Appendix C of
+ * RFC4122).
+ */
+ final static UUID NS_DNS = UUID.fromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
+ /**
+ * Standard URL namespace ID for type 3 or 5 UUID (as defined in Appendix C of
+ * RFC4122).
+ */
+ final static UUID NS_URL = UUID.fromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
+ /**
+ * Standard OID namespace ID (typically an LDAP type) for type 3 or 5 UUID (as
+ * defined in Appendix C of RFC4122).
+ */
+ final static UUID NS_OID = UUID.fromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
+ /**
+ * Standard X500 namespace ID (typically an LDAP DN) for type 3 or 5 UUID (as
+ * defined in Appendix C of RFC4122).
+ */
+ final static UUID NS_X500 = UUID.fromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8");
+
+ /*
+ * UTILITIES
+ */
+
+ static boolean isRandom(UUID uuid) {
+ return uuid.version() == 4;
+ }
+
+ static boolean isTimeBased(UUID uuid) {
+ return uuid.version() == 1;
+ }
+
+ /**
+ * Whether this UUID is time based but was not generated from an IEEE 802
+ * address, as per Section 4.5 of RFC4122.
+ *
+ * @see https://datatracker.ietf.org/doc/html/rfc4122#section-4.5
+ */
+ static boolean isTimeBasedWithMacAddress(UUID uuid) {
+ if (uuid.version() == 1) {
+ return (uuid.node() & 1L) == 0;
+ } else
+ return false;
+ }
+
+ static boolean isNameBased(UUID uuid) {
+ return uuid.version() == 3 || uuid.version() == 5;
+ }
+}