package nl.thanod;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.*;
public class TimedUUIDGenerator {
public static final Comparator<byte[]> MAC_COMPARATOR = new Comparator<byte[]>() {
@Override
public int compare(byte[] o1, byte[] o2) {
if (o1 == null)
return -1;
if (o2 == null)
return 1;
if (isLocalMAC(o1) != isLocalMAC(o2))
return isLocalMAC(o1) ? -1 : 1;
int len = Math.min(o1.length, o2.length);
for (int i = 0; i < len; i++) {
int diff = (o1[i] & 0xFF) - (o2[i] & 0xFF);
if (diff != 0)
return diff;
}
return o1.length - o2.length;
}
};
public static final int CLOCK_ID_MASK = 0xFFF;
public static final long TIME_MASK = 0x0FFFFFFFFFFFFFFFL;
public static final long VERSION_MASK = 0x1000000000000000L;
private static long CLOCK_ID;
private static long LAST_TIME = 0;
private static final Random RANDY = new Random(System.currentTimeMillis());
private static long TIME_INCREMENT = 0;
private static final byte[] USING_MAC;
static {
byte[] mac = null;
try {
Enumeration<NetworkInterface> inf = NetworkInterface.getNetworkInterfaces();
while (inf.hasMoreElements()) {
NetworkInterface n = inf.nextElement();
byte[] m = n.getHardwareAddress();
if (MAC_COMPARATOR.compare(mac, m) < 0)
mac = m;
}
} catch (SocketException ball) {
}
if (mac == null || (isLocalMAC(mac) && !isGeneratedMacStrong(mac)))
mac = generateMac();
USING_MAC = mac;
CLOCK_ID = RANDY.nextLong() & CLOCK_ID_MASK;
}
public static byte[] generateMac() {
byte[] mac = new byte[6];
RANDY.nextBytes(mac);
mac[0] = 0x02;
return mac;
}
public static String getMacString(byte[] b) {
if (b == null)
return null;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < b.length; i++) {
if (sb.length() > 0)
sb.append(':');
sb.append(Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
public synchronized static UUID getTimeBasedUUID() {
// convert the time to nanoseconds since 15 October 1582
long uppertime = System.currentTimeMillis();// +Calendar.getInstance().getTimeZone().getOffset(System.currentTimeMillis());
uppertime = uppertime * 10000 + 122192928000000000L;
uppertime &= TIME_MASK;
if (uppertime < LAST_TIME)
CLOCK_ID = (CLOCK_ID + 1) & CLOCK_ID_MASK;
if (uppertime == LAST_TIME)
TIME_INCREMENT++;
else
TIME_INCREMENT = 0;
LAST_TIME = uppertime;
uppertime += TIME_INCREMENT;
uppertime &= TIME_MASK;
uppertime |= VERSION_MASK;
long swap = (uppertime >> 32) & 0xFFFFFFFF;
uppertime <<= 32;
uppertime |= (swap & 0xFFFF0000) >> 16;
uppertime |= (swap & 0x0000FFFF) << 16;
long lowertime = macToLong(USING_MAC);
lowertime |= CLOCK_ID << 48;
lowertime |= 0x80L << 56;
return new UUID(uppertime, lowertime);
}
public static boolean isGeneratedMacStrong(byte[] mac) {
int x = ~0;
for (int i = 0; i < mac.length; i++)
x &= mac[i] & 0xFF;
int c = 0;
for (int i = 0; i < mac.length; i++)
if ((mac[i] & 0xFF) == x)
c++;
// System.out.println(getMacString(mac) + " - " + c + " - " + x + " - "
// + (c < 2));
return c < 2;
}
public static boolean isLocalMAC(byte[] mac) {
if (mac == null)
return false;
return (mac[0] & 0x02) == 0x02;
}
public static void main(String... args) {
int count = 20;
long start, took;
start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
UUID uuid = getTimeBasedUUID();
System.out.println(uuid);
}
took = System.currentTimeMillis() - start;
System.out.println("generating " + count + " uuid's took " + took + "ms");
System.out.println(UUID.fromString("c70e067b-56c7-11df-8ec4-00236c001b40").version());
}
private static long macToLong(byte[] mac) {
long m = 0;
m |= (long) (mac[0] & 0xFF) << 40;
m |= (long) (mac[1] & 0xFF) << 32;
m |= (long) (mac[2] & 0xFF) << 24;
m |= (long) (mac[3] & 0xFF) << 16;
m |= (long) (mac[4] & 0xFF) << 8;
m |= (long) (mac[5] & 0xFF) << 0;
return m;
}
}
//------------------------------
// Code by: Nils 'ThaNODnl' Dijk
// found on github.com/thanodnl
//------------------------------