/* * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.rmi.server; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.Serializable; import java.security.SecureRandom; /** * A UID represents an identifier that is unique over time * with respect to the host it is generated on, or one of 216 * "well-known" identifiers. * *

The {@link #UID()} constructor can be used to generate an * identifier that is unique over time with respect to the host it is * generated on. The {@link #UID(short)} constructor can be used to * create one of 216 well-known identifiers. * *

A UID instance contains three primitive values: *

* *

An independently generated UID instance is unique * over time with respect to the host it is generated on as long as * the host requires more than one millisecond to reboot and its system * clock is never set backward. A globally unique identifier can be * constructed by pairing a UID instance with a unique host * identifier, such as an IP address. * * @author Ann Wollrath * @author Peter Jones * @since JDK1.1 */ public final class UID implements Serializable { private static int hostUnique; private static boolean hostUniqueSet = false; private static final Object lock = new Object(); private static long lastTime = System.currentTimeMillis(); private static short lastCount = Short.MIN_VALUE; /** indicate compatibility with JDK 1.1.x version of class */ private static final long serialVersionUID = 1086053664494604050L; /** * number that uniquely identifies the VM that this UID * was generated in with respect to its host and at the given time * @serial */ private final int unique; /** * a time (as returned by {@link System#currentTimeMillis()}) at which * the VM that this UID was generated in was alive * @serial */ private final long time; /** * 16-bit number to distinguish UID instances created * in the same VM with the same time value * @serial */ private final short count; /** * Generates a UID that is unique over time with * respect to the host that it was generated on. */ public UID() { synchronized (lock) { if (!hostUniqueSet) { hostUnique = (new SecureRandom()).nextInt(); hostUniqueSet = true; } unique = hostUnique; if (lastCount == Short.MAX_VALUE) { boolean interrupted = Thread.interrupted(); boolean done = false; while (!done) { long now = System.currentTimeMillis(); if (now == lastTime) { // wait for time to change try { Thread.sleep(1); } catch (InterruptedException e) { interrupted = true; } } else { // If system time has gone backwards increase // original by 1ms to maintain uniqueness lastTime = (now < lastTime) ? lastTime+1 : now; lastCount = Short.MIN_VALUE; done = true; } } if (interrupted) { Thread.currentThread().interrupt(); } } time = lastTime; count = lastCount++; } } /** * Creates a "well-known" UID. * * There are 216 possible such well-known ids. * *

A UID created via this constructor will not * clash with any UIDs generated via the no-arg * constructor. * * @param num number for well-known UID */ public UID(short num) { unique = 0; time = 0; count = num; } /** * Constructs a UID given data read from a stream. */ private UID(int unique, long time, short count) { this.unique = unique; this.time = time; this.count = count; } /** * Returns the hash code value for this UID. * * @return the hash code value for this UID */ public int hashCode() { return (int) time + (int) count; } /** * Compares the specified object with this UID for * equality. * * This method returns true if and only if the * specified object is a UID instance with the same * unique, time, and count * values as this one. * * @param obj the object to compare this UID to * * @return true if the given object is equivalent to * this one, and false otherwise */ public boolean equals(Object obj) { if (obj instanceof UID) { UID uid = (UID) obj; return (unique == uid.unique && count == uid.count && time == uid.time); } else { return false; } } /** * Returns a string representation of this UID. * * @return a string representation of this UID */ public String toString() { return Integer.toString(unique,16) + ":" + Long.toString(time,16) + ":" + Integer.toString(count,16); } /** * Marshals a binary representation of this UID to * a DataOutput instance. * *

Specifically, this method first invokes the given stream's * {@link DataOutput#writeInt(int)} method with this UID's * unique value, then it invokes the stream's * {@link DataOutput#writeLong(long)} method with this UID's * time value, and then it invokes the stream's * {@link DataOutput#writeShort(int)} method with this UID's * count value. * * @param out the DataOutput instance to write * this UID to * * @throws IOException if an I/O error occurs while performing * this operation */ public void write(DataOutput out) throws IOException { out.writeInt(unique); out.writeLong(time); out.writeShort(count); } /** * Constructs and returns a new UID instance by * unmarshalling a binary representation from an * DataInput instance. * *

Specifically, this method first invokes the given stream's * {@link DataInput#readInt()} method to read a unique value, * then it invoke's the stream's * {@link DataInput#readLong()} method to read a time value, * then it invoke's the stream's * {@link DataInput#readShort()} method to read a count value, * and then it creates and returns a new UID instance * that contains the unique, time, and * count values that were read from the stream. * * @param in the DataInput instance to read * UID from * * @return unmarshalled UID instance * * @throws IOException if an I/O error occurs while performing * this operation */ public static UID read(DataInput in) throws IOException { int unique = in.readInt(); long time = in.readLong(); short count = in.readShort(); return new UID(unique, time, count); } }