KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > utils > UniversalUniqueIdentifier


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.utils;
12
13 import java.io.*;
14 import java.math.BigInteger JavaDoc;
15 import java.net.InetAddress JavaDoc;
16 import java.net.UnknownHostException JavaDoc;
17 import java.security.SecureRandom JavaDoc;
18 import java.util.GregorianCalendar JavaDoc;
19 import java.util.Random JavaDoc;
20 import org.eclipse.core.runtime.Assert;
21
22 public class UniversalUniqueIdentifier implements java.io.Serializable JavaDoc {
23
24     /**
25      * All serializable objects should have a stable serialVersionUID
26      */

27     private static final long serialVersionUID = 1L;
28
29     /* INSTANCE FIELDS =============================================== */
30
31     private byte[] fBits = new byte[BYTES_SIZE];
32
33     /* NON-FINAL PRIVATE STATIC FIELDS =============================== */
34
35     private static BigInteger JavaDoc fgPreviousClockValue;
36     private static int fgClockAdjustment = 0;
37     private static int fgClockSequence = -1;
38     private static byte[] nodeAddress;
39
40     static {
41         nodeAddress = computeNodeAddress();
42     }
43
44     /* PRIVATE STATIC FINAL FIELDS =================================== */
45
46     private static Random JavaDoc fgRandomNumberGenerator = new Random JavaDoc();
47
48     /* PUBLIC STATIC FINAL FIELDS ==================================== */
49
50     public static final int BYTES_SIZE = 16;
51     public static final byte[] UNDEFINED_UUID_BYTES = new byte[16];
52     public static final int MAX_CLOCK_SEQUENCE = 0x4000;
53     public static final int MAX_CLOCK_ADJUSTMENT = 0x7FFF;
54     public static final int TIME_FIELD_START = 0;
55     public static final int TIME_FIELD_STOP = 6;
56     public static final int TIME_HIGH_AND_VERSION = 7;
57     public static final int CLOCK_SEQUENCE_HIGH_AND_RESERVED = 8;
58     public static final int CLOCK_SEQUENCE_LOW = 9;
59     public static final int NODE_ADDRESS_START = 10;
60     public static final int NODE_ADDRESS_BYTE_SIZE = 6;
61
62     public static final int BYTE_MASK = 0xFF;
63
64     public static final int HIGH_NIBBLE_MASK = 0xF0;
65
66     public static final int LOW_NIBBLE_MASK = 0x0F;
67
68     public static final int SHIFT_NIBBLE = 4;
69
70     public static final int ShiftByte = 8;
71
72     /**
73      UniversalUniqueIdentifier default constructor returns a
74      new instance that has been initialized to a unique value.
75      */

76     public UniversalUniqueIdentifier() {
77         this.setVersion(1);
78         this.setVariant(1);
79         this.setTimeValues();
80         this.setNode(getNodeAddress());
81     }
82
83     /**
84      Constructor that accepts the bytes to use for the instance.   The format
85      of the byte array is compatible with the <code>toBytes()</code> method.
86
87      <p>The constructor returns the undefined uuid if the byte array is invalid.
88
89      @see #toBytes()
90      @see #BYTES_SIZE
91      */

92     public UniversalUniqueIdentifier(byte[] byteValue) {
93         fBits = new byte[BYTES_SIZE];
94         if (byteValue.length >= BYTES_SIZE)
95             System.arraycopy(byteValue, 0, fBits, 0, BYTES_SIZE);
96     }
97
98     private void appendByteString(StringBuffer JavaDoc buffer, byte value) {
99         String JavaDoc hexString;
100
101         if (value < 0)
102             hexString = Integer.toHexString(256 + value);
103         else
104             hexString = Integer.toHexString(value);
105         if (hexString.length() == 1)
106             buffer.append("0"); //$NON-NLS-1$
107
buffer.append(hexString);
108     }
109
110     private static BigInteger JavaDoc clockValueNow() {
111         GregorianCalendar JavaDoc now = new GregorianCalendar JavaDoc();
112         BigInteger JavaDoc nowMillis = BigInteger.valueOf(now.getTime().getTime());
113         BigInteger JavaDoc baseMillis = BigInteger.valueOf(now.getGregorianChange().getTime());
114
115         return (nowMillis.subtract(baseMillis).multiply(BigInteger.valueOf(10000L)));
116     }
117
118     /**
119      Simply increases the visibility of <code>Object</code>'s clone.
120      Otherwise, no new behaviour.
121      */

122     public Object JavaDoc clone() {
123         try {
124             return super.clone();
125         } catch (CloneNotSupportedException JavaDoc e) {
126             Assert.isTrue(false, Messages.utils_clone);
127             return null;
128         }
129     }
130
131     public static int compareTime(byte[] fBits1, byte[] fBits2) {
132         for (int i = TIME_FIELD_STOP; i >= 0; i--)
133             if (fBits1[i] != fBits2[i])
134                 return (0xFF & fBits1[i]) - (0xFF & fBits2[i]);
135         return 0;
136     }
137
138     /**
139      * Answers the node address attempting to mask the IP
140      * address of this machine.
141      *
142      * @return byte[] the node address
143      */

144     private static byte[] computeNodeAddress() {
145
146         byte[] address = new byte[NODE_ADDRESS_BYTE_SIZE];
147
148         // Seed the secure randomizer with some oft-varying inputs
149
int thread = Thread.currentThread().hashCode();
150         long time = System.currentTimeMillis();
151         int objectId = System.identityHashCode(new String JavaDoc());
152         ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
153         DataOutputStream out = new DataOutputStream(byteOut);
154         byte[] ipAddress = getIPAddress();
155
156         try {
157             if (ipAddress != null)
158                 out.write(ipAddress);
159             out.write(thread);
160             out.writeLong(time);
161             out.write(objectId);
162             out.close();
163         } catch (IOException exc) {
164             //ignore the failure, we're just trying to come up with a random seed
165
}
166         byte[] rand = byteOut.toByteArray();
167
168         SecureRandom JavaDoc randomizer = new SecureRandom JavaDoc(rand);
169         randomizer.nextBytes(address);
170
171         // set the MSB of the first octet to 1 to distinguish from IEEE node addresses
172
address[0] = (byte) (address[0] | (byte) 0x80);
173
174         return address;
175     }
176
177     public boolean equals(Object JavaDoc obj) {
178         if (this == obj)
179             return true;
180         if (!(obj instanceof UniversalUniqueIdentifier))
181             return false;
182
183         byte[] other = ((UniversalUniqueIdentifier) obj).fBits;
184         if (fBits == other)
185             return true;
186         if (fBits.length != other.length)
187             return false;
188         for (int i = 0; i < fBits.length; i++) {
189             if (fBits[i] != other[i])
190                 return false;
191         }
192         return true;
193     }
194
195     /**
196      Answers the IP address of the local machine using the
197      Java API class <code>InetAddress</code>.
198
199      @return byte[] the network address in network order
200      @see java.net.InetAddress#getLocalHost()
201      @see java.net.InetAddress#getAddress()
202      */

203     protected static byte[] getIPAddress() {
204         try {
205             return InetAddress.getLocalHost().getAddress();
206         } catch (UnknownHostException JavaDoc e) {
207             //valid for this to be thrown be a machine with no IP connection
208
//It is VERY important NOT to throw this exception
209
return null;
210         }
211     }
212
213     private static byte[] getNodeAddress() {
214         return nodeAddress;
215     }
216
217     public int hashCode() {
218         return fBits[0] + fBits[3] + fBits[7] + fBits[11] + fBits[15];
219     }
220
221     private static int nextClockSequence() {
222
223         if (fgClockSequence == -1)
224             fgClockSequence = (int) (fgRandomNumberGenerator.nextDouble() * MAX_CLOCK_SEQUENCE);
225
226         fgClockSequence = (fgClockSequence + 1) % MAX_CLOCK_SEQUENCE;
227
228         return fgClockSequence;
229     }
230
231     private static BigInteger JavaDoc nextTimestamp() {
232
233         BigInteger JavaDoc timestamp = clockValueNow();
234         int timestampComparison;
235
236         timestampComparison = timestamp.compareTo(fgPreviousClockValue);
237
238         if (timestampComparison == 0) {
239             if (fgClockAdjustment == MAX_CLOCK_ADJUSTMENT) {
240                 while (timestamp.compareTo(fgPreviousClockValue) == 0)
241                     timestamp = clockValueNow();
242                 timestamp = nextTimestamp();
243             } else
244                 fgClockAdjustment++;
245         } else {
246             fgClockAdjustment = 0;
247
248             if (timestampComparison < 0)
249                 nextClockSequence();
250         }
251
252         return timestamp;
253     }
254
255     private void setClockSequence(int clockSeq) {
256         int clockSeqHigh = (clockSeq >>> ShiftByte) & LOW_NIBBLE_MASK;
257         int reserved = fBits[CLOCK_SEQUENCE_HIGH_AND_RESERVED] & HIGH_NIBBLE_MASK;
258
259         fBits[CLOCK_SEQUENCE_HIGH_AND_RESERVED] = (byte) (reserved | clockSeqHigh);
260         fBits[CLOCK_SEQUENCE_LOW] = (byte) (clockSeq & BYTE_MASK);
261     }
262
263     protected void setNode(byte[] bytes) {
264
265         for (int index = 0; index < NODE_ADDRESS_BYTE_SIZE; index++)
266             fBits[index + NODE_ADDRESS_START] = bytes[index];
267     }
268
269     private void setTimestamp(BigInteger JavaDoc timestamp) {
270         BigInteger JavaDoc value = timestamp;
271         BigInteger JavaDoc bigByte = BigInteger.valueOf(256L);
272         BigInteger JavaDoc[] results;
273         int version;
274         int timeHigh;
275
276         for (int index = TIME_FIELD_START; index < TIME_FIELD_STOP; index++) {
277             results = value.divideAndRemainder(bigByte);
278             value = results[0];
279             fBits[index] = (byte) results[1].intValue();
280         }
281         version = fBits[TIME_HIGH_AND_VERSION] & HIGH_NIBBLE_MASK;
282         timeHigh = value.intValue() & LOW_NIBBLE_MASK;
283         fBits[TIME_HIGH_AND_VERSION] = (byte) (timeHigh | version);
284     }
285
286     protected synchronized void setTimeValues() {
287         this.setTimestamp(timestamp());
288         this.setClockSequence(fgClockSequence);
289     }
290
291     protected int setVariant(int variantIdentifier) {
292         int clockSeqHigh = fBits[CLOCK_SEQUENCE_HIGH_AND_RESERVED] & LOW_NIBBLE_MASK;
293         int variant = variantIdentifier & LOW_NIBBLE_MASK;
294
295         fBits[CLOCK_SEQUENCE_HIGH_AND_RESERVED] = (byte) ((variant << SHIFT_NIBBLE) | clockSeqHigh);
296         return (variant);
297     }
298
299     protected void setVersion(int versionIdentifier) {
300         int timeHigh = fBits[TIME_HIGH_AND_VERSION] & LOW_NIBBLE_MASK;
301         int version = versionIdentifier & LOW_NIBBLE_MASK;
302
303         fBits[TIME_HIGH_AND_VERSION] = (byte) (timeHigh | (version << SHIFT_NIBBLE));
304     }
305
306     private static BigInteger JavaDoc timestamp() {
307         BigInteger JavaDoc timestamp;
308
309         if (fgPreviousClockValue == null) {
310             fgClockAdjustment = 0;
311             nextClockSequence();
312             timestamp = clockValueNow();
313         } else
314             timestamp = nextTimestamp();
315
316         fgPreviousClockValue = timestamp;
317         return fgClockAdjustment == 0 ? timestamp : timestamp.add(BigInteger.valueOf(fgClockAdjustment));
318     }
319
320     /**
321      This representation is compatible with the (byte[]) constructor.
322
323      @see #UniversalUniqueIdentifier(byte[])
324      */

325     public byte[] toBytes() {
326         byte[] result = new byte[fBits.length];
327
328         System.arraycopy(fBits, 0, result, 0, fBits.length);
329         return result;
330     }
331
332     public String JavaDoc toString() {
333         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
334         for (int i = 0; i < fBits.length; i++)
335             appendByteString(buffer, fBits[i]);
336         return buffer.toString();
337     }
338
339     public String JavaDoc toStringAsBytes() {
340         String JavaDoc result = "{"; //$NON-NLS-1$
341

342         for (int i = 0; i < fBits.length; i++) {
343             result += fBits[i];
344             if (i < fBits.length + 1)
345                 result += ","; //$NON-NLS-1$
346
}
347         return result + "}"; //$NON-NLS-1$
348
}
349 }
350
Popular Tags