Mega Code Archive

 
Categories / Java / Development Class
 

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() {     } }