Generate pseudo-GUID sequences
/*
*
* The ObjectStyle Group Software License, version 1.1
* ObjectStyle Group - http://objectstyle.org/
*
* Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
* of the software. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if any,
* must include the following acknowlegement:
* "This product includes software developed by independent contributors
* and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
* or promote products derived from this software without prior written
* permission. For written permission, email
* "andrus at objectstyle dot org".
*
* 5. Products derived from this software may not be called "ObjectStyle"
* or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
* names without prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* This software consists of voluntary contributions made by many
* individuals and hosted on ObjectStyle Group web site. For more
* information on the ObjectStyle Group, please see
* <http://objectstyle.org/>.
*/
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* helper class to generate pseudo-GUID sequences.
*
* @author Andrus Adamchik
*/
public class IDUtil {
private static final int BITMASK_0 = 0xff;
private static final int BITMASK_1 = 0xff << 8;
private static final int BITMASK_2 = 0xff << 16;
private static final int BITMASK_3 = 0xff << 24;
private static final int BITMASK_4 = 0xff << 32;
private static final int BITMASK_5 = 0xff << 40;
private static final int BITMASK_6 = 0xff << 48;
private static final int BITMASK_7 = 0xff << 56;
// this id sequence needs to be long enough to feel
// the gap within the same timestamp millisecond
private static volatile int currentId;
private static MessageDigest md;
private static byte[] ipAddress;
static {
try {
md = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Can't initialize MessageDigest.", e);
}
try {
ipAddress = java.net.InetAddress.getLocalHost().getAddress();
}
catch (UnknownHostException e) {
// use loopback interface
ipAddress = new byte[] {
127, 0, 0, 1
};
}
}
/**
* Prints a byte value to a StringBuffer as a double digit hex value.
*
* @since 1.2
*/
public static void appendFormattedByte(StringBuffer buffer, byte byteValue) {
final String digits = "0123456789ABCDEF";
buffer.append(digits.charAt((byteValue >>> 4) & 0xF));
buffer.append(digits.charAt(byteValue & 0xF));
}
/**
* @param length the length of returned byte[]
* @return A pseudo-unique byte array of the specified length. Length must be at least
* 16 bytes, or an exception is thrown.
* @since 1.0.2
*/
public synchronized static byte[] pseudoUniqueByteSequence(int length) {
if (length < 16) {
throw new IllegalArgumentException(
"Can't generate unique byte sequence shorter than 16 bytes: "
+ length);
}
if (length == 16) {
return pseudoUniqueByteSequence16();
}
byte[] bytes = new byte[length];
for (int i = 0; i <= length - 16; i += 16) {
byte[] nextSequence = pseudoUniqueByteSequence16();
System.arraycopy(nextSequence, 0, bytes, i, 16);
}
// leftovers?
int leftoverLen = length % 16;
if (leftoverLen > 0) {
byte[] nextSequence = pseudoUniqueByteSequence16();
System.arraycopy(nextSequence, 0, bytes, length - leftoverLen, leftoverLen);
}
return bytes;
}
public synchronized static byte[] pseudoUniqueSecureByteSequence(int length) {
if (length < 16) {
throw new IllegalArgumentException(
"Can't generate unique byte sequence shorter than 16 bytes: "
+ length);
}
if (length == 16) {
return pseudoUniqueSecureByteSequence16();
}
byte[] bytes = new byte[length];
for (int i = 0; i <= length - 16; i += 16) {
byte[] nextSequence = pseudoUniqueSecureByteSequence16();
System.arraycopy(nextSequence, 0, bytes, i, 16);
}
// leftovers?
int leftoverLen = length % 16;
if (leftoverLen > 0) {
byte[] nextSequence = pseudoUniqueSecureByteSequence16();
System.arraycopy(nextSequence, 0, bytes, length - leftoverLen, leftoverLen);
}
return bytes;
}
public static final byte[] pseudoUniqueByteSequence8() {
byte[] bytes = new byte[8];
// bytes 0..2 - incrementing #
// bytes 3..5 - timestamp high bytes
// bytes 6..7 - IP address
int nextInt = nextInt();
bytes[0] = (byte) ((nextInt & (0xff << 16)) >>> 16);
bytes[1] = (byte) ((nextInt & (0xff << 8)) >>> 8);
bytes[2] = (byte) (nextInt & 0xff);
// append 3 high bytes of timestamp
long t = System.currentTimeMillis();
bytes[3] = (byte) ((t & BITMASK_2) >>> 16);
bytes[4] = (byte) ((t & BITMASK_1) >>> 8);
bytes[5] = (byte) (t & BITMASK_0);
// append 2 last bytes of IP address
System.arraycopy(ipAddress, 2, bytes, 6, 2);
return bytes;
}
/**
* @return A pseudo unique 16-byte array.
*/
public static final byte[] pseudoUniqueByteSequence16() {
byte[] bytes = new byte[16];
// bytes 0..3 - incrementing #
// bytes 4..11 - timestamp
// bytes 12..15 - IP address
int nextInt = nextInt();
bytes[0] = (byte) ((nextInt & BITMASK_3) >>> 24);
bytes[1] = (byte) ((nextInt & BITMASK_2) >>> 16);
bytes[2] = (byte) ((nextInt & BITMASK_1) >>> 8);
bytes[3] = (byte) (nextInt & BITMASK_0);
long t = System.currentTimeMillis();
bytes[4] = (byte) ((t & BITMASK_7) >>> 56);
bytes[5] = (byte) ((t & BITMASK_6) >>> 48);
bytes[6] = (byte) ((t & BITMASK_5) >>> 40);
bytes[7] = (byte) ((t & BITMASK_4) >>> 32);
bytes[8] = (byte) ((t & BITMASK_3) >>> 24);
bytes[9] = (byte) ((t & BITMASK_2) >>> 16);
bytes[10] = (byte) ((t & BITMASK_1) >>> 8);
bytes[11] = (byte) (t & BITMASK_0);
System.arraycopy(ipAddress, 0, bytes, 12, 4);
return bytes;
}
/**
* @return A pseudo unique digested 16-byte array.
*/
public static byte[] pseudoUniqueSecureByteSequence16() {
byte[] bytes = pseudoUniqueByteSequence16();
synchronized (md) {
return md.digest(bytes);
}
}
private static final int nextInt() {
if (currentId == Integer.MAX_VALUE) {
currentId = 0;
}
return currentId++;
}
private IDUtil() {
}
}
Related examples in the same category