diff -r 4ebc2e2fb97c -r 71c04702a3d5 src/java.rmi/share/classes/java/rmi/server/UID.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.rmi/share/classes/java/rmi/server/UID.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,269 @@ +/* + * 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 1.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); + } +}