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