/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.UUID; /** * A generator of GUID. */ public final class GUIDGenerator { /** * The last time value. Used to remove duplicate UUIDs. */ private static long s_lastTime = Long.MIN_VALUE; /** * The current clock and node value. */ private static long s_clockSeqAndNode = 0x8000000000000000L; /** * Restricted constructor. */ private GUIDGenerator() { } //------------------------------------------------------------------------- /** * Generate a UUID. * * @return the UUID, not null */ public static UUID generate() { return new UUID(newTime(), generateClockSeqAndNode(MacAddressLookUp.ADDRESS)); } /** * Generates the time part of the GUID. * * @return the time */ public static synchronized long newTime() { long time; // UTC time long timeMillis = (System.currentTimeMillis() * 10000) + 0x01B21DD213814000L; if (timeMillis > s_lastTime) { s_lastTime = timeMillis; } else { timeMillis = ++s_lastTime; } // time low time = timeMillis << 32; // time mid time |= (timeMillis & 0xFFFF00000000L) >> 16; // time hi and version time |= 0x1000 | ((timeMillis >> 48) & 0x0FFF); // version 1 return time; } /** * Generates part of the GUID. * @param macAddress the MAC address, null uses the local host address * @return the clock sequence and node */ private static synchronized long generateClockSeqAndNode(String macAddress) { if (macAddress != null) { s_clockSeqAndNode |= parseLong(macAddress); } else { try { byte[] local = InetAddress.getLocalHost().getAddress(); s_clockSeqAndNode |= (local[0] << 24) & 0xFF000000L; s_clockSeqAndNode |= (local[1] << 16) & 0xFF0000; s_clockSeqAndNode |= (local[2] << 8) & 0xFF00; s_clockSeqAndNode |= local[3] & 0xFF; } catch (UnknownHostException ex) { s_clockSeqAndNode |= (long) (Math.random() * 0x7FFFFFFF); } } // Skip the clock sequence generation process and use random instead. //REVIEW yomi -- 20091127 not sure if this correct // s_clockSeqAndNode |= (long) (Math.random() * 0x3FFF) << 48; return s_clockSeqAndNode; } /** * Parses a string to a long as required by GUID. * @param s the string, not null * @return the long */ public static long parseLong(CharSequence s) { long out = 0; byte shifts = 0; char c; for (int i = 0; i < s.length() && shifts < 16; i++) { c = s.charAt(i); if ((c > 47) && (c < 58)) { ++shifts; out <<= 4; out |= c - 48; } else if ((c > 64) && (c < 71)) { ++shifts; out <<= 4; out |= c - 55; } else if ((c > 96) && (c < 103)) { ++shifts; out <<= 4; out |= c - 87; } } return out; } }