KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > webdav > impl > UUID


1 package com.ibm.webdav.impl;
2
3 /*
4  * (C) Copyright IBM Corp. 2000 All rights reserved.
5  *
6  * The program is provided "AS IS" without any warranty express or
7  * implied, including the warranty of non-infringement and the implied
8  * warranties of merchantibility and fitness for a particular purpose.
9  * IBM will not be liable for any damages suffered by you as a result
10  * of using the Program. In no event will IBM be liable for any
11  * special, indirect or consequential damages or lost profits even if
12  * IBM has been advised of the possibility of their occurrence. IBM
13  * will not be liable for any third party claims against you.
14  *
15  * Portions Copyright (C) Simulacra Media Ltd, 2004.
16  */

17
18 import java.net.InetAddress JavaDoc;
19 import java.util.Date JavaDoc;
20 import java.util.Random JavaDoc;
21 import java.io.*;
22 import java.security.MessageDigest JavaDoc;
23
24 /** A Universally Unique Identifier (UUID) is a 128 bit number generated
25  * according to an algorithm that is garanteed to be unique in time and
26  * space from all other UUIDs. It consists of an IEEE 802 Internet Address
27  * and various time stamps to ensure uniqueness. For a complete specification,
28  * see ftp://ietf.org/internet-drafts/draft-leach-uuids-guids-01.txt [leach].
29  * @author Jim Amsden <jamsden@us.ibm.com>
30  */

31 public class UUID implements Serializable {
32     private static byte[] internetAddress = null;
33     private static String JavaDoc uuidFile = null;
34     private long time;
35     private short clockSequence;
36     private byte version = 1;
37     private byte[] node = new byte[6];
38     private static final int UUIDsPerTick = 128;
39     private static long lastTime = new Date JavaDoc().getTime();
40     private static int uuidsThisTick = UUIDsPerTick;
41     private static UUID previousUUID = null; // initialized from saved state
42
private static long nextSave = new Date JavaDoc().getTime();
43     private static Random JavaDoc randomGenerator = new Random JavaDoc(new Date JavaDoc().getTime());
44     private static char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
45
46     //---------------------------------------------------------------------
47

48     static {
49         try {
50             internetAddress = InetAddress.getLocalHost().getAddress();
51         } catch (Exception JavaDoc exc) {
52             System.err.println("Can't get host address: " + exc);
53             exc.printStackTrace();
54         }
55         try {
56         uuidFile = System.getProperty("UUID_HOME");
57         if (uuidFile == null) {
58             uuidFile = System.getProperty("java.home");
59         }
60         if (!uuidFile.endsWith(File.separator)) {
61             uuidFile = uuidFile + File.separator;
62         }
63         uuidFile = uuidFile + "UUID";
64         previousUUID = getUUIDState();
65         } catch (Exception JavaDoc exc) {
66             exc.printStackTrace();
67         }
68     }
69 /** Generate a UUID for this host using version 1 of [leach].
70 */

71 public UUID() {
72     synchronized (this) {
73         time = getCurrentTime();
74         //node = getIEEEAddress();
75
node = previousUUID.getNode();
76         if (previousUUID == null || nodeChanged(previousUUID)) {
77             // if there is no saved state, or the node address changed,
78
// generate a random clock sequence
79
clockSequence = (short) random();
80         } else if (time < previousUUID.getTime()) {
81             // if the clock was turned back, increment the clock sequence
82
clockSequence++;
83         }
84         previousUUID = this; // for next time
85

86         // save for the next UUID
87
setUUIDState(this);
88     }
89 }
90 /** Generate a UUID for this host using version 1 of [leach].
91 * @param node the node to use in the UUID
92 */

93 public UUID(byte[] node) {
94     synchronized (this) {
95         time = getCurrentTime();
96         this.node = node;
97
98         // save for the next UUID
99
setUUIDState(this);
100     }
101 }
102 /** Generate a UUID from a name (NOT IMPLEMENTED)
103 */

104 public UUID(UUID context, String JavaDoc name) {
105 }
106 /** Lexically compare this UUID with withUUID. Note: lexical ordering
107 * is not temporal ordering.
108 *
109 * @param withUUID the UUID to compare with
110 * @return
111 * <ul>
112 * <li>-1 if this UUID is less than withUUID
113 * <li>0 if this UUID is equal to withUUID
114 * <li>1 if this UUID is greater than withUUID
115 * </ul>
116 */

117 public int compare(UUID withUUID) {
118     if (time < withUUID.getTime()) {
119         return -1;
120     } else if (time > withUUID.getTime()) {
121         return 1;
122     }
123     if (version < withUUID.getVersion()) {
124         return -1;
125     } else if (version > withUUID.getVersion()) {
126         return 1;
127     }
128     if (clockSequence < withUUID.getClockSequence()) {
129         return -1;
130     } else if (clockSequence > withUUID.getClockSequence()) {
131         return 1;
132     }
133     byte[] withNode = withUUID.getNode();
134     for (int i = 0; i < 6; i++) {
135         if (node[i] < withNode[i]) {
136             return -1;
137         } else if (node[i] > withNode[i]) {
138             return 1;
139         }
140     }
141     return 0;
142 }
143 /** Get a 48 bit cryptographic quality random number to use as the node field
144 * of a UUID as specified in section 6.4.1 of version 10 of the WebDAV spec.
145 * This is an alternative to the IEEE 802 host address which is not available
146 * from Java. The number will not conflict with any IEEE 802 host address because
147 * the most significant bit of the first octet is set to 1.
148 * @return a 48 bit number specifying an id for this node
149 */

150 private static byte[] computeNodeAddress() {
151     byte[] address = new byte[6];
152     // create a random number by concatenating:
153
// the hash code for the current thread
154
// the current time in milli-seconds
155
// the internet address for this node
156
int thread = Thread.currentThread().hashCode();
157     long time = System.currentTimeMillis();
158     ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
159     DataOutputStream out = new DataOutputStream(byteOut);
160     try {
161         if (internetAddress != null) {
162             out.write(internetAddress);
163         }
164         out.write(thread);
165         out.writeLong(time);
166         out.close();
167     } catch (IOException exc) {
168     }
169     byte[] rand = byteOut.toByteArray();
170     MessageDigest JavaDoc md5 = null;
171     try {
172         md5 = MessageDigest.getInstance("MD5");
173     } catch (Exception JavaDoc exc) {
174     }
175     md5.update(rand);
176     byte[] temp = md5.digest();
177     // pick the middle 6 bytes of the MD5 digest
178
for (int i = 0; i < 6; i++) {
179         address[i] = temp[i+5];
180     }
181     // set the MSB of the first octet to 1 to distinguish from IEEE node addresses
182
address[0] = (byte)(address[0] | (byte)0x80);
183     return address;
184 }
185 /** Get the clock sequence number.
186 * @return the clock sequence number
187 */

188 public int getClockSequence() {
189     return clockSequence;
190 }
191 /** Get the current time compensating for the fact that the real
192 * clock resolution may be less than 100ns.
193 *
194 * @return the current date and time
195 */

196 private static long getCurrentTime() {
197     long now = 0;
198     boolean waitForTick = true;
199     while (waitForTick) {
200         now = new Date JavaDoc().getTime();
201         if (lastTime < now) {
202             // got a new tick, make sure uuidsPerTick doesn't cause an overrun
203
uuidsThisTick = 0;
204             waitForTick = false;
205         } else if (uuidsThisTick < UUIDsPerTick) {
206             //
207
uuidsThisTick++;
208             waitForTick = false;
209         }
210     }
211     // add the uuidsThisTick to the time to increase the clock resolution
212
now += uuidsThisTick;
213     lastTime = now;
214     return now;
215 }
216 /** Get the 48 bit IEEE 802 host address. NOT IMPLEMENTED
217 * @return a 48 bit number specifying a unique location
218 */

219 private static byte[] getIEEEAddress() {
220     byte[] address = new byte[6];
221     // TODO: get the IEEE 802 host address
222
return address;
223 }
224 /** Get the spatially unique portion of the UUID. This is either
225 * the 48 bit IEEE 802 host address, or if on is not available, a random
226 * number that will not conflict with any IEEE 802 host address.
227 * @return node portion of the UUID
228 */

229 public byte[] getNode() {
230     return node;
231 }
232 /** Get the temporal unique portion of the UUID.
233 * @return the time portion of the UUID
234 */

235 public long getTime() {
236     return time;
237 }
238 /** Get the 128 bit UUID.
239 */

240 public byte[] getUUID() {
241     byte[] uuid = new byte[16];
242     long t = time;
243     for (int i = 0; i < 8; i++) {
244         uuid[i] = (byte) ((t >> 8 * i) & 0xFF); // time
245
}
246     uuid[7] |= (byte) (version << 12); // time hi and version
247
uuid[8] = (byte) (clockSequence & 0xFF);
248     uuid[9] = (byte) ((clockSequence & 0x3F00) >> 8);
249     uuid[9] |= 0x80; // clock sequence hi and reserved
250
for (int i = 0; i < 6; i++) {
251         uuid[10 + i] = node[i]; // node
252
}
253     return uuid;
254 }
255 /** Get the UUID generator state. This consists of the last (or
256 * nearly last) UUID generated. This state is used in the construction
257 * of the next UUID. May return null if the UUID state is not
258 * available.
259 * @return the last UUID generator state
260 */

261 private static UUID getUUIDState() {
262     UUID uuid = null;
263     try {
264         FileInputStream in = new FileInputStream(uuidFile);
265         ObjectInputStream s = new ObjectInputStream(in);
266         uuid = (UUID) s.readObject();
267     } catch (Exception JavaDoc exc) {
268         uuid = new UUID(computeNodeAddress());
269         System.err.println("Can't get saved UUID state: " + exc);
270     }
271     return uuid;
272 }
273 /** Get the UUID version number.
274 */

275 public int getVersion() {
276     return version;
277 }
278 /** Compare two UUIDs
279 * @return true if the UUIDs are equal
280 */

281 public boolean isEqual(UUID toUUID) {
282     return compare(toUUID) == 0;
283 }
284 /** Determine if the node changed with respect to previousUUID.
285 * @param previousUUID the UUID to compare with
286 * @return true if the the previousUUID has a different node than this UUID
287 */

288 private boolean nodeChanged(UUID previousUUID) {
289     byte[] previousNode = previousUUID.getNode();
290     boolean nodeChanged = false;
291     int i = 0;
292     while (!nodeChanged && i < 6) {
293         nodeChanged = node[i] != previousNode[i];
294         i++;
295     }
296     return nodeChanged;
297 }
298 /** Generate a crypto-quality random number. This implementation
299 * doesn't do that.
300 * @return a random number
301 */

302 private static int random() {
303     return randomGenerator.nextInt();
304 }
305 /** Set the persistent UUID state.
306 * @param aUUID the UUID to save
307 */

308 private static void setUUIDState(UUID aUUID) {
309     if (aUUID.getTime() > nextSave) {
310         try {
311             FileOutputStream f = new FileOutputStream(uuidFile);
312             ObjectOutputStream s = new ObjectOutputStream(f);
313             s.writeObject(aUUID);
314             s.close();
315             nextSave = aUUID.getTime() + 10 * 10 * 1000 * 1000;
316         } catch (Exception JavaDoc exc) {
317             System.err.println("Can't save UUID state: " + exc);
318         }
319     }
320 }
321 /** Provide a String representation of a UUID as specified in section
322 * 3.5 of [leach].
323 */

324 public String JavaDoc toString() {
325     byte[] uuid = getUUID();
326     StringWriter s = new StringWriter();
327     for (int i = 0; i < 16; i++) {
328         s.write(hexDigits[(uuid[i] & 0xF0) >> 4]);
329         s.write(hexDigits[uuid[i] & 0x0F]);
330         if (i == 3 || i == 5 || i == 7 || i == 9) {
331             s.write('-');
332         }
333     }
334     return s.toString();
335 }
336 }
337
Popular Tags