UUID generator from http://www1.ics.uci.edu : UUID GUID « Development Class « Java






UUID generator from http://www1.ics.uci.edu

     

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.    
 */

import java.io.IOException;
import java.net.InetAddress;
import java.security.SecureRandom;
import java.util.Random;
import java.util.UUID;


/**
 * UUID value generator.  Type 1 generator is based on the time-based generator  
 * in the Apache Commons Id project:  http://jakarta.apache.org/commons/sandbox
 * /id/uuid.html  The type 4 generator uses the standard Java UUID generator.
 *
 * The type 1 code has been vastly simplified and modified to replace the 
 * ethernet address of the host machine with the IP, since we do not want to 
 * require native libs and Java cannot access the MAC address directly.
 *
 * In spirit, implements the IETF UUID draft specification, found here:<br />
 * http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01
 * .txt
 *
 * @author Abe White, Kevin Sutter
 * @nojavadoc
 * @since 0.3.3
 */
public class UUIDGenerator {

    // supported UUID types
    public static final int TYPE1 = 1;
    public static final int TYPE4 = 4;

    // indexes within the uuid array for certain boundaries
    private static final byte IDX_TIME_HI = 6;
    private static final byte IDX_TYPE = 6; // multiplexed
    private static final byte IDX_TIME_MID = 4;
    private static final byte IDX_TIME_LO = 0;
    private static final byte IDX_TIME_SEQ = 8;
    private static final byte IDX_VARIATION = 8; // multiplexed

    // indexes and lengths within the timestamp for certain boundaries
    private static final byte TS_TIME_LO_IDX = 4;
    private static final byte TS_TIME_LO_LEN = 4;
    private static final byte TS_TIME_MID_IDX = 2;
    private static final byte TS_TIME_MID_LEN = 2;
    private static final byte TS_TIME_HI_IDX = 0;
    private static final byte TS_TIME_HI_LEN = 2;

    // offset to move from 1/1/1970, which is 0-time for Java, to gregorian
    // 0-time 10/15/1582, and multiplier to go from 100nsec to msec units
    private static final long GREG_OFFSET = 0xB1D069B5400L;
    private static final long MILLI_MULT = 10000L;

    // type of UUID -- time based
    private final static byte TYPE_TIME_BASED = 0x10;

    // random number generator used to reduce conflicts with other JVMs, and
    // hasher for strings.  
    private static Random RANDOM;

    // 4-byte IP address + 2 random bytes to compensate for the fact that
    // the MAC address is usually 6 bytes
    private static byte[] IP;

    // counter is initialized to 0 and is incremented for each uuid request
    // within the same timestamp window.
    private static int _counter;

    // current timestamp (used to detect multiple uuid requests within same
    // timestamp)
    private static long _currentMillis;

    // last used millis time, and a semi-random sequence that gets reset
    // when it overflows
    private static long _lastMillis = 0L;
    private static final int MAX_14BIT = 0x3FFF;
    private static short _seq = 0;
        
    /*
     * Initializer for type 1 UUIDs.  Creates random generator and genenerates
     * the node portion of the UUID using the IP address.
     */
    private static synchronized void initializeForType1()
    {
        if (RANDOM != null)
            return;
        // note that secure random is very slow the first time
        // it is used; consider switching to a standard random
        RANDOM = new SecureRandom();
        _seq = (short) RANDOM.nextInt(MAX_14BIT);
        
        byte[] ip = null;
        try {
            ip = InetAddress.getLocalHost().getAddress();
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }

        IP = new byte[6];
        RANDOM.nextBytes(IP);
        System.arraycopy(ip, 0, IP, 2, ip.length);        
    }

    /**
     * Return a unique UUID value.
     */
    public static byte[] next(int type) {
        if (type == TYPE4) {
            return createType4();
        }
        return createType1();
    }
      
    /*
     * Creates a type 1 UUID 
     */
    public static byte[] createType1() {
        if (RANDOM == null)
            initializeForType1();
        // set ip addr
        byte[] uuid = new byte[16];
        System.arraycopy(IP, 0, uuid, 10, IP.length);

        // Set time info.  Have to do this processing within a synchronized
        // block because of the statics...
        long now = 0;
        synchronized (UUIDGenerator.class) {
            // Get the time to use for this uuid.  This method has the side
            // effect of modifying the clock sequence, as well.
            now = getTime();

            // Insert the resulting clock sequence into the uuid
            uuid[IDX_TIME_SEQ] = (byte) ((_seq & 0x3F00) >>> 8);
            uuid[IDX_VARIATION] |= 0x80;
            uuid[IDX_TIME_SEQ+1] = (byte) (_seq & 0xFF);

        }

        // have to break up time because bytes are spread through uuid
        byte[] timeBytes = Long.toString(now).getBytes();

        // Copy time low
        System.arraycopy(timeBytes, TS_TIME_LO_IDX, uuid, IDX_TIME_LO,
                TS_TIME_LO_LEN);
        // Copy time mid
        System.arraycopy(timeBytes, TS_TIME_MID_IDX, uuid, IDX_TIME_MID,
                TS_TIME_MID_LEN);
        // Copy time hi
        System.arraycopy(timeBytes, TS_TIME_HI_IDX, uuid, IDX_TIME_HI,
                TS_TIME_HI_LEN);
        //Set version (time-based)
        uuid[IDX_TYPE] |= TYPE_TIME_BASED; // 0001 0000

        return uuid;
    }

    /*
     * Creates a type 4 UUID
     */
    private static byte[] createType4() {
        UUID type4 = UUID.randomUUID();
        byte[] uuid = new byte[16];
        longToBytes(type4.getMostSignificantBits(), uuid, 0);
        longToBytes(type4.getLeastSignificantBits(), uuid, 8);
        return uuid;
    }
    
    /*
     * Converts a long to byte values, setting them in a byte array
     * at a given starting position.
     */
    private static void longToBytes(long longVal, byte[] buf, int sPos) {
        sPos += 7;
        for(int i = 0; i < 8; i++)         
            buf[sPos-i] = (byte)(longVal >>> (i * 8));
    }

    /**
     * Return the next unique uuid value as a 16-character string.
     */
    public static String nextString(int type) {
        byte[] bytes = next(type);
        try {
            return new String(bytes, "ISO-8859-1");
        } catch (Exception e) {
            return new String(bytes);
        }
    }

    /**
     * Return the next unique uuid value as a 32-character hex string.
     */
    public static String nextHex(int type) {
        return Base16Encoder.encode(next(type));
    }

    /**
     * Get the timestamp to be used for this uuid.  Must be called from
     * a synchronized block.
     *
     * @return long timestamp
     */
    // package-visibility for testing
    static long getTime() {
        if (RANDOM == null)
            initializeForType1();
        long newTime = getUUIDTime();
        if (newTime <= _lastMillis) {
            incrementSequence();
            newTime = getUUIDTime();
        }
        _lastMillis = newTime;
        return newTime;
    }

    /**
     * Gets the appropriately modified timestamep for the UUID.  Must be called
     * from a synchronized block.
     *
     * @return long timestamp in 100ns intervals since the Gregorian change
     * offset
     */
    private static long getUUIDTime() {
        if (_currentMillis != System.currentTimeMillis()) {
            _currentMillis = System.currentTimeMillis();
            _counter = 0;  // reset counter
        }

        // check to see if we have created too many uuid's for this timestamp
        if (_counter + 1 >= MILLI_MULT) {
            // Original algorithm threw exception.  Seemed like overkill.
            // Let's just increment the timestamp instead and start over...
            _currentMillis++;
            _counter = 0;
        }

        // calculate time as current millis plus offset times 100 ns ticks
        long currentTime = (_currentMillis + GREG_OFFSET) * MILLI_MULT;

        // return the uuid time plus the artificial tick counter incremented
        return currentTime + _counter++;
    }

    /**
     * Increments the clock sequence for this uuid.  Must be called from a
     * synchronized block.
     */
    private static void incrementSequence() {
        // increment, but if it's greater than its 14-bits, reset it
        if (++_seq > MAX_14BIT) {
            _seq = (short) RANDOM.nextInt(MAX_14BIT);  // semi-random
        }
    }


}

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.    
 */

/**
 * Base 16 encoder.
 *
 * @author Marc Prud'hommeaux
 * @nojavadoc
 */
 class Base16Encoder {

    private final static char[] HEX = new char[]{
        '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

    /**
     * Convert bytes to a base16 string.
     */
    public static String encode(byte[] byteArray) {
        StringBuffer hexBuffer = new StringBuffer(byteArray.length * 2);
        for (int i = 0; i < byteArray.length; i++)
            for (int j = 1; j >= 0; j--)
                hexBuffer.append(HEX[(byteArray[i] >> (j * 4)) & 0xF]);
        return hexBuffer.toString();
    }

    /**
     * Convert a base16 string into a byte array.
     */
    public static byte[] decode(String s) {
        int len = s.length();
        byte[] r = new byte[len / 2];
        for (int i = 0; i < r.length; i++) {
            int digit1 = s.charAt(i * 2), digit2 = s.charAt(i * 2 + 1);
            if (digit1 >= '0' && digit1 <= '9')
                digit1 -= '0';
            else if (digit1 >= 'A' && digit1 <= 'F')
                digit1 -= 'A' - 10;
            if (digit2 >= '0' && digit2 <= '9')
                digit2 -= '0';
            else if (digit2 >= 'A' && digit2 <= 'F')
                digit2 -= 'A' - 10;

            r[i] = (byte) ((digit1 << 4) + digit2);
        }
        return r;
    }
}

   
    
    
    
    
  








Related examples in the same category

1.Random GUID
2.Algorithm for generating Random GUID
3.Get a unique identifier Using java.rmi.dgc.VMID
4.Using java.util.UUID
5.Create your own basic UUID
6.Session ID generator
7.UUID generator from Sun Microsystems
8.Using java.util.concurrent.AtomicLong: A numerical id, start at zero and increment by one.
9.A 32 byte GUID generator
10.A unique identifier
11.Generate pseudo-GUID sequences
12.Generates a UUID
13.Generates random UUIDs
14.Generator for Globally unique Strings
15.ID generator
16.Simple Id Generator
17.UUID generation
18.UUID generator of 32 bytes long values
19.Simple Long Id Generator
20.Long Sequence Generator
21.UUID generator
22.Thread-safe version of the Axiom UUIDGenerator
23.Convert an array of bytes into a List of Strings using UTF-8.
24.Your own UUID
25.Your own UUID 2
26.Create GUIDs according to the principles at http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt.
27.Get Unique Id