/* JUG Java Uuid Generator * * Copyright (c) 2002- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in the file licenses/LICENSE.txt which is * included with the source code. * You may not use this file except in compliance with the License. * * 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.jboss.messaging.util; /** * UUID represents Universally Unique Identifiers (aka Global UID in Windows * world). UUIDs are usually generated via UUIDGenerator (or in case of 'Null * UUID', 16 zero bytes, via static method getNullUUID()), or received from * external systems. * * By default class caches the string presentations of UUIDs so that description * is only created the first time it's needed. For memory stingy applications * this caching can be turned off (note though that if uuid.toString() is never * called, desc is never calculated so only loss is the space allocated for the * desc pointer... which can of course be commented out to save memory). * * Similarly, hash code is calculated when it's needed for the first time, and * from thereon that value is just returned. This means that using UUIDs as keys * should be reasonably efficient. * * UUIDs can be compared for equality, serialized, cloned and even sorted. * Equality is a simple bit-wise comparison. Ordering (for sorting) is done by * first ordering based on type (in the order of numeric values of types), * secondarily by time stamp (only for time-based time stamps), and finally by * straight numeric byte-by-byte comparison (from most to least significant * bytes). */ public class UUID { 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; 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; /** * 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; } /** * 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; } /** * 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; } }