001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.util;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.Serializable;
023: import java.security.MessageDigest;
024: import java.security.NoSuchAlgorithmException;
025: import java.security.SecureRandom;
026:
027: import org.apache.harmony.luni.util.Msg;
028:
029: /**
030: * <p>
031: * UUID is an immutable representation of a 128-bit universally unique
032: * identifier (UUID).
033: * </p>
034: * <p>
035: * There are multiple, variant layouts of UUIDs, but this class is based upon
036: * variant 2 of <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>, the
037: * Leach-Salz variant. This class can be used to model alternate variants, but
038: * most of the methods will be unsupported in those cases; see each method for
039: * details.
040: * </p>
041: *
042: * @since 1.5
043: * @author Nathan Beyer (Harmony)
044: */
045: public final class UUID implements Serializable, Comparable<UUID> {
046:
047: private static final long serialVersionUID = -4856846361193249489L;
048:
049: private static SecureRandom rng;
050:
051: private long mostSigBits;
052: private long leastSigBits;
053:
054: private transient int variant;
055: private transient int version;
056: private transient long timestamp;
057: private transient int clockSequence;
058: private transient long node;
059: private transient int hash;
060:
061: /**
062: * <p>
063: * Constructs an instance with the specified bits.
064: * </p>
065: *
066: * @param mostSigBits
067: * The 64 most significant bits of the UUID.
068: * @param leastSigBits
069: * The 64 least significant bits of the UUID.
070: */
071: public UUID(long mostSigBits, long leastSigBits) {
072: super ();
073: this .mostSigBits = mostSigBits;
074: this .leastSigBits = leastSigBits;
075: init();
076: }
077:
078: /**
079: * <p>
080: * Sets up the transient fields of this instance based on the current values
081: * of the <code>mostSigBits</code> and <code>leastSigBits</code> fields.
082: * </p>
083: */
084: private void init() {
085: // setup hash field
086: int msbHash = (int) (mostSigBits ^ (mostSigBits >>> 32));
087: int lsbHash = (int) (leastSigBits ^ (leastSigBits >>> 32));
088: hash = msbHash ^ lsbHash;
089:
090: // setup variant field
091: if ((leastSigBits & 0x8000000000000000L) == 0) {
092: // MSB0 not set, NCS backwards compatibility variant
093: variant = 0;
094: } else if ((leastSigBits & 0x4000000000000000L) != 0) {
095: // MSB1 set, either MS reserved or future reserved
096: variant = (int) ((leastSigBits & 0xE000000000000000L) >>> 61);
097: } else {
098: // MSB1 not set, RFC 4122 variant
099: variant = 2;
100: }
101:
102: // setup version field
103: version = (int) ((mostSigBits & 0x000000000000F000) >>> 12);
104:
105: if (variant != 2 && version != 1) {
106: return;
107: }
108:
109: // setup timestamp field
110: long timeLow = (mostSigBits & 0xFFFFFFFF00000000L) >>> 32;
111: long timeMid = (mostSigBits & 0x00000000FFFF0000L) << 16;
112: long timeHigh = (mostSigBits & 0x0000000000000FFFL) << 48;
113: timestamp = timeLow | timeMid | timeHigh;
114:
115: // setup clock sequence field
116: clockSequence = (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
117:
118: // setup node field
119: node = (leastSigBits & 0x0000FFFFFFFFFFFFL);
120: }
121:
122: /**
123: * <p>
124: * Generates a variant 2, version 4 (randomly generated number) UUID as per
125: * <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
126: * </p>
127: *
128: * @return A UUID instance.
129: */
130: public static UUID randomUUID() {
131: byte[] data;
132: // lock on the class to protect lazy init
133: synchronized (UUID.class) {
134: if (rng == null) {
135: rng = new SecureRandom();
136: }
137: }
138: rng.nextBytes(data = new byte[16]);
139: long msb = (data[0] & 0xFFL) << 56;
140: msb |= (data[1] & 0xFFL) << 48;
141: msb |= (data[2] & 0xFFL) << 40;
142: msb |= (data[3] & 0xFFL) << 32;
143: msb |= (data[4] & 0xFFL) << 24;
144: msb |= (data[5] & 0xFFL) << 16;
145: msb |= (data[6] & 0x0FL) << 8;
146: msb |= (0x4L << 12); // set the version to 4
147: msb |= (data[7] & 0xFFL);
148:
149: long lsb = (data[8] & 0x3FL) << 56;
150: lsb |= (0x2L << 62); // set the variant to bits 01
151: lsb |= (data[9] & 0xFFL) << 48;
152: lsb |= (data[10] & 0xFFL) << 40;
153: lsb |= (data[11] & 0xFFL) << 32;
154: lsb |= (data[12] & 0xFFL) << 24;
155: lsb |= (data[13] & 0xFFL) << 16;
156: lsb |= (data[14] & 0xFFL) << 8;
157: lsb |= (data[15] & 0xFFL);
158: return new UUID(msb, lsb);
159: }
160:
161: /**
162: * <p>
163: * Generates a variant 2, version 3 (name-based, MD5-hashed) UUID as per <a
164: * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
165: * </p>
166: *
167: * @return A UUID instance.
168: */
169: public static UUID nameUUIDFromBytes(byte[] name) {
170: if (name == null) {
171: throw new NullPointerException();
172: }
173:
174: byte[] hash;
175: try {
176: MessageDigest md = MessageDigest.getInstance("MD5"); //$NON-NLS-1$
177: hash = md.digest(name);
178: } catch (NoSuchAlgorithmException e) {
179: throw new AssertionError(e);
180: }
181:
182: long msb = (hash[0] & 0xFFL) << 56;
183: msb |= (hash[1] & 0xFFL) << 48;
184: msb |= (hash[2] & 0xFFL) << 40;
185: msb |= (hash[3] & 0xFFL) << 32;
186: msb |= (hash[4] & 0xFFL) << 24;
187: msb |= (hash[5] & 0xFFL) << 16;
188: msb |= (hash[6] & 0x0FL) << 8;
189: msb |= (0x3L << 12); // set the version to 3
190: msb |= (hash[7] & 0xFFL);
191:
192: long lsb = (hash[8] & 0x3FL) << 56;
193: lsb |= (0x2L << 62); // set the variant to bits 01
194: lsb |= (hash[9] & 0xFFL) << 48;
195: lsb |= (hash[10] & 0xFFL) << 40;
196: lsb |= (hash[11] & 0xFFL) << 32;
197: lsb |= (hash[12] & 0xFFL) << 24;
198: lsb |= (hash[13] & 0xFFL) << 16;
199: lsb |= (hash[14] & 0xFFL) << 8;
200: lsb |= (hash[15] & 0xFFL);
201: return new UUID(msb, lsb);
202: }
203:
204: /**
205: * <p>
206: * Parses a UUID string with the format defined by {@link #toString()}.
207: * </p>
208: *
209: * @param uuid
210: * The UUID string to parse.
211: * @return A UUID instance.
212: * @throws NullPointerException
213: * if <code>uuid</code> is <code>null</code>.
214: * @throws IllegalArgumentException
215: * if <code>uuid</code> is not formatted correctly.
216: */
217: public static UUID fromString(String uuid) {
218: if (uuid == null) {
219: throw new NullPointerException();
220: }
221:
222: int[] position = new int[5];
223: int lastPosition = 1;
224: int startPosition = 0;
225:
226: int i = 0;
227: for (; i < position.length && lastPosition > 0; i++) {
228: position[i] = uuid.indexOf("-", startPosition); //$NON-NLS-1$
229: lastPosition = position[i];
230: startPosition = position[i] + 1;
231: }
232:
233: // should have and only can have four "-" in UUID
234: if (i != position.length || lastPosition != -1) {
235: throw new IllegalArgumentException(
236: Msg.getString("KA014") + uuid); //$NON-NLS-1$
237: }
238:
239: long m1 = Long.parseLong(uuid.substring(0, position[0]), 16);
240: long m2 = Long.parseLong(uuid.substring(position[0] + 1,
241: position[1]), 16);
242: long m3 = Long.parseLong(uuid.substring(position[1] + 1,
243: position[2]), 16);
244:
245: long lsb1 = Long.parseLong(uuid.substring(position[2] + 1,
246: position[3]), 16);
247: long lsb2 = Long.parseLong(uuid.substring(position[3] + 1), 16);
248:
249: long msb = (m1 << 32) | (m2 << 16) | m3;
250: long lsb = (lsb1 << 48) | lsb2;
251:
252: return new UUID(msb, lsb);
253: }
254:
255: /**
256: * <p>
257: * The 64 least significant bits of the UUID.
258: * </p>
259: *
260: * @return A long value.
261: */
262: public long getLeastSignificantBits() {
263: return leastSigBits;
264: }
265:
266: /**
267: * <p>
268: * The 64 most significant bits of the UUID.
269: * </p>
270: *
271: * @return A long value.
272: */
273: public long getMostSignificantBits() {
274: return mostSigBits;
275: }
276:
277: /**
278: * <p>
279: * The version of the variant 2 UUID as per <a
280: * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. If the variant
281: * is not 2, then the version will be 0.
282: * </p>
283: * <ul>
284: * <li>1 - Time-based UUID</li>
285: * <li>2 - DCE Security UUID</li>
286: * <li>3 - Name-based with MD5 hashing UUID ({@link #nameUUIDFromBytes(byte[])})</li>
287: * <li>4 - Randomly generated UUID ({@link #randomUUID()})</li>
288: * <li>5 - Name-based with SHA-1 hashing UUID</li>
289: * </ul>
290: *
291: * @return An int value.
292: */
293: public int version() {
294: return version;
295: }
296:
297: /**
298: * <p>
299: * The variant of the UUID as per <a
300: * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
301: * </p>
302: * <ul>
303: * <li>0 - Reserved for NCS compatibility</li>
304: * <li>2 - RFC 4122/Leach-Salz</li>
305: * <li>6 - Reserved for Microsoft Corporation compatibility</li>
306: * <li>7 - Reserved for future use</li>
307: * </ul>
308: *
309: * @return An int value.
310: */
311: public int variant() {
312: return variant;
313: }
314:
315: /**
316: * <p>
317: * The timestamp value of the version 1, variant 2 UUID as per <a
318: * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
319: * </p>
320: *
321: * @return A long value.
322: * @throws UnsupportedOperationException
323: * if {@link #version()} is not 1.
324: */
325: public long timestamp() {
326: if (version != 1) {
327: throw new UnsupportedOperationException();
328: }
329: return timestamp;
330: }
331:
332: /**
333: * <p>
334: * The clock sequence value of the version 1, variant 2 UUID as per <a
335: * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
336: * </p>
337: *
338: * @return A long value.
339: * @throws UnsupportedOperationException
340: * if {@link #version()} is not 1.
341: */
342: public int clockSequence() {
343: if (version != 1) {
344: throw new UnsupportedOperationException();
345: }
346: return clockSequence;
347: }
348:
349: /**
350: * <p>
351: * The node value of the version 1, variant 2 UUID as per <a
352: * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
353: * </p>
354: *
355: * @return A long value.
356: * @throws UnsupportedOperationException
357: * if {@link #version()} is not 1.
358: */
359: public long node() {
360: if (version != 1) {
361: throw new UnsupportedOperationException();
362: }
363: return node;
364: }
365:
366: /**
367: * <p>
368: * Compares this UUID to the specified UUID. The natural ordering of UUIDs
369: * is based upon the value of the bits from most significant to least
370: * significant.
371: * </p>
372: *
373: * @param uuid
374: * The UUID to compare to.
375: * @return A value of -1, 0 or 1 if this UUID is less than, equal to or
376: * greater than <code>uuid</code>.
377: */
378: public int compareTo(UUID uuid) {
379: if (uuid == this ) {
380: return 0;
381: }
382:
383: if (this .mostSigBits != uuid.mostSigBits) {
384: return this .mostSigBits < uuid.mostSigBits ? -1 : 1;
385: }
386:
387: assert this .mostSigBits == uuid.mostSigBits;
388:
389: if (this .leastSigBits != uuid.leastSigBits) {
390: return this .leastSigBits < uuid.leastSigBits ? -1 : 1;
391: }
392:
393: assert this .leastSigBits == uuid.leastSigBits;
394:
395: return 0;
396: }
397:
398: /**
399: * <p>
400: * Compares this UUID to another object for equality. If <code>object</code>
401: * is not <code>null</code>, a UUID instance and all bits are equals,
402: * then <code>true</code> is returned.
403: * </p>
404: *
405: * @param object
406: * The Object to compare to.
407: * @return A <code>true</code> if this UUID is equal to
408: * <code>object</code> or <code>false</code> if not.
409: */
410: @Override
411: public boolean equals(Object object) {
412: if (object == null) {
413: return false;
414: }
415:
416: if (this == object) {
417: return true;
418: }
419:
420: if (!(object instanceof UUID)) {
421: return false;
422: }
423:
424: UUID that = (UUID) object;
425:
426: return (this .leastSigBits == that.leastSigBits)
427: && (this .mostSigBits == that.mostSigBits);
428: }
429:
430: /**
431: * <p>
432: * Returns a hash value for this UUID that is consistent with the
433: * {@link #equals(Object)} method.
434: * </p>
435: *
436: * @return An int value.
437: */
438: @Override
439: public int hashCode() {
440: return hash;
441: }
442:
443: /**
444: * <p>
445: * Returns a string representation of this UUID in the following format, as
446: * per <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
447: * </p>
448: *
449: * <pre>
450: * UUID = time-low "-" time-mid "-"
451: * time-high-and-version "-"
452: * clock-seq-and-reserved
453: * clock-seq-low "-" node
454: * time-low = 4hexOctet
455: * time-mid = 2hexOctet
456: * time-high-and-version = 2hexOctet
457: * clock-seq-and-reserved = hexOctet
458: * clock-seq-low = hexOctet
459: * node = 6hexOctet
460: * hexOctet = hexDigit hexDigit
461: * hexDigit =
462: * "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" /
463: * "a" / "b" / "c" / "d" / "e" / "f" /
464: * "A" / "B" / "C" / "D" / "E" / "F"
465: * </pre>
466: *
467: * @return A String instance.
468: */
469: @Override
470: public String toString() {
471: StringBuilder builder = new StringBuilder(36);
472: String msbStr = Long.toHexString(mostSigBits);
473: if (msbStr.length() < 16) {
474: int diff = 16 - msbStr.length();
475: for (int i = 0; i < diff; i++) {
476: builder.append('0');
477: }
478: }
479: builder.append(msbStr);
480: builder.insert(8, '-');
481: builder.insert(13, '-');
482: builder.append('-');
483: String lsbStr = Long.toHexString(leastSigBits);
484: if (lsbStr.length() < 16) {
485: int diff = 16 - lsbStr.length();
486: for (int i = 0; i < diff; i++) {
487: builder.append('0');
488: }
489: }
490: builder.append(lsbStr);
491: builder.insert(23, '-');
492: return builder.toString();
493: }
494:
495: /**
496: * <p>
497: * Resets the transient fields to match the behavior of the constructor.
498: * </p>
499: *
500: * @param in
501: * The InputStream to read from.
502: * @throws IOException
503: * if <code>in</code> throws it.
504: * @throws ClassNotFoundException
505: * if <code>in</code> throws it.
506: */
507: private void readObject(ObjectInputStream in) throws IOException,
508: ClassNotFoundException {
509: // read in non-transient fields
510: in.defaultReadObject();
511: // setup transient fields
512: init();
513: }
514: }
|