001/* UID.java -- The unique object Id
002   Copyright (c) 2006 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010 
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.rmi.server;
040
041import java.io.DataInput;
042import java.io.DataOutput;
043import java.io.IOException;
044import java.io.Serializable;
045import java.net.InetAddress;
046
047/**
048 * Represents the unique identifier over time for the host which has generated
049 * it. It contains time (when created), counter (the number of the UID
050 * creation order) and virtual machine id components. The UID can also be
051 * constructed specifying a "well known" identifier in the for of short:
052 * this identifier defines the UID uniqueness alone. 
053 * 
054 * @author Audrius Meskauskas (audriusa@bioinformatics.org)
055 */
056public final class UID
057    implements Serializable
058{
059  /**
060   * Use the serial version uid for interoperability.
061   */
062  private static final long serialVersionUID = 1086053664494604050L;
063 
064  /**
065   * The UID counter (the ordinary number in the sequence of number of UID's,
066   * created during the recent millisecond). In the next millisecond, it 
067   * starts from the minimal value again. In the unlikely case of creating
068   * more than 65536 uids per millisecond the process pauses till the next
069   * ms.
070   */
071  private static short uidCounter = Short.MIN_VALUE;
072  
073  /**
074   * The time, when the last UID has been created.
075   */
076  private static long last;
077
078  /**
079   * This constant tries to be the unique identifier of the virtual machine.
080   */
081  private static final int machineId = getMachineId();
082
083  /**
084   * The UID number in the UID creation sequence.
085   */
086  private short count;
087
088  /**
089   * Always gets the uniqueNr value.
090   */
091  private int unique;
092
093  /**
094   * The time stamp, when the UID was created.
095   */
096  private long time;
097  
098  /**
099   * Create the new UID that would have the described features of the
100   * uniqueness.
101   */
102  public UID()
103  {
104    synchronized (UID.class)
105      {
106        time = System.currentTimeMillis();
107        unique = machineId;
108        if (time > last)
109          {
110            last = time;
111            count = uidCounter = Short.MIN_VALUE;
112          }
113        else
114          {
115            if (uidCounter == Short.MAX_VALUE)
116              {
117                // Make a 2 ms pause if the counter has reached the maximal
118                // value. This should seldom happen.
119                try
120                  {
121                    Thread.sleep(2);
122                  }
123                catch (InterruptedException e)
124                  {
125                  }
126                uidCounter = Short.MIN_VALUE;
127                time = last = System.currentTimeMillis();
128              }
129            count = ++uidCounter;
130          }
131      }
132  }
133  
134  /**
135   * Create the new UID with the well known id (number). All UIDs, creates
136   * with the this constructor having the same parameter are equal to each
137   * other (regardless to the host and time where they were created.
138   * 
139   * @param wellKnownId the well known UID.
140   */
141  public UID(short wellKnownId)
142  {
143    unique = wellKnownId;
144  }
145  
146  /**
147   * Get the hashCode of this UID.
148   */
149  public int hashCode()
150  {
151    return (int) (unique ^ time ^ count);
152  }
153  
154  /**
155   * Compare this UID with another UID for equality (not equal to other types of
156   * objects).
157   */
158  public boolean equals(Object other)
159  {
160    if (other instanceof UID)
161      {
162        UID ui = (UID) other;
163        return unique == ui.unique && time == ui.time && count == ui.count;
164      }
165    else
166      return false;
167  }
168  
169  public static UID read(DataInput in) throws IOException
170  {
171    UID uid = new UID();
172    uid.unique = in.readInt();
173    uid.time = in.readLong();
174    uid.count = in.readShort();
175    return (uid);
176  }
177
178  public void write(DataOutput out) throws IOException
179  {
180    out.writeInt(unique);
181    out.writeLong(time);
182    out.writeShort(count);
183  }
184
185  /**
186   * Do our best to get the Id of this virtual machine.
187   */
188  static int getMachineId()
189  {
190    int hostIpHash;
191
192    try
193      {
194        // Try to get the host IP.
195        String host = InetAddress.getLocalHost().toString();
196        // This hash is content - based, not the address based.
197        hostIpHash = host.hashCode();
198      }
199    catch (Exception e)
200      {
201        // Failed due some reason.
202        hostIpHash = 0;
203      }
204
205    // Should be the unque address if hashcodes are addresses.
206    // Additionally, add the time when the RMI system was probably started
207    // (this class was first instantiated).
208    return new Object().hashCode() ^ (int) System.currentTimeMillis()
209           ^ hostIpHash;
210  }
211  
212    /**
213   * Get the string representation of this UID.
214   * 
215   * @return a string, uniquely identifying this id.
216   */
217  public String toString()
218  {
219    int max = Character.MAX_RADIX;
220    // Translate into object count, counting from 0.
221    long lc = (count - Short.MIN_VALUE) & 0xFFFF;
222    return Long.toString(unique, max) + ":" + Long.toString(time, max) + "."
223           + Long.toString(lc, max);
224  }
225}