UUID.java Source code

Java tutorial

Introduction

Here is the source code for UUID.java

Source

/**
 * Copyright (C) 2001-2005 Connected Systems Inc. All rights reserved.
 * This software is the confidential and proprietary information of
 * Connected Systems Inc. ("Confidential Information").
 */
//package biz.evot.util.uuid;

import java.io.Serializable;

public class UUID implements Serializable, Cloneable, Comparable {
    /**
     * 
     */
    private static final long serialVersionUID = 112102158432121213L;

    private final static String kHexChars = "0123456789abcdefABCDEF";

    public final static byte INDEX_CLOCK_HI = 6;

    public final static byte INDEX_CLOCK_MID = 4;

    public final static byte INDEX_CLOCK_LO = 0;

    public final static byte INDEX_TYPE = 6;

    // Clock seq. & variant are multiplexed...
    public final static byte INDEX_CLOCK_SEQUENCE = 8;

    public final static byte INDEX_VARIATION = 8;

    public final static byte TYPE_NULL = 0;

    public final static byte TYPE_TIME_BASED = 1;

    public final static byte TYPE_DCE = 2; // Not

    // used

    public final static byte TYPE_NAME_BASED = 3;

    public final static byte TYPE_RANDOM_BASED = 4;

    /*
     * 'Standard' namespaces defined (suggested) by UUID specs:
     */
    public final static String NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";

    public final static String NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";

    public final static String NAMESPACE_OID = "6ba7b812-9dad-11d1-80b4-00c04fd430c8";

    public final static String NAMESPACE_X500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8";

    /*
     * By default let's cache desc, can be turned off. For hash code there's no
     * point in turning it off (since the int is already part of the instance
     * memory allocation); if you want to save those 4 bytes (or possibly bit
     * more if alignment is bad) just comment out hash caching.
     */
    private static boolean sDescCaching = true;

    /**
     * The shared null UUID. Would be nice to do lazy instantiation, but if the
     * instance really has to be a singleton, that would mean class-level
     * locking (synchronized getNullUUID()), which would be some overhead... So
     * let's just bite the bullet the first time assuming creation of the null
     * UUID (plus wasted space if it's not needed) can be ignored.
     */
    private final static UUID sNullUUID = new UUID();

    private final byte[] mId = new byte[16];

    // Both string presentation and hash value may be cached...
    private transient String mDesc = null;

    private transient int mHashCode = 0;

    /* *** Object creation: *** */

    /**
     * Default constructor creates a NIL UUID, one that contains all zeroes
     * 
     * Note that the clearing of array is actually unnecessary as JVMs are
     * required to clear up the allocated arrays by default.
     */
    public UUID() {
        /*
         * for (int i = 0; i < 16; ++i) { mId[i] = (byte)0; }
         */
    }

    /**
     * Constructor for cases where you already have the 16-byte binary
     * representation of the UUID (for example if you save UUIDs binary takes
     * less than half of space string representation takes).
     * 
     * @param data
     *            array that contains the binary representation of UUID
     */
    public UUID(byte[] data) {
        /*
         * Could call the other constructor... and/or use System.arraycopy.
         * However, it's likely that those would make this slower to use, and
         * initialization is really simple as is in any case.
         */
        for (int i = 0; i < 16; ++i) {
            mId[i] = data[i];
        }
    }

    /**
     * Constructor for cases where you already have the binary representation of
     * the UUID (for example if you save UUIDs binary takes less than half of
     * space string representation takes) in a byte array
     * 
     * @param data
     *            array that contains the binary representation of UUID
     * @param start
     *            byte offset where UUID starts
     */
    public UUID(byte[] data, int start) {
        for (int i = 0; i < 16; ++i) {
            mId[i] = data[start + i];
        }
    }

    /**
     * Protected constructor used by UUIDGenerator
     * 
     * @param type
     *            UUID type
     * @param data
     *            16 byte UUID contents
     */
    UUID(int type, byte[] data) {
        for (int i = 0; i < 16; ++i) {
            mId[i] = data[i];
        }
        // Type is multiplexed with time_hi:
        mId[INDEX_TYPE] &= (byte) 0x0F;
        mId[INDEX_TYPE] |= (byte) (type << 4);
        // Variant masks first two bits of the clock_seq_hi:
        mId[INDEX_VARIATION] &= (byte) 0x3F;
        mId[INDEX_VARIATION] |= (byte) 0x80;
    }

    /**
     * Constructor for creating UUIDs from the canonical string representation
     * 
     * Note that implementation is optimized for speed, not necessarily code
     * clarity... Also, since what we get might not be 100% canonical (see
     * below), let's not yet populate mDesc here.
     * 
     * @param id
     *            String that contains the canonical representation of the UUID
     *            to build; 36-char string (see UUID specs for details).
     *            Hex-chars may be in upper-case too; UUID class will always
     *            output them in lowercase.
     */
    public UUID(String id) throws NumberFormatException {
        if (id == null) {
            throw new NullPointerException();
        }
        if (id.length() != 36) {
            throw new NumberFormatException("UUID has to be represented by the standard 36-char representation");
        }

        for (int i = 0, j = 0; i < 36; ++j) {
            // Need to bypass hyphens:
            switch (i) {
            case 8:
            case 13:
            case 18:
            case 23:
                if (id.charAt(i) != '-') {
                    throw new NumberFormatException(
                            "UUID has to be represented by the standard 36-char representation");
                }
                ++i;
            }
            char c = id.charAt(i);

            if (c >= '0' && c <= '9') {
                mId[j] = (byte) ((c - '0') << 4);
            } else if (c >= 'a' && c <= 'f') {
                mId[j] = (byte) ((c - 'a' + 10) << 4);
            } else if (c >= 'A' && c <= 'F') {
                mId[j] = (byte) ((c - 'A' + 10) << 4);
            } else {
                throw new NumberFormatException("Non-hex character '" + c + "'");
            }

            c = id.charAt(++i);

            if (c >= '0' && c <= '9') {
                mId[j] |= (byte) (c - '0');
            } else if (c >= 'a' && c <= 'f') {
                mId[j] |= (byte) (c - 'a' + 10);
            } else if (c >= 'A' && c <= 'F') {
                mId[j] |= (byte) (c - 'A' + 10);
            } else {
                throw new NumberFormatException("Non-hex character '" + c + "'");
            }
            ++i;
        }
    }

    /**
     * Default cloning behaviour (bitwise copy) is just fine...
     * 
     * Could clear out cached string presentation, but there's probably no point
     * in doing that.
     */
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            // shouldn't happen
            return null;
        }
    }

    /* *** Configuration: *** */
    public static void setDescCaching(boolean state) {
        sDescCaching = state;
    }

    /* *** Accessors: *** */

    /**
     * Accessor for getting the shared null UUID
     * 
     * @return the shared null UUID
     */
    public static UUID getNullUUID() {
        return sNullUUID;
    }

    public boolean isNullUUID() {
        // Assuming null uuid is usually used for nulls:
        if (this == sNullUUID) {
            return true;
        }
        // Could also check hash code; null uuid has -1 as hash?
        byte[] data = mId;
        int i = mId.length;
        byte zero = (byte) 0;
        while (--i >= 0) {
            if (data[i] != zero) {
                return false;
            }
        }

        return true;
    }

    /**
     * Returns the UUID type code
     * 
     * @return UUID type
     */
    public int getType() {
        return (mId[INDEX_TYPE] & 0xFF) >> 4;
    }

    /**
     * Returns the UUID as a 16-byte byte array
     * 
     * @return 16-byte byte array that contains UUID bytes in the network byte
     *         order
     */
    public byte[] asByteArray() {
        byte[] result = new byte[16];
        toByteArray(result);
        return result;
    }

    /**
     * Fills in the 16 bytes (from index pos) of the specified byte array with
     * the UUID contents.
     * 
     * @param dst
     *            Byte array to fill
     * @param pos
     *            Offset in the array
     */
    public void toByteArray(byte[] dst, int pos) {
        byte[] src = mId;
        for (int i = 0; i < 16; ++i) {
            dst[pos + i] = src[i];
        }
    }

    public void toByteArray(byte[] dst) {
        toByteArray(dst, 0);
    }

    /**
     * 'Synonym' for 'asByteArray'
     */
    public byte[] toByteArray() {
        return asByteArray();
    }

    /* *** Standard methods from Object overridden: *** */

    /**
     * Could use just the default hash code, but we can probably create a better
     * identity hash (ie. same contents generate same hash) manually, without
     * sacrificing speed too much. Although multiplications with modulos would
     * generate better hashing, let's use just shifts, and do 2 bytes at a time.
     * <p>
     * Of course, assuming UUIDs are randomized enough, even simpler approach
     * might be good enough?
     * <p>
     * Is this a good hash? ... one of these days I better read more about basic
     * hashing techniques I swear!
     */
    private final static int[] kShifts = { 3, 7, 17, 21, 29, 4, 9 };

    public int hashCode() {
        if (mHashCode == 0) {
            // Let's handle first and last byte separately:
            int result = mId[0] & 0xFF;

            result |= (result << 16);
            result |= (result << 8);

            for (int i = 1; i < 15; i += 2) {
                int curr = (mId[i] & 0xFF) << 8 | (mId[i + 1] & 0xFF);
                int shift = kShifts[i >> 1];

                if (shift > 16) {
                    result ^= (curr << shift) | (curr >>> (32 - shift));
                } else {
                    result ^= (curr << shift);
                }
            }

            // and then the last byte:
            int last = mId[15] & 0xFF;
            result ^= (last << 3);
            result ^= (last << 13);

            result ^= (last << 27);
            // Let's not accept hash 0 as it indicates 'not hashed yet':
            if (result == 0) {
                mHashCode = -1;
            } else {
                mHashCode = result;
            }
        }
        return mHashCode;
    }

    public String toString() {
        /*
         * Could be synchronized, but there isn't much harm in just taking our
         * chances (ie. in the worst case we'll form the string more than
         * once... but result is the same)
         */

        if (mDesc == null) {
            StringBuffer b = new StringBuffer(36);

            for (int i = 0; i < 16; ++i) {
                // Need to bypass hyphens:
                switch (i) {
                case 4:
                case 6:
                case 8:
                case 10:
                    b.append('-');
                }
                int hex = mId[i] & 0xFF;
                b.append(kHexChars.charAt(hex >> 4));
                b.append(kHexChars.charAt(hex & 0x0f));
            }
            if (!sDescCaching) {
                return b.toString();
            }
            mDesc = b.toString();
        }
        return mDesc;
    }

    /* *** Comparison methods: *** */

    private final static int[] sTimeCompare = new int[] { INDEX_CLOCK_HI, INDEX_CLOCK_HI + 1, INDEX_CLOCK_MID,
            INDEX_CLOCK_MID + 1, INDEX_CLOCK_LO, INDEX_CLOCK_LO + 1, INDEX_CLOCK_LO + 2, INDEX_CLOCK_LO + 3, };

    /**
     * Let's also make UUIDs sortable. This will mostly/only be useful with
     * time-based UUIDs; they will sorted by time of creation. The order will be
     * strictly correct with UUIDs produced over one JVM's lifetime; that is, if
     * more than one JVMs create UUIDs and/or system is rebooted the order may
     * not be 100% accurate between UUIDs created under different JVMs.
     * 
     * For all UUIDs, type is first compared, and UUIDs of different types are
     * sorted together (ie. null UUID is before all other UUIDs, then time-based
     * UUIDs etc). If types are the same, time-based UUIDs' time stamps
     * (including additional clock counter) are compared, so UUIDs created first
     * are ordered first. For all other types (and for time-based UUIDs with
     * same time stamp, which should only occur when comparing a UUID with
     * itself, or with UUIDs created on different JVMs or external systems)
     * binary comparison is done over all 16 bytes.
     * 
     * @param o
     *            Object to compare this UUID to; should be a UUID
     * 
     * @return -1 if this UUID should be ordered before the one passed, 1 if
     *         after, and 0 if they are the same
     * 
     * @throws ClassCastException
     *             if o is not a UUID.
     */
    public int compareTo(Object o) {
        UUID other = (UUID) o;

        int thisType = getType();
        int thatType = other.getType();

        /*
         * Let's first order by type:
         */
        if (thisType > thatType) {
            return 1;
        } else if (thisType < thatType) {
            return -1;
        }

        /*
         * And for time-based UUIDs let's compare time stamps first, then the
         * rest... For all other types, we'll just do straight byte-by-byte
         * comparison.
         */
        byte[] thisId = mId;
        byte[] thatId = other.mId;
        int i = 0;
        if (thisType == TYPE_TIME_BASED) {
            for (; i < 8; ++i) {
                int index = sTimeCompare[i];
                int cmp = (((int) thisId[index]) & 0xFF) - (((int) thatId[index]) & 0xFF);
                if (cmp != 0) {
                    return cmp;
                }
            }
            // Let's fall down to full comparison otherwise
        }

        for (; i < 16; ++i) {
            int cmp = (((int) thisId[i]) & 0xFF) - (((int) thatId[i]) & 0xFF);
            if (cmp != 0) {
                return cmp;
            }
        }

        return 0;
    }

    /**
     * Checking equality of UUIDs is easy; just compare the 128-bit number.
     */
    public boolean equals(Object o) {
        if (!(o instanceof UUID)) {
            return false;
        }
        byte[] otherId = ((UUID) o).mId;
        byte[] thisId = mId;
        for (int i = 0; i < 16; ++i) {
            if (otherId[i] != thisId[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * Constructs a new UUID instance given the canonical string representation
     * of an UUID.
     * 
     * Note that calling this method returns the same result as would using the
     * matching (1 string arg) constructor.
     * 
     * @param id
     *            Canonical string representation used for constructing an UUID
     *            instance
     * 
     * @throws NumberFormatException
     *             if 'id' is invalid UUID
     */
    public static UUID valueOf(String id) throws NumberFormatException {
        return new UUID(id);
    }

    /**
     * Constructs a new UUID instance given a byte array that contains the (16
     * byte) binary representation.
     * 
     * Note that calling this method returns the same result as would using the
     * matching constructor
     * 
     * @param src
     *            Byte array that contains the UUID definition
     * @param start
     *            Offset in the array where the UUID starts
     */
    public static UUID valueOf(byte[] src, int start) {
        return new UUID(src, start);
    }

    /**
     * Constructs a new UUID instance given a byte array that contains the (16
     * byte) binary representation.
     * 
     * Note that calling this method returns the same result as would using the
     * matching constructor
     * 
     * @param src
     *            Byte array that contains the UUID definition
     */
    public static UUID valueOf(byte[] src) {
        return new UUID(src);
    }

    public static void main(String[] args) {
    }
}