package io.vivarium.util; import java.io.Serializable; import com.google.common.io.BaseEncoding; import com.google.common.primitives.Longs; import com.googlecode.gwtstreamer.client.Streamable; /** * Guava based UUID implementation for compatibility with GWT. This class can be used as a plug in replacement for the * standard java.util.UUID, but it's worth noting that GWT does not support SecureRandom, so this UUID implementation * does not provide the same guarantee of entropy. It's much preferable to generate UUIDs from the java.util.UUID and * convert into this class before sending to GWT if possible. * * @author John H. Uckele */ public class UUID implements Serializable, Streamable { private static final long serialVersionUID = -3965221404087809719L; private static final BaseEncoding ENCODING = BaseEncoding.base16().lowerCase(); private final long _long1; private final long _long2; private UUID() { _long1 = 0; _long2 = 0; } private UUID(long long1, long long2) { _long1 = long1; _long2 = long2; } public static UUID randomUUID() { // This is compatible with a real UUID, but it is not cryptographically secure. In an isolated environment, the // cycle time of this UUID generator is only 2^64-1, but there are also 2^64-1 different possible cycles, so // collisions should remain improbable. long long1 = (Rand.getInstance().getRandomLong() | 0b00000000_00000000_00000000_00000000_00000000_00000000_01000000_00000000L) & 0b11111111_11111111_11111111_11111111_11111111_11111111_01001111_11111111L; long long2 = (Rand.getInstance().getRandomLong2() | 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L) & 0b10111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111L; return new UUID(long1, long2); } @Override public String toString() { StringBuilder sb = new StringBuilder(); // encode first long byte[] bytes1 = Longs.toByteArray(_long1); sb.append(ENCODING.encode(bytes1, 0, 4)).append('-'); sb.append(ENCODING.encode(bytes1, 4, 2)).append('-'); sb.append(ENCODING.encode(bytes1, 6, 2)).append('-'); // encode second long byte[] bytes2 = Longs.toByteArray(_long2); sb.append(ENCODING.encode(bytes2, 0, 2)).append('-'); sb.append(ENCODING.encode(bytes2, 2, 6)); return sb.toString(); } public static UUID fromString(String s) { s = s.replaceAll("-", "").toLowerCase(); // decode first long byte[] bytes1 = ENCODING.decode(s.substring(0, 16)); long long1 = Longs.fromByteArray(bytes1); // decode second long byte[] bytes2 = ENCODING.decode(s.substring(16, 32)); long long2 = Longs.fromByteArray(bytes2); return new UUID(long1, long2); } @Override public int hashCode() { return toString().hashCode(); } @Override public boolean equals(Object that) { return this.toString().equals(String.valueOf(that)); } }