/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.axis.components.uuid; import java.util.Random; import java.security.SecureRandom; /** * Creates time-based UUID's. See the UUID Internet Draft for details. * * @author Jarek Gawor (gawor@apache.org) */ public class FastUUIDGen implements UUIDGen { private static Random secureRandom; private static String nodeStr; private static int clockSequence; private long lastTime = 0; static { // problem: the node should be the IEEE 802 ethernet address, but can not // be retrieved in Java yet. // see bug ID 4173528 // workaround (also suggested in bug ID 4173528) // If a system wants to generate UUIDs but has no IEE 802 compliant // network card or other source of IEEE 802 addresses, then this section // describes how to generate one. // The ideal solution is to obtain a 47 bit cryptographic quality random // number, and use it as the low 47 bits of the node ID, with the most // significant bit of the first octet of the node ID set to 1. This bit // is the unicast/multicast bit, which will never be set in IEEE 802 // addresses obtained from network cards; hence, there can never be a // conflict between UUIDs generated by machines with and without network // cards. try { secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN"); } catch (Exception e) { secureRandom = new Random(); } nodeStr = getNodeHexValue(); clockSequence = getClockSequence(); } private static String getNodeHexValue() { long node = 0; long nodeValue = 0; while ( (node = getBitsValue(nodeValue, 47, 47)) == 0 ) { nodeValue = secureRandom.nextLong(); } node = node | 0x800000000000L; return leftZeroPadString(Long.toHexString(node), 12); } private static int getClockSequence() { return secureRandom.nextInt(16384); } public String nextUUID() { long time = System.currentTimeMillis(); long timestamp = time * 10000; timestamp += 0x01b21dd2L << 32; timestamp += 0x13814000; synchronized(this) { if (time - lastTime <= 0) { clockSequence = ((clockSequence + 1) & 16383); } lastTime = time; } long timeLow = getBitsValue(timestamp, 32, 32); long timeMid = getBitsValue(timestamp, 48, 16); long timeHi = getBitsValue(timestamp, 64, 16) | 0x1000; long clockSeqLow = getBitsValue(clockSequence, 8, 8); long clockSeqHi = getBitsValue(clockSequence, 16, 8) | 0x80; String timeLowStr = leftZeroPadString(Long.toHexString(timeLow), 8); String timeMidStr = leftZeroPadString(Long.toHexString(timeMid), 4); String timeHiStr = leftZeroPadString(Long.toHexString(timeHi), 4); String clockSeqHiStr = leftZeroPadString(Long.toHexString(clockSeqHi), 2); String clockSeqLowStr = leftZeroPadString(Long.toHexString(clockSeqLow), 2); StringBuffer result = new StringBuffer(36); result.append(timeLowStr).append("-"); result.append(timeMidStr).append("-"); result.append(timeHiStr).append("-"); result.append(clockSeqHiStr).append(clockSeqLowStr); result.append("-").append(nodeStr); return result.toString(); } private static long getBitsValue(long value, int startBit, int bitLen) { return ((value << (64-startBit)) >>> (64-bitLen)); } private static final String leftZeroPadString(String bitString, int len) { if (bitString.length() < len) { int nbExtraZeros = len - bitString.length(); StringBuffer extraZeros = new StringBuffer(); for (int i = 0; i < nbExtraZeros; i++) { extraZeros.append("0"); } extraZeros.append(bitString); bitString = extraZeros.toString(); } return bitString; } }