OSDN Git Service

2006-08-14 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / util / UUID.java
1 /* UUID.java -- Class that represents a UUID object.
2    Copyright (C) 2006  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package java.util;
40
41 import java.io.Serializable;
42 import java.security.MessageDigest;
43 import java.security.NoSuchAlgorithmException;
44
45 /**
46  * This class represents a 128-bit UUID value.
47  * 
48  * There are several types of UUID, and while this class can be used to store
49  * them, only the Leach-Salz (variant 2) UUID specified in RFC-4122 will 
50  * give meaningful results from the method calls.
51  * See: http://tools.ietf.org/html/4122 for the details
52  *
53  * The format of a Leach-Salz (variant 2) time-based (version 1) UUID 
54  * is as follows:
55  * time_low - upper 32 bits of the most significant 64 bits,
56  *            this is the least-significant part of the timestamp.
57  *
58  * time_mid - bits 16-31 of the most significant 64 bits,
59  *            this is the middle portion of the timestamp. 
60  *
61  * version  - bits 8-15 of the most significant 64 bits. 
62  *
63  * time_hi  - bits 0-7 of the most significant 64 bits,
64  *            the most significant portion of the timestamp.
65  *
66  * clock_and_reserved  - bits 48-63 of the least significant 64 bits.
67  *                       a variable number of bits hold the variant 
68  *                       (see the spec)
69  * 
70  * node identifier     - bits 0-47 of the least signficant 64 bits.
71  *
72  * These fields are valid only for version 1, in the remaining versions,
73  * only the version and variant fields are set, all others are used for data.
74  *
75  * @since 1.5
76  * @author Sven de Marothy
77  */
78 public final class UUID 
79   extends Object 
80   implements Serializable, Comparable // genericizeme!
81 {
82   private static final long serialVersionUID = -4856846361193249489L;
83
84   /**
85    * Serialized field - most significant 64 bits.
86    */
87   private long mostSigBits;
88
89   /**
90    * Serialized field - least significant 64 bits.
91    */
92   private long leastSigBits;
93
94   /**
95    * Random-number generator.
96    */
97   private static transient Random r = new Random();
98
99   /**
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(Object val)
131   {
132     return compareTo((UUID)val);
133   }
134
135   /**
136    * Compare this UUID to another.
137    * The comparison is performed as between two 128-bit integers.
138    *
139    * @return -1 if this < val, 0 if they are equal, 1 if this > val.
140    */
141   public int compareTo(UUID o)
142   {
143     if( mostSigBits < o.mostSigBits )
144       return -1;
145     if( mostSigBits > o.mostSigBits )
146       return 1;
147     if( leastSigBits < o.leastSigBits )
148       return -1;
149     if( leastSigBits > o.mostSigBits )
150       return 1;
151     return 0;
152   }
153
154   /**
155    * Compare a (UUID) object to this one
156    */
157   public boolean equals(Object obj)
158   {
159     if( !(obj instanceof UUID ) )
160       return false;
161     return ( ((UUID)obj).mostSigBits == mostSigBits && 
162              ((UUID)obj).leastSigBits == leastSigBits );
163   }
164
165   /**
166    * Creates a UUID object from a Sting representation.
167    *
168    * For the format of the string,
169    * @see #toString()
170    *
171    * @return a new UUID object.
172    */
173   public static UUID fromString(String name)
174   {
175     StringTokenizer st = new StringTokenizer( name.trim(), "-" );
176     if( st.countTokens() < 5 )
177       throw new IllegalArgumentException( "Incorrect UUID string"+
178                                           " representation:"+name );
179
180     long msb = (Long.parseLong(st.nextToken(), 16) << 32); // time low
181     msb |= (Long.parseLong(st.nextToken(), 16) << 16); // time mid
182     msb |= Long.parseLong(st.nextToken(), 16); // time high
183
184     long lsb = (Long.parseLong(st.nextToken(), 16) << 48); // clock
185     lsb |= Long.parseLong(st.nextToken(), 16); // node
186
187     return new UUID(msb, lsb);
188   }
189
190   /**
191    * Returns a String representation of the UUID.
192    *
193    * The format of the standard string representation (given in RFC4122) is:
194    *
195    * time-low "-" time-mid "-"
196    * time-high-and-version "-"
197    * clock-seq-and-reserved
198    * clock-seq-low "-" node
199    *
200    * Where each field is represented as a hex string.
201    *
202    * @return the String representation.
203    */
204   public String toString()
205   {
206     return // time-low first
207       padHex( (( mostSigBits & 0xFFFFFFFF00000000L) >> 32) & 0xFFFFFFFFL, 8)
208       + "-" + // then time-mid
209       padHex( (( mostSigBits & 0xFFFF0000L ) >> 16), 4 ) 
210       + "-" + // time-high
211       padHex( ( mostSigBits & 0x0000000000000000FFFFL ), 4 ) 
212       + "-" + // clock (note - no reason to separate high and low here)
213       padHex( (((leastSigBits & 0xFFFF000000000000L) >> 48) & 0xFFFF), 4 ) 
214       + "-" + // finally the node value.
215       padHex(leastSigBits & 0xFFFFFFFFFFFFL, 12); 
216   }
217
218   /**
219    * Returns the least significant 64 bits of the UUID as a <code>long</code>.
220    */ 
221   public long getLeastSignificantBits()
222   {
223     return leastSigBits;
224   }
225
226   /**
227    * Returns the most significant 64 bits of the UUID as a <code>long</code>.
228    */ 
229   public long getMostSignificantBits()
230   {
231     return mostSigBits;
232   }
233
234   /**
235    * Returns a hash of this UUID.
236    */
237   public int hashCode()
238   {
239     int l1 = (int)(leastSigBits & 0xFFFFFFFFL);
240     int l2 = (int)((leastSigBits & 0xFFFFFFFF00000000L) >> 32);
241     int m1 = (int)(mostSigBits & 0xFFFFFFFFL);
242     int m2 = (int)((mostSigBits & 0xFFFFFFFF00000000L) >> 32);
243
244     return (l1 ^ l2) ^ (m1 ^ m2);
245   }
246
247   /**
248    * Creates a UUID version 3 object (name based with MD5 hashing)
249    * from a series of bytes representing a name.
250    */
251   public static UUID nameUUIDFromBytes(byte[] name)
252   {    
253     long msb, lsb;
254     byte[] hash;
255
256     try
257       {
258         MessageDigest md5 = MessageDigest.getInstance("MD5");
259         hash = md5.digest( name );
260       } 
261     catch (NoSuchAlgorithmException e) 
262       {
263         throw new UnsupportedOperationException("No MD5 algorithm available.");
264       }
265         
266     msb = ((hash[0] & 0xFFL) << 56) | ((hash[1] & 0xFFL) << 48) |
267       ((hash[2] & 0xFFL) << 40) | ((hash[3] & 0xFFL) << 32) |
268       ((hash[4] & 0xFFL) << 24) | ((hash[5] & 0xFFL) << 16) |
269       ((hash[6] & 0xFFL) << 8) | (hash[7] & 0xFFL);
270
271     lsb = ((hash[8] & 0xFFL) << 56) | ((hash[9] & 0xFFL) << 48) |
272       ((hash[10] & 0xFFL) << 40) | ((hash[11] & 0xFFL) << 32) |
273       ((hash[12] & 0xFFL) << 24) | ((hash[13] & 0xFFL) << 16) |
274       ((hash[14] & 0xFFL) << 8) | (hash[15] & 0xFFL);
275
276     lsb &= 0x3FFFFFFFFFFFFFFFL; 
277     lsb |= 0x8000000000000000L; // set top two bits to variant 2
278
279     msb &= 0xFFFFFFFFFFFF0FFFL; 
280     msb |= 0x3000; // Version 3; 
281
282     return new UUID(msb, lsb);
283   }
284
285   /**
286    * Returns the 48-bit node value in a long. 
287    * This field only exists in a time-based (version 1) UUID.
288    *
289    * @throws UnsupportedOperationException if the UUID type is not 1.
290    * @returns a long with the node value in the lower 48 bits.
291    */
292   public long node() 
293   {
294     if( version() != 1 )
295       throw new UnsupportedOperationException("Not a type 1 UUID");
296     return (leastSigBits & 0xFFFFFFFFFFFFL);
297   }
298
299   /**
300    * Returns the 60-bit timestamp value of the UUID in a long. 
301    * This field only exists in a time-based (version 1) UUID.
302    *
303    * @throws UnsupportedOperationException if the UUID type is not 1.
304    * @returns a long with the timestamp value.
305    */
306   public long timestamp()
307   {
308     if( version() != 1 )
309       throw new UnsupportedOperationException("Not a type 1 UUID");
310     long time = (( mostSigBits & 0xFFFFFFFF00000000L) >> 32);
311     time |= (( mostSigBits & 0xFFFF0000L ) << 16);
312     long time_hi = ( mostSigBits & 0xFFFL );
313     time |= (time_hi << 48);
314     return time;
315   }
316
317   /**
318    * Generate a Leach-Salz (Variant 2) randomly generated (version 4)
319    * UUID.
320    *
321    */
322   public static UUID randomUUID()
323   {  
324     long lsb = r.nextLong(); 
325     long msb = r.nextLong();
326
327     lsb &= 0x3FFFFFFFFFFFFFFFL; 
328     lsb |= 0x8000000000000000L; // set top two bits to variant 2
329
330     msb &= 0xFFFFFFFFFFFF0FFFL; 
331     msb |= 0x4000; // Version 4; 
332
333     return new UUID( msb, lsb );
334   }
335
336   /**
337    * Returns a hex String from l, padded to n spaces.
338    */
339   private String padHex( long l, int n )
340   {
341     String s = Long.toHexString( l );
342     while( s.length() < n )
343       s = "0" + s;
344     return s;
345   }
346
347   /**
348    * Returns the variant of the UUID
349    *
350    * This may be:
351    * 0 = Reserved for NCS backwards-compatibility
352    * 2 = Leach-Salz (supports the other methods in this class)
353    * 6 = Reserved for Microsoft backwards-compatibility
354    * 7 = (reserved for future use)
355    */
356   public int variant()
357   {
358     // Get the top 3 bits (not all may be part of the variant)
359     int v = (int)((leastSigBits & 0xE000000000000000L) >> 61);
360     if( (v & 0x04) == 0 ) // msb of the variant is 0
361       return 0;
362     if( (v & 0x02) == 0 ) // variant is 0 1 (Leach-Salz)
363       return 2;
364     return v; // 6 or 7 
365   }
366
367   /**
368    * Returns the version # of the UUID.
369    *
370    * Valid version numbers for a variant 2 UUID are:
371    * 1 = Time based UUID
372    * 2 = DCE security UUID
373    * 3 = Name-based UUID using MD5 hashing
374    * 4 = Randomly generated UUID
375    * 5 = Name-based UUID using SHA-1 hashing
376    *
377    * @return the version number
378    */
379   public int version()
380   {
381     return (int)((mostSigBits & 0xF000L) >> 12);
382   }
383 }