org.apache.axis.components.uuid.SimpleUUIDGen Maven / Gradle / Ivy
/*
* 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.
*/
/**
*
* UUIDGen adopted from the juddi project
* (http://sourceforge.net/projects/juddi/)
*
*/
package org.apache.axis.components.uuid;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;
/**
* Used to create new universally unique identifiers or UUID's (sometimes called
* GUID's). UDDI UUID's are allways formmated according to DCE UUID conventions.
*
* @author Maarten Coene
* @author Steve Viens
* @version 0.3.2 3/25/2001
* @since JDK1.2.2
*/
public class SimpleUUIDGen implements UUIDGen {
private static final BigInteger countStart = new BigInteger("-12219292800000"); // 15 October 1582
private static final int clock_sequence = (new Random()).nextInt(16384);
private static final byte ZERO = (byte) 48; // "0"
private static final byte ONE = (byte) 49; // "1"
private static Random secureRandom = null;
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();
}
}
/**
* utility method which returns a bitString with left zero padding
* for as many places as necessary to reach len; otherwise
* returns bitString unaltered.
*
* @return a left zero padded string of at least len chars
* @param bitString a String to pad
* @param len the length under which bitString needs padding
*/
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;
}
/**
* Creates a new UUID. The algorithm used is described by The Open Group.
* See
* Universal Unique Identifier for more details.
*
* Due to a lack of functionality in Java, a part of the UUID is a secure
* random. This results in a long processing time when this method is called
* for the first time.
*/
public String nextUUID() {
// TODO: this method has to be checked for it's correctness. I'm not sure the standard is
// implemented correctly.
// the count of 100-nanosecond intervals since 00:00:00.00 15 October 1582
BigInteger count;
// the number of milliseconds since 1 January 1970
BigInteger current = BigInteger.valueOf(System.currentTimeMillis());
// the number of milliseconds since 15 October 1582
BigInteger countMillis = current.subtract(countStart);
// the result
count = countMillis.multiply(BigInteger.valueOf(10000));
byte[] bits = leftZeroPadString(count.toString(2), 60).getBytes();
// the time_low field
byte[] time_low = new byte[32];
for (int i = 0; i < 32; i++)
time_low[i] = bits[bits.length - i - 1];
// the time_mid field
byte[] time_mid = new byte[16];
for (int i = 0; i < 16; i++)
time_mid[i] = bits[bits.length - 32 - i - 1];
// the time_hi_and_version field
byte[] time_hi_and_version = new byte[16];
for (int i = 0; i < 12; i++)
time_hi_and_version[i] = bits[bits.length - 48 - i - 1];
time_hi_and_version[12] = ONE;
time_hi_and_version[13] = ZERO;
time_hi_and_version[14] = ZERO;
time_hi_and_version[15] = ZERO;
// the clock_seq_low field
BigInteger clockSequence = BigInteger.valueOf(clock_sequence);
byte[] clock_bits = leftZeroPadString(clockSequence.toString(2), 14).getBytes();
byte[] clock_seq_low = new byte[8];
for (int i = 0; i < 8; i++) {
clock_seq_low[i] = clock_bits[clock_bits.length - i - 1];
}
// the clock_seq_hi_and_reserved
byte[] clock_seq_hi_and_reserved = new byte[8];
for (int i = 0; i < 6; i++)
clock_seq_hi_and_reserved[i] = clock_bits[clock_bits.length - 8 - i - 1];
clock_seq_hi_and_reserved[6] = ZERO;
clock_seq_hi_and_reserved[7] = ONE;
String timeLow = Long.toHexString((new BigInteger(new String(reverseArray(time_low)), 2)).longValue());
timeLow = leftZeroPadString(timeLow, 8);
String timeMid = Long.toHexString((new BigInteger(new String(reverseArray(time_mid)), 2)).longValue());
timeMid = leftZeroPadString(timeMid, 4);
String timeHiAndVersion = Long.toHexString((new BigInteger(new String(reverseArray(time_hi_and_version)), 2)).longValue());
timeHiAndVersion = leftZeroPadString(timeHiAndVersion, 4);
String clockSeqHiAndReserved = Long.toHexString((new BigInteger(new String(reverseArray(clock_seq_hi_and_reserved)), 2)).longValue());
clockSeqHiAndReserved = leftZeroPadString(clockSeqHiAndReserved, 2);
String clockSeqLow = Long.toHexString((new BigInteger(new String(reverseArray(clock_seq_low)), 2)).longValue());
clockSeqLow = leftZeroPadString(clockSeqLow, 2);
long nodeValue = secureRandom.nextLong();
nodeValue = Math.abs(nodeValue);
while (nodeValue > 140737488355328L) {
nodeValue = secureRandom.nextLong();
nodeValue = Math.abs(nodeValue);
}
BigInteger nodeInt = BigInteger.valueOf(nodeValue);
byte[] node_bits = leftZeroPadString(nodeInt.toString(2), 47).getBytes();
byte[] node = new byte[48];
for (int i = 0; i < 47; i++)
node[i] = node_bits[node_bits.length - i - 1];
node[47] = ONE;
String theNode = Long.toHexString((new BigInteger(new String(reverseArray(node)), 2)).longValue());
theNode = leftZeroPadString(theNode, 12);
StringBuffer result = new StringBuffer(timeLow);
result.append("-");
result.append(timeMid);
result.append("-");
result.append(timeHiAndVersion);
result.append("-");
result.append(clockSeqHiAndReserved);
result.append(clockSeqLow);
result.append("-");
result.append(theNode);
return result.toString().toUpperCase();
}
private static byte[] reverseArray(byte[] bits) {
byte[] result = new byte[bits.length];
for (int i = 0; i < result.length; i++)
result[i] = bits[result.length - 1 - i];
return result;
}
}