commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From trei...@apache.org
Subject cvs commit: jakarta-commons-sandbox/id/src/java/org/apache/commons/id/uuid UUID.java
Date Mon, 31 May 2004 07:07:31 GMT
treilly     2004/05/31 00:07:31

  Modified:    id/src/java/org/apache/commons/id/uuid UUID.java
  Log:
  Many changes drops use of BigInteger, closer to matching jdk1.5 UUID class - new methods
  
  Revision  Changes    Path
  1.7       +255 -116  jakarta-commons-sandbox/id/src/java/org/apache/commons/id/uuid/UUID.java
  
  Index: UUID.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/id/src/java/org/apache/commons/id/uuid/UUID.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- UUID.java	28 Apr 2004 03:11:05 -0000	1.6
  +++ UUID.java	31 May 2004 07:07:31 -0000	1.7
  @@ -15,10 +15,15 @@
    */
   package org.apache.commons.id.uuid;
   
  +import java.io.DataInput;
  +import java.io.IOException;
   import java.io.Serializable;
  -import java.math.BigInteger;
   import java.util.StringTokenizer;
   
  +import org.apache.commons.id.IdentifierUtils;
  +import org.apache.commons.codec.DecoderException;
  +import org.apache.commons.codec.binary.Hex;
  +
   /**
    * <p><code>UUID</code> represents a Universally Unique Identifier per
IETF
    * Draft specification. For more information regarding the IETF Draft UUID
  @@ -31,109 +36,59 @@
    *
    */
   
  -public class UUID implements Serializable, Cloneable {
  -
  -    /** Bits in a UUID. */
  -    public static final int BIT_LENGTH = 128;
  -
  -    /** Number of bytes in a UUID. */
  -    public static final int BYTE_LENGTH = 16;
  -
  -    /** Chars in a UUID String. */
  -    public static final int UUID_UNFORMATTED_LENGTH = 32;
  -
  -    /** Chars in a UUID String. */
  -    public static final int UUID_FORMATTED_LENGTH = 36;
  -
  -    /** Token length of '-' separated tokens. */
  -    public static final int TOKENS_IN_UUID = 5;
  -
  -    /** The string prefix for a urn UUID identifier. */
  -    public static final String URN_PREFIX = "urn:uuid:";
  -
  -    /** Base for hexidecimal used in parse and format. */
  -    public static final int BASE16 = 16;
  -
  -    /** UUID variant bits described in the IETF Draft MSB order,
  -     *  this is the "Reserved, NCS backward compatibility field" 0 x x with unknown bits
as 0*/
  -    public static final byte VARIANT_NCS_COMPAT = (byte) 0x00;
  -
  -    /** UUID variant bits described in the IETF Draft MSB order,
  -     *  this is the IETF Draft memo variant field 1 0 x with unknown bits as 0*/
  -    public static final byte VARIANT_IETF_DRAFT = (byte) 0x80;
  -
  -    /** UUID variant bits described in the IETF Draft MSB order,
  -     *  this is the IETF Draft "Microsoft Corporation" field variant 1 1 0 x with unknown
bits as 0*/
  -    public static final byte VARIANT_MS = (byte) 0xC0;
  -
  -    /** UUID variant bits described in the IETF Draft MSB order,
  -     *  this is the "Future Reserved variant 1 1 1 x with unknown bits as 0*/
  -    public static final byte VARIANT_FUTURE = (byte) 0xE0;
  -
  -    /** Version one constant for UUID version one of four */
  -    public static final byte VERSION_ONE = 1;
  -
  -    /** Version two constant for UUID version two of four */
  -    public static final byte VERSION_TWO = 2;
  -
  -    /** Version three constant for UUID version three of four */
  -    public static final byte VERSION_THREE = 3;
  +public class UUID implements Constants, Serializable, Comparable {
   
  -    /** Version four constant for UUID version four of four */
  -    public static final byte VERSION_FOUR = 4;
  -
  -    /** Array to check tokenized UUID's segment lengths */
  -    private static final int[] TOKEN_LENGTHS = {8, 4, 4, 4, 12};
  +    /** byte array to store 128-bits composing this UUID */
  +    private byte[] rawBytes = new byte[UUID_BYTE_LENGTH];
   
  -    /** Insertion point 1 for dashes in the string format */
  -    private static final int FORMAT_POSITION1 = 8;
  +    /** Holds node identifier for this UUID */
  +    private Long node = null;
   
  -    /** Insertion point 2 for dashes in the string format */
  -    private static final int FORMAT_POSITION2 = 13;
  +    /** Holds timestamp for this UUID */
  +    private long timestamp = -1;
   
  -    /** Insertion point 3 for dashes in the string format */
  -    private static final int FORMAT_POSITION3 = 18;
  +    /** Holds the clock sequence field */
  +    private Short clockSq = null;
   
  -    /** Insertion point 4 for dashes in the string format */
  -    private static final int FORMAT_POSITION4 = 23;
  +    /** Holds the version field of this UUID */
  +    private int version = -1;
   
  -    /** byte array to store 128-bits composing this UUID */
  -    private BigInteger numberValue = null;
  +    /** Holds the variant field of this UUID */
  +    private int variant = -1;
   
       /** Holds the internal string value of the UUID */
       private String stringValue = null;
   
  +
       /** Constructs a nil UUID */
       public UUID() {
           super();
  -        numberValue = new BigInteger("0");
  -    }
  -
  -    /**
  -     * <p>Copy constructor.</p>
  -     *
  -     * @param copyFrom the UUID to copy to create this UUID.
  -     * @throws IllegalArgumentException argument must be 128 bit UUID.
  -     */
  -    public UUID(UUID copyFrom) throws IllegalArgumentException {
  -        super();
  -        this.numberValue =
  -            new BigInteger(copyFrom.toBigInteger().toByteArray());
  -        this.stringValue = copyFrom.toString();
       }
   
       /**
        * <p>Constructs a UUID from a 128 bit java.math.BigInteger.</p>
  +     * <p>Method is protected as their is no standard as to the internal representation
of a UUID.
  +     * In this case a BigInteger is used with signum always positive.</p>
        *
        *  @param bigIntValue the 128 bit BigInteger to construct this UUID from.
        *  @throws IllegalArgumentException argument must be 128 bit
        */
  -    public UUID(BigInteger bigIntValue) throws IllegalArgumentException {
  +   /* protected UUID(BigInteger bigIntValue) throws IllegalArgumentException {
           super();
  -        if (bigIntValue.bitLength() > UUID.BIT_LENGTH) {
  +        if (bigIntValue.bitLength() > UUID.UUID_BIT_LENGTH) {
               throw new IllegalArgumentException("UUID must be contructed using a 128 bit
BigInteger");
           }
           numberValue = bigIntValue;
  +    } */
  +
  +    /**
  +     * <p>Copy constructor.</p>
  +     *
  +     * @param copyFrom the UUID to copy to create this UUID.
  +     */
  +    public UUID(UUID copyFrom) {
  +        super();
  +        rawBytes = copyFrom.getRawBytes();
       }
   
       /**
  @@ -144,10 +99,32 @@
        */
       public UUID(byte[] byteArray) throws IllegalArgumentException {
           super();
  -        if (byteArray.length != UUID.BYTE_LENGTH) {
  +        if (byteArray.length != UUID_BYTE_LENGTH) {
               throw new IllegalArgumentException("UUID must be contructed using a 16 byte
array.");
           }
  -        numberValue = new BigInteger(1, byteArray);
  +        // UUID must be immutable so a copy is used.
  +        System.arraycopy(byteArray, 0, rawBytes, 0, UUID_BYTE_LENGTH);
  +    }
  +
  +    /**
  +     * <p>Constructs a UUID from a DataInput. Note if 16 bytes are not available
this method will block.</p>
  +     *
  +     *  @param input the datainput with 16 bytes to read in from.
  +     *  @throws IOException exception if there is an IO problem also argument must contain
16 bytes.
  +     */
  +    public UUID(DataInput input) throws IOException {
  +        super();
  +        input.readFully(rawBytes, 0, UUID_BYTE_LENGTH);
  +    }
  +
  +    /**
  +     * <p>Constructs a UUID from two long values in most significant byte, and least
significant bytes order.</p>
  +     *
  +     * @param mostSignificant - the most significant 8 bytes of the uuid to be constructed.
  +     * @param leastSignificant - the least significant 8 bytes of the uuid to be constructed.
  +     */
  +    public UUID(long mostSignificant, long leastSignificant) {
  +       rawBytes = Bytes.append(Bytes.toBytes(mostSignificant), Bytes.toBytes(leastSignificant));
       }
   
       /**
  @@ -158,7 +135,7 @@
        */
       public UUID(String uuidString) throws UUIDFormatException {
           //Calls the copy constructor
  -        this(UUID.parseString(uuidString));
  +        this(UUID.fromString(uuidString));
       }
   
       /**
  @@ -168,7 +145,7 @@
        *  @throws UUIDFormatException the String must be a properly formatted UUID String.
        *  @return Returns a UUID or null if the formatted string could not be parsed.
        */
  -    public static UUID parseString(String uuidString)
  +    public static UUID fromString(String uuidString)
           throws UUIDFormatException {
           String leanString = uuidString.toLowerCase();
           UUID tmpUUID = null;
  @@ -192,7 +169,7 @@
           }
   
           //Remove the "-" from the formatted string and test token sizes
  -        StringBuffer buf = new StringBuffer();
  +        StringBuffer buf = new StringBuffer(UUID_UNFORMATTED_LENGTH);
           String token = null;
           int count = 0;
           while (tok.hasMoreTokens()) {
  @@ -203,19 +180,20 @@
               buf.append(token);
           }
   
  -        //Test creating a BigInteger from the hex value
  -        BigInteger bigIntValue = null;
  +        //Create from the hex value
           try {
  -            bigIntValue = new BigInteger(buf.toString(), BASE16);
  -        } catch (NumberFormatException nfe) {
  -              throw new UUIDFormatException();
  +            char[] chars = buf.toString().toCharArray();
  +            //TODO Remove check once codec 1.3 is released
  +            for (int i = 0; i < chars.length; i++) {
  +                if (Character.digit(chars[i], 16) == -1) {
  +                    throw new UUIDFormatException();
  +                }
  +            }
  +            // end check
  +            tmpUUID = new UUID(Hex.decodeHex(chars));
  +        } catch (DecoderException de) {
  +              throw new UUIDFormatException(de.getMessage());
          }
  -
  -        //Construct the UUID to return
  -        tmpUUID = new UUID(bigIntValue);
  -        // Set the uuidString value - the stringValue is "lazy" so set it now.
  -        tmpUUID.stringValue = leanString;
  -
           return tmpUUID;
       }
   
  @@ -227,11 +205,11 @@
       public String toString() {
           //set string value if not set
           if (stringValue == null) {
  -            StringBuffer buf = new StringBuffer(numberValue.toString(BASE16));
  +            StringBuffer buf = new StringBuffer(new String(Hex.encodeHex(rawBytes)));
               while (buf.length() != UUID_UNFORMATTED_LENGTH) {
                   buf.insert(0, "0");
               }
  -
  +            buf.ensureCapacity(UUID_FORMATTED_LENGTH);
               buf.insert(FORMAT_POSITION1, '-');
               buf.insert(FORMAT_POSITION2, '-');
               buf.insert(FORMAT_POSITION3, '-');
  @@ -248,22 +226,10 @@
        * @return Returns the urn string representation of the UUID
        */
       public String toUrn() {
  -        if (numberValue == null) {
  -            return null;
  -        }
           return URN_PREFIX + this.toString();
       }
   
       /**
  -     * <p>Returns the BigInteger representation of this UUID.</p>
  -     *
  -     * @return returns a BigInteger representing the value of this UUID
  -     */
  -    public BigInteger toBigInteger() {
  -        return numberValue;
  -    }
  -
  -    /**
        * <p>Compares two UUID for equality.</p>
        *
        * @see java.lang.Object#equals(Object)
  @@ -273,7 +239,7 @@
           if (!(obj instanceof UUID)) {
               return false;
           }
  -        return ((UUID) obj).toBigInteger().equals(this.numberValue);
  +        return Bytes.areEqual( ((UUID) obj).getRawBytes(), rawBytes);
       }
   
       /**
  @@ -282,15 +248,188 @@
        * @see java.lang.Object#hashCode()
        */
       public int hashCode() {
  -       return this.numberValue.hashCode();
  +        int iConstant = 37;
  +        int iTotal = 17;
  +        for (int i = 0; i < rawBytes.length; i++) {
  +            iTotal = iTotal * iConstant + rawBytes[i];
  +        }
  +       return iTotal;
  +    }
  +
  +    /**
  +     * <p>Compares two UUID's for equality</p>
  +     *
  +     * @see Comparable#compareTo(Object)
  +     */
  +    public int compareTo(Object compareTo) throws ClassCastException {
  +        if (!(compareTo instanceof UUID)) {
  +            throw new ClassCastException();
  +        }
  +        return (Bytes.compareTo(rawBytes, ((UUID) compareTo).getRawBytes()));
  +    }
  +
  +    /**
  +     * <p>Returns the clock sequence value in the UUID. The clock sequence is a random
assigned to a particular clock instance that
  +     * generated the time in the timestamp of a time based UUID.</p>
  +     *
  +     * @return the clock sequence value in the UUID.
  +     * @throws UnsupportedOperationException thrown if this is not a IETF variant or not
a time-based UUID.
  +     */
  +    public int clockSequence() throws UnsupportedOperationException {
  +        //if variant is not mealling leach salz throw unsupported operation exception
  +        if (variant() != VARIANT_IETF_DRAFT || version() != VERSION_ONE) {
  +            throw new UnsupportedOperationException(WRONG_VAR_VER_MSG);
  +        }
  +        if (clockSq == null) {
  +            byte[] b = {((byte) (rawBytes[8] & 0x3F)), rawBytes[9]};
  +            clockSq = new Short(Bytes.toShort(b));
  +        }
  +        return clockSq.intValue();
  +    }
  +
  +    /**
  +     * <p>Returns the version of the UUID.
  +     * <ul>
  +     *   <li>VERSION_ONE - The time-based version</li>
  +     *   <li>VERSION_TWO - DCE Security version, with embedded POSIX UIDs.</li>
  +     *   <li>VERSION_THREE - Name based UUID.</li>
  +     *   <li>VERSION_FOUR - Random based UUID.</li>
  +     * </ul>
  +     * </p>
  +     * @return the version of the UUID.
  +     */
  +    public int version() {
  +        if (version == -1) {
  +            version = ((rawBytes[6] >>> 4) & 0x0F);
  +        }
  +        return version;
  +    }
  +
  +    /**
  +     * <p>Returns the variant field of the UUID.</p>
  +     *
  +     * @return Returns the variant field of the UUID.
  +     * @see UUID#VARIANT_NCS_COMPAT
  +     * @see UUID#VARIANT_IETF_DRAFT
  +     * @see UUID#VARIANT_MS
  +     * @see UUID#VARIANT_FUTURE
  +     */
  +    public int variant() {
  +        if (variant == -1) {
  +            if ((rawBytes[8] & 0x80) == 0x0) {
  +                variant = VARIANT_NCS_COMPAT;
  +            } else if ((rawBytes[8] & 0x40) == 0x0) {
  +                variant = VARIANT_IETF_DRAFT;
  +            } else if ((rawBytes[8] & 0x20) == 0x0) {
  +                variant = VARIANT_MS;
  +            } else {
  +                variant = VARIANT_FUTURE;
  +            }
  +        }
  +        return variant;
  +    }
  +
  +    /**
  +     * <p>Returns the node identifier found in this UUID. The specification was written
such that this value holds the IEEE 802 MAC
  +     * address. The specification permits this value to be calculated from other sources
other than the MAC.</p>
  +     *
  +     * @return the node identifier found in this UUID.
  +     * @throws UnsupportedOperationException thrown if this is not a IETF variant or not
a time-based UUID.
  +     */
  +    public long node() throws UnsupportedOperationException {
  +        //if variant is not mealling leach salz throw unsupported operation exception
  +        if (variant() != VARIANT_IETF_DRAFT || version() != VERSION_ONE) {
  +            throw new UnsupportedOperationException(WRONG_VAR_VER_MSG);
  +        }
  +        if (node == null) {
  +            byte[] b = new byte[8];
  +            System.arraycopy(rawBytes, 10, b, 2, 6);
  +            node = new Long((Bytes.toLong(b) & 0xFFFFFFFFFFFFL));
  +        }
  +        return node.longValue();
  +    }
  +
  +    /**
  +     * <p>Returns the timestamp value of the UUID as 100-nano second intervals since
the Gregorian change offset (00:00:00.00, 15
  +     * October 1582 ).</p>
  +     *
  +     * @return the timestamp value of the UUID as 100-nano second intervals since the Gregorian
change offset.
  +     * @throws UnsupportedOperationException thrown if this is not a IETF variant or not
a time-based UUID.
  +     */
  +    public long timestamp() throws UnsupportedOperationException {
  +        //if variant is not mealling leach salz throw unsupported operation exception
  +        if (variant() != VARIANT_IETF_DRAFT || version() != VERSION_ONE) {
  +            throw new UnsupportedOperationException(WRONG_VAR_VER_MSG);
  +        }
  +        if (timestamp == -1) {
  +            byte[] longVal = new byte[8];
  +            System.arraycopy(rawBytes, TIME_HI_START_POS, longVal, TIME_HI_TS_POS, TIME_HI_BYTE_LEN);
  +            System.arraycopy(rawBytes, TIME_MID_START_POS, longVal, TIME_MID_TS_POS, TIME_MID_BYTE_LEN);
  +            System.arraycopy(rawBytes, TIME_LOW_START_POS, longVal, TIME_LOW_TS_POS, TIME_LOW_BYTE_LEN);
  +            longVal[TIME_HI_TS_POS] &= 0x0F;
  +            timestamp = Bytes.toLong(longVal);
  +        }
  +        return timestamp;
  +    }
  +
  +    /**
  +     * <p>Returns the least significant bits stored in the uuid's internal structure.</p>
  +     *
  +     * @return the least significant bits stored in the uuid's internal structure.
  +     */
  +    long getLeastSignificantBits()  {
  +        byte[] lsb = new byte[8];
  +        System.arraycopy(rawBytes, 8, lsb, 0, 8);
  +        return Bytes.toLong(lsb);
  +    }
  +
  +    /**
  +     * <p>Returns the least significant bits stored in the uuid's internal structure.</p>
  +     *
  +     * @return the least significant bits stored in the uuid's internal structure.
  +     */
  +    long getMostSignificantBits()  {
  +        byte[] msb = new byte[8];
  +        System.arraycopy(rawBytes, 0, msb, 0, 8);
  +        return Bytes.toLong(msb);
  +    }
  +
  +    /**
  +     * <p>Returns a copy of the byte values contained in this UUID.
  +     *
  +     * @return a copy of the byte values contained in this UUID.
  +     */
  +    public byte[] getRawBytes() {
  +        byte[] ret = new byte[UUID_BYTE_LENGTH];
  +        System.arraycopy(rawBytes, 0, ret, 0, UUID_BYTE_LENGTH);
  +        return ret;
  +    }
  +
  +    /**
  +     * <p>Returns a new version 4 UUID, based upon Random bits.</p>
  +     *
  +     * @return a new version 4 UUID, based upon Random bits.
  +     */
  +    static UUID randomUUID() {
  +        return (UUID) IdentifierUtils.UUID_VERSION_FOUR_GENERATOR.nextIdentifier();
  +    }
  +
  +    /**
  +     * <p>Returns a new version 1 UUID, based upon node identifier and time stamp.</p>
  +     *
  +     * @return a new version 1 UUID, based upon node identifier and time stamp.
  +     */
  +    static UUID timeUUID() {
  +        return (UUID) IdentifierUtils.UUID_VERSION_ONE_GENERATOR.nextIdentifier();
       }
   
       /**
  -     * </p>Clone method returns a copy of this UUID.</p>
  +     * <p>Returns a new version 3 UUID, based upon a name and namespace.</p>
        *
  -     * @see java.lang.Object#clone()
  +     * @return a new version 3 UUID, based upon a name and namespace.
        */
  -    public Object clone() {
  -        return new UUID(this);
  +    static UUID nameUUID() {
  +        /* @TODO */
  +        return null;
       }
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message