All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.id.uuid.UUID Maven / Gradle / Ivy

/*
 * 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.
 */
package org.apache.commons.id.uuid;

import org.apache.commons.id.DecoderException;
import org.apache.commons.id.DigestUtils;
import org.apache.commons.id.Hex;

import java.io.DataInput;
import java.io.IOException;
import java.io.Serializable;
import java.util.StringTokenizer;


/**
 * 

UUID represents a Universally Unique Identifier per RFC 4122. * See the RFC 4122: * A Universally Unique IDentifier (UUID) URN Namespace * for more information.

* * @author Commons-Id Team * @version $Revision: 480488 $ $Date: 2006-11-29 00:57:26 -0800 (Wed, 29 Nov 2006) $ * */ public class UUID implements Constants, Serializable, Comparable { /** byte array to store 128-bits composing this UUID */ private byte[] rawBytes = new byte[UUID_BYTE_LENGTH]; /** Holds node identifier for this UUID */ private Long node = null; /** Holds timestamp for this UUID */ private long timestamp = -1; /** Holds the clock sequence field */ private Short clockSq = null; /** Holds the version field of this UUID */ private int version = -1; /** 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(); } /** *

Constructs a UUID from a 128 bit java.math.BigInteger.

*

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.

* * @param bigIntValue the 128 bit BigInteger to construct this UUID from. * @throws IllegalArgumentException argument must be 128 bit */ /* protected UUID(BigInteger bigIntValue) throws IllegalArgumentException { super(); if (bigIntValue.bitLength() > UUID.UUID_BIT_LENGTH) { throw new IllegalArgumentException("UUID must be contructed using a 128 bit BigInteger"); } numberValue = bigIntValue; } */ /** *

Copy constructor.

* * @param copyFrom the UUID to copy to create this UUID. */ public UUID(UUID copyFrom) { super(); rawBytes = copyFrom.getRawBytes(); } /** *

Constructs a UUID from a 16 byte array.

* * @param byteArray the 16 byte array to construct this UUID from. * @throws IllegalArgumentException argument must be 16 bytes */ public UUID(byte[] byteArray) throws IllegalArgumentException { super(); if (byteArray.length != UUID_BYTE_LENGTH) { throw new IllegalArgumentException("UUID must be contructed using a 16 byte array."); } // UUID must be immutable so a copy is used. System.arraycopy(byteArray, 0, rawBytes, 0, UUID_BYTE_LENGTH); } /** *

Constructs a UUID from a DataInput. Note if 16 bytes are not available this method will block.

* * @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); } /** *

Constructs a UUID from two long values in most significant byte, and least significant bytes order.

* * @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)); } /** *

Constructs a UUID from a UUID formatted String.

* * @param uuidString the String representing a UUID to construct this UUID * @throws UUIDFormatException String must be a properly formatted UUID string */ public UUID(String uuidString) throws UUIDFormatException { //Calls the copy constructor this(UUID.fromString(uuidString)); } /** *

Parses a string for a UUID.

* * @param uuidString the UUID formatted String to parse. * @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 fromString(String uuidString) throws UUIDFormatException { String leanString = uuidString.toLowerCase(); UUID tmpUUID = null; //Handle prefixed UUIDs // e.g. urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6 int pos = uuidString.lastIndexOf(":"); if (pos > 1) { leanString = uuidString.substring(++pos, uuidString.length()); } //Check for 36 char length if (leanString.length() != UUID_FORMATTED_LENGTH) { throw new UUIDFormatException(uuidString); } //Check for 5 fields StringTokenizer tok = new StringTokenizer(leanString, "-"); if ( tok.countTokens() != TOKENS_IN_UUID ) { throw new UUIDFormatException(uuidString); } //Remove the "-" from the formatted string and test token sizes StringBuffer buf = new StringBuffer(UUID_UNFORMATTED_LENGTH); String token = null; int count = 0; while (tok.hasMoreTokens()) { token = tok.nextToken(); if (token.length() != TOKEN_LENGTHS[count++]) { throw new UUIDFormatException(uuidString); } buf.append(token); } //Create from the hex value try { char[] chars = buf.toString().toCharArray(); tmpUUID = new UUID(Hex.decodeHex(chars)); } catch (DecoderException de) { throw new UUIDFormatException(uuidString + ": " + de.getMessage()); } return tmpUUID; } /** *

Returns a string representation of the UUID.

* * @return a string representation of the UUID formatted according to the specification. */ public String toString() { //set string value if not set if (stringValue == null) { 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, '-'); buf.insert(FORMAT_POSITION4, '-'); stringValue = buf.toString(); } return stringValue; } /** *

Returns a urn representation of the UUID. This is same as the * toString() value prefixed with urn:uuid:

* * @return Returns the urn string representation of the UUID */ public String toUrn() { return URN_PREFIX + this.toString(); } /** *

Compares two UUID for equality.

* * @see java.lang.Object#equals(Object) */ public boolean equals(Object obj) { if (!(obj instanceof UUID)) { return false; } return Bytes.areEqual( ((UUID) obj).getRawBytes(), rawBytes); } /** *

Returns a hash code value for the object.

* * @see java.lang.Object#hashCode() */ public int hashCode() { int iConstant = 37; int iTotal = 17; for (int i = 0; i < rawBytes.length; i++) { iTotal = iTotal * iConstant + rawBytes[i]; } return iTotal; } /** *

Compares two UUID's for equality.

* * @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())); } /** *

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.

* * @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(); } /** *

Returns the version of the UUID. *

    *
  • VERSION_ONE - The time-based version
  • *
  • VERSION_TWO - DCE Security version, with embedded POSIX UIDs.
  • *
  • VERSION_THREE - Name based UUID with MD5 hashing.
  • *
  • VERSION_FOUR - Random based UUID.
  • *
  • VERSION_FIVE - Name based UUID with SHA-1 hashing.
  • *
*

* @return the version of the UUID. */ public int version() { if (version == -1) { version = ((rawBytes[6] >>> 4) & 0x0F); } return version; } /** *

Returns the variant field of the UUID.

* * @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; } /** *

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.

* * @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(); } /** *

Returns the timestamp value of the UUID as 100-nano second intervals since the Gregorian change offset (00:00:00.00, 15 * October 1582 ).

* * @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; } /** *

Returns the least significant bits stored in the uuid's internal structure.

* * @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); } /** *

Returns the least significant bits stored in the uuid's internal structure.

* * @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); } /** *

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; } /** *

Returns a new version 4 UUID, based upon Random bits.

* * @return a new version 4 UUID, based upon Random bits. */ public static UUID randomUUID() { return VersionFourGenerator.getInstance().nextUUID(); } /** *

Returns a new version 1 UUID, based upon node identifier and time stamp.

* * @return a new version 1 UUID, based upon node identifier and time stamp. */ public static UUID timeUUID() { return VersionOneGenerator.getInstance().nextUUID(); } /** *

Returns a new version three (MD5) or five (SHA-1) UUID, using the specified encoding * given a name and the namespace's UUID.

* * @param name String the name to calculate the UUID for. * @param namespace UUID assigned to this namespace. * @param encoding The encoding to use, either #{link UUID.MD5_ENCODING} or #{link UUID.SHA1_ENCODING} * @return a new version three UUID given a name and the namespace's UUID. */ public static UUID nameUUIDFromString(String name, UUID namespace, String encoding) { byte[] nameAsBytes = name.getBytes(); byte[] concat = new byte[UUID_BYTE_LENGTH + nameAsBytes.length]; System.arraycopy(namespace.getRawBytes(), 0, concat, 0, UUID_BYTE_LENGTH); System.arraycopy(nameAsBytes, 0, concat, UUID_BYTE_LENGTH, nameAsBytes.length); byte[] raw = null; if(encoding.equals(UUID.MD5_ENCODING)) { raw = DigestUtils.md5(concat); } else if(encoding.equals(UUID.SHA1_ENCODING)) { byte[] shaDigest = DigestUtils.sha(concat); // Truncate digest to 16 bytes (SHA-1 returns a 20-byte digest) raw = new byte[16]; System.arraycopy(shaDigest, 0, raw, 0, 16); } else { throw new RuntimeException("Unsupported encoding " + encoding); } //Set version (version 3 and version 5 are identical on a bit-level, //thus we only need ever set one of them raw[TIME_HI_AND_VERSION_BYTE_6] &= 0x0F; raw[TIME_HI_AND_VERSION_BYTE_6] |= (UUID.VERSION_THREE << 4); //Set variant raw[CLOCK_SEQ_HI_AND_RESERVED_BYTE_8] &= 0x3F; //0011 1111 raw[CLOCK_SEQ_HI_AND_RESERVED_BYTE_8] |= 0x80; //1000 0000 return new UUID(raw); } /** *

Returns a new version three UUID given a name and the namespace's UUID.

* * @param name String the name to calculate the UUID for. * @param namespace UUID assigned to this namespace. * @return a new version three UUID given a name and the namespace's UUID. * */ public static UUID nameUUIDFromString(String name, UUID namespace) { return nameUUIDFromString(name, namespace, UUID.MD5_ENCODING); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy