com.seeq.utilities.UUIDs Maven / Gradle / Ivy
package com.seeq.utilities;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.Clock;
import java.util.Arrays;
import java.util.Base64;
import java.util.UUID;
import java.util.regex.Pattern;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
/**
* Collection of methods for interacting with and generating UUIDs
*/
public class UUIDs {
public static final Pattern ID_PATTERN = Pattern.compile("\\p{XDigit}{8}-(\\p{XDigit}{4}-){3}\\p{XDigit}{12}");
private static final Generator GENERATOR = new Generator(Clock.systemUTC());
/**
* Generates a random base64 guid
*
* @return the random base64 guid
*/
public static String randomBase64Guid() {
UUID uuid = UUID.randomUUID();
byte[] src = ByteBuffer.wrap(new byte[16])
.putLong(uuid.getMostSignificantBits())
.putLong(uuid.getLeastSignificantBits())
.array();
return Base64.getUrlEncoder().withoutPadding().encodeToString(src);
}
/**
* Generates a time ordered UUID, also known as UUID v6. This type of UUID is well-suited for
* database primary keys, since it starts with a monotonically increasing timestamp.
*
*
* Our implementation makes the least significant bits completely random, since we have no use for a node identifier
* or clock sequence, and we have some code that depends on the LSB being random. This also means that we don't
* need to block when two entries have the same millisecond timestamp, as the randomness will distinguish them.
*
*
* See Peabody for more information.
*/
public static UUID timeOrderedUUID() {
return GENERATOR.next();
}
/**
* Generates a UUID from a concatenation of UUIDs.
*/
public static UUID fromConcatenatedUUIDs(UUID... uuids) {
Preconditions.checkArgument(uuids.length > 0, "Must have at least one UUID to concatenate");
return UUID.nameUUIDFromBytes(
(Arrays.stream(uuids).map(UUID::toString).reduce("", String::concat))
.getBytes(StandardCharsets.UTF_8));
}
@VisibleForTesting
static class Generator {
private static final long EPOCH_OFFSET = -122192928000000000L;
private final SecureRandom random = new SecureRandom();
private final Clock clock;
public Generator(Clock clock) {
this.clock = clock;
}
public UUID next() {
long t = this.clock.millis() * 10_000 - EPOCH_OFFSET;
long msb = ((t << 4) & 0x0ffffffffffff000L) | 0x0000000000006000L | (t & 0x0000000000000fffL);
long lsb = (this.random.nextLong() & 0x3fffffffffffffffL) | 0x8000000000000000L;
return new UUID(msb, lsb);
}
}
}