001    /* UUID.java -- Class that represents a UUID object.
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.util;
040    
041    import java.io.Serializable;
042    import java.security.MessageDigest;
043    import java.security.NoSuchAlgorithmException;
044    
045    /**
046     * This class represents a 128-bit UUID value.
047     * 
048     * There are several types of UUID, and while this class can be used to store
049     * them, only the Leach-Salz (variant 2) UUID specified in RFC-4122 will 
050     * give meaningful results from the method calls.
051     * See: http://tools.ietf.org/html/4122 for the details
052     *
053     * The format of a Leach-Salz (variant 2) time-based (version 1) UUID 
054     * is as follows:
055     * time_low - upper 32 bits of the most significant 64 bits,
056     *            this is the least-significant part of the timestamp.
057     *
058     * time_mid - bits 16-31 of the most significant 64 bits,
059     *            this is the middle portion of the timestamp. 
060     *
061     * version  - bits 8-15 of the most significant 64 bits. 
062     *
063     * time_hi  - bits 0-7 of the most significant 64 bits,
064     *            the most significant portion of the timestamp.
065     *
066     * clock_and_reserved  - bits 48-63 of the least significant 64 bits.
067     *                       a variable number of bits hold the variant 
068     *                       (see the spec)
069     * 
070     * node identifier     - bits 0-47 of the least signficant 64 bits.
071     *
072     * These fields are valid only for version 1, in the remaining versions,
073     * only the version and variant fields are set, all others are used for data.
074     *
075     * @since 1.5
076     * @author Sven de Marothy
077     */
078    public final class UUID 
079      extends Object 
080      implements Serializable, Comparable<UUID>
081    {
082      private static final long serialVersionUID = -4856846361193249489L;
083    
084      /**
085       * Serialized field - most significant 64 bits.
086       */
087      private long mostSigBits;
088    
089      /**
090       * Serialized field - least significant 64 bits.
091       */
092      private long leastSigBits;
093    
094      /**
095       * Random-number generator.
096       */
097      private static transient Random r = new Random();
098    
099      /**
100       * Constructs a new UUID.
101       *
102       * @since 1.5
103       */
104      public UUID(long mostSigBits, long leastSigBits)
105      {
106        this.mostSigBits = mostSigBits;
107        this.leastSigBits = leastSigBits;
108      }
109     
110      /**
111       * Returns the clock-sequence value of this UUID.
112       * This field only exists in a time-based (version 1) UUID.
113       *
114       * @throws UnsupportedOperationException if the UUID type is not 1.
115       * @returns an int containing the clock-sequence value.
116       */
117      public int clockSequence()
118      {
119        if( version() != 1 )
120          throw new UnsupportedOperationException("Not a type 1 UUID");
121        return (int)((leastSigBits & 0x3FFF000000000000L) >> 48);
122      }
123    
124      /**
125       * Compare this UUID to another.
126       * The comparison is performed as between two 128-bit integers.
127       *
128       * @return -1 if this < val, 0 if they are equal, 1 if this > val.
129       */
130      public int compareTo(UUID o)
131      {
132        if( mostSigBits < o.mostSigBits )
133          return -1;
134        if( mostSigBits > o.mostSigBits )
135          return 1;
136        if( leastSigBits < o.leastSigBits )
137          return -1;
138        if( leastSigBits > o.mostSigBits )
139          return 1;
140        return 0;
141      }
142    
143      /**
144       * Compare a (UUID) object to this one
145       */
146      public boolean equals(Object obj)
147      {
148        if( !(obj instanceof UUID ) )
149          return false;
150        return ( ((UUID)obj).mostSigBits == mostSigBits && 
151                 ((UUID)obj).leastSigBits == leastSigBits );
152      }
153    
154      /**
155       * Creates a UUID object from a Sting representation.
156       *
157       * For the format of the string,
158       * @see #toString()
159       *
160       * @return a new UUID object.
161       */
162      public static UUID fromString(String name)
163      {
164        StringTokenizer st = new StringTokenizer( name.trim(), "-" );
165        if( st.countTokens() < 5 )
166          throw new IllegalArgumentException( "Incorrect UUID string"+
167                                              " representation:"+name );
168    
169        long msb = (Long.parseLong(st.nextToken(), 16) << 32); // time low
170        msb |= (Long.parseLong(st.nextToken(), 16) << 16); // time mid
171        msb |= Long.parseLong(st.nextToken(), 16); // time high
172    
173        long lsb = (Long.parseLong(st.nextToken(), 16) << 48); // clock
174        lsb |= Long.parseLong(st.nextToken(), 16); // node
175    
176        return new UUID(msb, lsb);
177      }
178    
179      /**
180       * Returns a String representation of the UUID.
181       *
182       * The format of the standard string representation (given in RFC4122) is:
183       *
184       * time-low "-" time-mid "-"
185       * time-high-and-version "-"
186       * clock-seq-and-reserved
187       * clock-seq-low "-" node
188       *
189       * Where each field is represented as a hex string.
190       *
191       * @return the String representation.
192       */
193      public String toString()
194      {
195        return // time-low first
196          padHex( (( mostSigBits & 0xFFFFFFFF00000000L) >> 32) & 0xFFFFFFFFL, 8)
197          + "-" + // then time-mid
198          padHex( (( mostSigBits & 0xFFFF0000L ) >> 16), 4 ) 
199          + "-" + // time-high
200          padHex( ( mostSigBits & 0x0000000000000000FFFFL ), 4 ) 
201          + "-" + // clock (note - no reason to separate high and low here)
202          padHex( (((leastSigBits & 0xFFFF000000000000L) >> 48) & 0xFFFF), 4 ) 
203          + "-" + // finally the node value.
204          padHex(leastSigBits & 0xFFFFFFFFFFFFL, 12); 
205      }
206    
207      /**
208       * Returns the least significant 64 bits of the UUID as a <code>long</code>.
209       */ 
210      public long getLeastSignificantBits()
211      {
212        return leastSigBits;
213      }
214    
215      /**
216       * Returns the most significant 64 bits of the UUID as a <code>long</code>.
217       */ 
218      public long getMostSignificantBits()
219      {
220        return mostSigBits;
221      }
222    
223      /**
224       * Returns a hash of this UUID.
225       */
226      public int hashCode()
227      {
228        int l1 = (int)(leastSigBits & 0xFFFFFFFFL);
229        int l2 = (int)((leastSigBits & 0xFFFFFFFF00000000L) >> 32);
230        int m1 = (int)(mostSigBits & 0xFFFFFFFFL);
231        int m2 = (int)((mostSigBits & 0xFFFFFFFF00000000L) >> 32);
232    
233        return (l1 ^ l2) ^ (m1 ^ m2);
234      }
235    
236      /**
237       * Creates a UUID version 3 object (name based with MD5 hashing)
238       * from a series of bytes representing a name.
239       */
240      public static UUID nameUUIDFromBytes(byte[] name)
241      {    
242        long msb, lsb;
243        byte[] hash;
244    
245        try
246          {
247            MessageDigest md5 = MessageDigest.getInstance("MD5");
248            hash = md5.digest( name );
249          } 
250        catch (NoSuchAlgorithmException e) 
251          {
252            throw new UnsupportedOperationException("No MD5 algorithm available.");
253          }
254            
255        msb = ((hash[0] & 0xFFL) << 56) | ((hash[1] & 0xFFL) << 48) |
256          ((hash[2] & 0xFFL) << 40) | ((hash[3] & 0xFFL) << 32) |
257          ((hash[4] & 0xFFL) << 24) | ((hash[5] & 0xFFL) << 16) |
258          ((hash[6] & 0xFFL) << 8) | (hash[7] & 0xFFL);
259    
260        lsb = ((hash[8] & 0xFFL) << 56) | ((hash[9] & 0xFFL) << 48) |
261          ((hash[10] & 0xFFL) << 40) | ((hash[11] & 0xFFL) << 32) |
262          ((hash[12] & 0xFFL) << 24) | ((hash[13] & 0xFFL) << 16) |
263          ((hash[14] & 0xFFL) << 8) | (hash[15] & 0xFFL);
264    
265        lsb &= 0x3FFFFFFFFFFFFFFFL; 
266        lsb |= 0x8000000000000000L; // set top two bits to variant 2
267    
268        msb &= 0xFFFFFFFFFFFF0FFFL; 
269        msb |= 0x3000; // Version 3; 
270    
271        return new UUID(msb, lsb);
272      }
273    
274      /**
275       * Returns the 48-bit node value in a long. 
276       * This field only exists in a time-based (version 1) UUID.
277       *
278       * @throws UnsupportedOperationException if the UUID type is not 1.
279       * @returns a long with the node value in the lower 48 bits.
280       */
281      public long node() 
282      {
283        if( version() != 1 )
284          throw new UnsupportedOperationException("Not a type 1 UUID");
285        return (leastSigBits & 0xFFFFFFFFFFFFL);
286      }
287    
288      /**
289       * Returns the 60-bit timestamp value of the UUID in a long. 
290       * This field only exists in a time-based (version 1) UUID.
291       *
292       * @throws UnsupportedOperationException if the UUID type is not 1.
293       * @returns a long with the timestamp value.
294       */
295      public long timestamp()
296      {
297        if( version() != 1 )
298          throw new UnsupportedOperationException("Not a type 1 UUID");
299        long time = (( mostSigBits & 0xFFFFFFFF00000000L) >> 32);
300        time |= (( mostSigBits & 0xFFFF0000L ) << 16);
301        long time_hi = ( mostSigBits & 0xFFFL );
302        time |= (time_hi << 48);
303        return time;
304      }
305    
306      /**
307       * Generate a Leach-Salz (Variant 2) randomly generated (version 4)
308       * UUID.
309       *
310       */
311      public static UUID randomUUID()
312      {  
313        long lsb = r.nextLong(); 
314        long msb = r.nextLong();
315    
316        lsb &= 0x3FFFFFFFFFFFFFFFL; 
317        lsb |= 0x8000000000000000L; // set top two bits to variant 2
318    
319        msb &= 0xFFFFFFFFFFFF0FFFL; 
320        msb |= 0x4000; // Version 4; 
321    
322        return new UUID( msb, lsb );
323      }
324    
325      /**
326       * Returns a hex String from l, padded to n spaces.
327       */
328      private String padHex( long l, int n )
329      {
330        String s = Long.toHexString( l );
331        while( s.length() < n )
332          s = "0" + s;
333        return s;
334      }
335    
336      /**
337       * Returns the variant of the UUID
338       *
339       * This may be:
340       * 0 = Reserved for NCS backwards-compatibility
341       * 2 = Leach-Salz (supports the other methods in this class)
342       * 6 = Reserved for Microsoft backwards-compatibility
343       * 7 = (reserved for future use)
344       */
345      public int variant()
346      {
347        // Get the top 3 bits (not all may be part of the variant)
348        int v = (int)((leastSigBits & 0xE000000000000000L) >> 61);
349        if( (v & 0x04) == 0 ) // msb of the variant is 0
350          return 0;
351        if( (v & 0x02) == 0 ) // variant is 0 1 (Leach-Salz)
352          return 2;
353        return v; // 6 or 7 
354      }
355    
356      /**
357       * Returns the version # of the UUID.
358       *
359       * Valid version numbers for a variant 2 UUID are:
360       * 1 = Time based UUID
361       * 2 = DCE security UUID
362       * 3 = Name-based UUID using MD5 hashing
363       * 4 = Randomly generated UUID
364       * 5 = Name-based UUID using SHA-1 hashing
365       *
366       * @return the version number
367       */
368      public int version()
369      {
370        return (int)((mostSigBits & 0xF000L) >> 12);
371      }
372    }