001/* UUID.java -- Class that represents a UUID object.
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.util;
040
041import java.io.Serializable;
042import java.security.MessageDigest;
043import 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 */
078public 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}