Development Class Java

/**
 * 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.
   * 


   * Of course, assuming UUIDs are randomized enough, even simpler approach
   * might be good enough?
   * 


   * 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) {
  }
}