1. /*
  2. * @(#)UID.java 1.22 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.rmi.server;
  8. import java.io.DataInput;
  9. import java.io.DataOutput;
  10. import java.io.EOFException;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.io.OutputStream;
  14. import java.security.SecureRandom;
  15. /**
  16. * A <code>UID</code> represents an identifier that is unique over time
  17. * with respect to the host it is generated on, or one of 2<sup>16</sup>
  18. * "well-known" identifiers.
  19. *
  20. * <p>The {@link #UID()} constructor can be used to generate an
  21. * identifier that is unique over time with respect to the host it is
  22. * generated on. The {@link #UID(short)} constructor can be used to
  23. * create one of 2<sup>16</sup> well-known identifiers.
  24. *
  25. * <p>A <code>UID</code> instance contains three primitive values:
  26. * <ul>
  27. * <li><code>unique</code>, an <code>int</code> that uniquely identifies
  28. * the VM that this <code>UID</code> was generated in, with respect to its
  29. * host and at the time represented by the <code>time</code> value (an
  30. * example implementation of the <code>unique</code> value would be a
  31. * process identifier),
  32. * or zero for a well-known <code>UID</code>
  33. * <li><code>time</code>, a <code>long</code> equal to a time (as returned
  34. * by {@link System#currentTimeMillis()}) at which the VM that this
  35. * <code>UID</code> was generated in was alive,
  36. * or zero for a well-known <code>UID</code>
  37. * <li><code>count</code>, a <code>short</code> to distinguish
  38. * <code>UID</code>s generated in the same VM with the same
  39. * <code>time</code> value
  40. * </ul>
  41. *
  42. * <p>An independently generated <code>UID</code> instance is unique
  43. * over time with respect to the host it is generated on as long as
  44. * the host requires more than one millisecond to reboot and its system
  45. * clock is never set backward. A globally unique identifier can be
  46. * constructed by pairing a <code>UID</code> instance with a unique host
  47. * identifier, such as an IP address.
  48. *
  49. * @author Ann Wollrath
  50. * @author Peter Jones
  51. * @version 1.22, 03/12/19
  52. * @since JDK1.1
  53. */
  54. public final class UID implements java.io.Serializable {
  55. private static final long ONE_SECOND = 1000; // in milliseconds
  56. private static int hostUnique;
  57. private static boolean hostUniqueSet = false;
  58. private static final Object lock = new Object();
  59. private static long lastTime = System.currentTimeMillis();
  60. private static short lastCount = Short.MIN_VALUE;
  61. /** indicate compatibility with JDK 1.1.x version of class */
  62. private static final long serialVersionUID = 1086053664494604050L;
  63. /**
  64. * number that uniquely identifies the VM that this <code>UID</code>
  65. * was generated in with respect to its host and at the given time
  66. * @serial
  67. */
  68. private final int unique;
  69. /**
  70. * a time (as returned by {@link System#currentTimeMillis()}) at which
  71. * the VM that this <code>UID</code> was generated in was alive
  72. * @serial
  73. */
  74. private final long time;
  75. /**
  76. * 16-bit number to distinguish <code>UID</code> instances created
  77. * in the same VM with the same time value
  78. * @serial
  79. */
  80. private final short count;
  81. /**
  82. * Generates a <code>UID</code> that is unique over time with
  83. * respect to the host that it was generated on.
  84. */
  85. public UID() {
  86. synchronized (lock) {
  87. if (!hostUniqueSet) {
  88. hostUnique = (new SecureRandom()).nextInt();
  89. hostUniqueSet = true;
  90. }
  91. unique = hostUnique;
  92. if (lastCount == Short.MAX_VALUE) {
  93. boolean done = false;
  94. while (!done) {
  95. long now = System.currentTimeMillis();
  96. if (now < lastTime + ONE_SECOND) {
  97. // pause for a second to wait for time to change
  98. try {
  99. Thread.currentThread().sleep(ONE_SECOND);
  100. } catch (java.lang.InterruptedException e) {
  101. } // ignore exception
  102. continue;
  103. } else {
  104. lastTime = now;
  105. lastCount = Short.MIN_VALUE;
  106. done = true;
  107. }
  108. }
  109. }
  110. time = lastTime;
  111. count = lastCount++;
  112. }
  113. }
  114. /**
  115. * Creates a "well-known" <code>UID</code>.
  116. *
  117. * There are 2<sup>16</sup> possible such well-known ids.
  118. *
  119. * <p>A <code>UID</code> created via this constructor will not
  120. * clash with any <code>UID</code>s generated via the no-arg
  121. * constructor.
  122. *
  123. * @param num number for well-known <code>UID</code>
  124. */
  125. public UID(short num) {
  126. unique = 0;
  127. time = 0;
  128. count = num;
  129. }
  130. /**
  131. * Constructs a <code>UID</code> given data read from a stream.
  132. */
  133. private UID(int unique, long time, short count) {
  134. this.unique = unique;
  135. this.time = time;
  136. this.count = count;
  137. }
  138. /**
  139. * Returns the hash code value for this <code>UID</code>.
  140. *
  141. * @return the hash code value for this <code>UID</code>
  142. */
  143. public int hashCode() {
  144. return (int) time + (int) count;
  145. }
  146. /**
  147. * Compares the specified object with this <code>UID</code> for
  148. * equality.
  149. *
  150. * This method returns <code>true</code> if and only if the
  151. * specified object is a <code>UID</code> instance with the same
  152. * <code>unique</code>, <code>time</code>, and <code>count</code>
  153. * values as this one.
  154. *
  155. * @param obj the object to compare this <code>UID</code> to
  156. *
  157. * @return <code>true</code> if the given object is equivalent to
  158. * this one, and <code>false</code> otherwise
  159. */
  160. public boolean equals(Object obj) {
  161. if (obj instanceof UID) {
  162. UID uid = (UID)obj;
  163. return (unique == uid.unique &&
  164. count == uid.count &&
  165. time == uid.time);
  166. } else {
  167. return false;
  168. }
  169. }
  170. /**
  171. * Returns a string representation of this <code>UID</code>.
  172. *
  173. * @return a string representation of this <code>UID</code>
  174. */
  175. public String toString() {
  176. return Integer.toString(unique,16) + ":" +
  177. Long.toString(time,16) + ":" +
  178. Integer.toString(count,16);
  179. }
  180. /**
  181. * Marshals a binary representation of this <code>UID</code> to
  182. * a <code>DataOutput</code> instance.
  183. *
  184. * <p>Specifically, this method first invokes the given stream's
  185. * {@link DataOutput#writeInt(int)} method with this <code>UID</code>'s
  186. * <code>unique</code> value, then it invokes the stream's
  187. * {@link DataOutput#writeLong(long)} method with this <code>UID</code>'s
  188. * <code>time</code> value, and then it invokes the stream's
  189. * {@link DataOutput#writeShort(int)} method with this <code>UID</code>'s
  190. * <code>count</code> value.
  191. *
  192. * @param out the <code>DataOutput</code> instance to write
  193. * this <code>UID</code> to
  194. *
  195. * @throws IOException if an I/O error occurs while performing
  196. * this operation
  197. */
  198. public void write(DataOutput out) throws IOException {
  199. out.writeInt(unique);
  200. out.writeLong(time);
  201. out.writeShort(count);
  202. }
  203. /**
  204. * Constructs and returns a new <code>UID</code> instance by
  205. * unmarshalling a binary representation from an
  206. * <code>DataInput</code> instance.
  207. *
  208. * <p>Specifically, this method first invokes the given stream's
  209. * {@link DataInput#readInt()} method to read a <code>unique</code> value,
  210. * then it invoke's the stream's
  211. * {@link DataInput#readLong()} method to read a <code>time</code> value,
  212. * then it invoke's the stream's
  213. * {@link DataInput#readShort()} method to read a <code>count</code> value,
  214. * and then it creates and returns a new <code>UID</code> instance
  215. * that contains the <code>unique</code>, <code>time</code>, and
  216. * <code>count</code> values that were read from the stream.
  217. *
  218. * @param in the <code>DataInput</code> instance to read
  219. * <code>UID</code> from
  220. *
  221. * @return unmarshalled <code>UID</code> instance
  222. *
  223. * @throws IOException if an I/O error occurs while performing
  224. * this operation
  225. */
  226. public static UID read(DataInput in) throws IOException {
  227. int unique = in.readInt();
  228. long time = in.readLong();
  229. short count = in.readShort();
  230. return new UID(unique, time, count);
  231. }
  232. }