001    /* UID.java -- The unique object Id
002       Copyright (c) 2006 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010     
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.rmi.server;
040    
041    import java.io.DataInput;
042    import java.io.DataOutput;
043    import java.io.IOException;
044    import java.io.Serializable;
045    import 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     */
056    public 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    }