Skip to content

Instantly share code, notes, and snippets.

@richardstephens
Created November 8, 2020 20:41
Show Gist options
  • Save richardstephens/d974260678cee5ee2906e71f7f9a8ab4 to your computer and use it in GitHub Desktop.
Save richardstephens/d974260678cee5ee2906e71f7f9a8ab4 to your computer and use it in GitHub Desktop.

Revisions

  1. richardstephens created this gist Nov 8, 2020.
    82 changes: 82 additions & 0 deletions RichUuid.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    package dev.richst.libs.richuuid;

    import java.io.*;
    import java.util.Base64;
    import java.util.UUID;

    public class RichUuid {
    static byte[] uuidToByteArray(UUID uuid) {
    try {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(bos);
    dos.writeLong(uuid.getMostSignificantBits());
    dos.writeLong(uuid.getLeastSignificantBits());
    dos.write(2);
    dos.flush();
    return bos.toByteArray();
    } catch (IOException ex) {
    // this should never be thrown, and there is no sensible way to handle it
    throw new IllegalStateException(
    "IO exception occurred working on memory backed streams", ex);
    }
    }

    static UUID byteArrayToUuid(byte[] uuidBytes) {
    try {
    ByteArrayInputStream bis = new ByteArrayInputStream(uuidBytes);
    DataInputStream dis = new DataInputStream(bis);
    long msb = dis.readLong();
    long lsb = dis.readLong();
    return new UUID(msb, lsb);
    } catch (IOException ex) {
    // this should never be thrown, and there is no sensible way to handle it
    throw new IllegalStateException(
    "IO exception occurred working on memory backed streams", ex);
    }
    }

    public static String fromUUID(UUID uuid) {
    byte[] uuidBytes = uuidToByteArray(uuid);
    byte[] uuidBytesWithChecksum = new byte[18];
    int checksum = 0;
    for (int ii = 0; ii < 16; ii++) {
    uuidBytesWithChecksum[ii] = uuidBytes[ii];
    checksum += uuidBytes[ii] & 0xFF;
    }
    uuidBytesWithChecksum[16] = 0;
    uuidBytesWithChecksum[17] = (byte) (checksum % 256);
    return Base64.getUrlEncoder().encodeToString(uuidBytesWithChecksum);
    }

    public static String generate() {
    return fromUUID(UUID.randomUUID());
    }

    private static boolean validateChecksum(byte[] uuidBytesWithChecksum) {
    int checksum = 0;
    for (int ii = 0; ii < 17; ii++) {
    checksum += uuidBytesWithChecksum[ii] & 0xFF;
    }
    return ((byte) checksum) == uuidBytesWithChecksum[17];
    }

    private static void assertChecksumValid(byte[] uuidBytes) {
    if (!validateChecksum(uuidBytes)) {
    throw new InvalidRichUuidException("checksum invalid");
    }
    }

    public static UUID toUUID(String richUuid) {
    byte[] uuidBytesWithChecksum;
    try {
    uuidBytesWithChecksum = Base64.getUrlDecoder().decode(richUuid);
    } catch (IllegalArgumentException ex) {
    throw new InvalidRichUuidException("Could not base64 decode richUuid", ex);
    }
    if (uuidBytesWithChecksum.length != 18) {
    throw new InvalidRichUuidException("UUID length invalid");
    }
    assertChecksumValid(uuidBytesWithChecksum);
    return byteArrayToUuid(uuidBytesWithChecksum);
    }
    }