Home | History | Annotate | Download | only in util
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.util;
     19 
     20 import java.io.IOException;
     21 import java.io.ObjectInputStream;
     22 import java.io.Serializable;
     23 import java.nio.ByteOrder;
     24 import java.security.MessageDigest;
     25 import java.security.NoSuchAlgorithmException;
     26 import java.security.SecureRandom;
     27 import libcore.io.Memory;
     28 
     29 /**
     30  * UUID is an immutable representation of a 128-bit universally unique
     31  * identifier (UUID).
     32  * <p>
     33  * There are multiple, variant layouts of UUIDs, but this class is based upon
     34  * variant 2 of <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>, the
     35  * Leach-Salz variant. This class can be used to model alternate variants, but
     36  * most of the methods will be unsupported in those cases; see each method for
     37  * details.
     38  *
     39  * @since 1.5
     40  */
     41 public final class UUID implements Serializable, Comparable<UUID> {
     42 
     43     private static final long serialVersionUID = -4856846361193249489L;
     44 
     45     private static SecureRandom rng;
     46 
     47     private long mostSigBits;
     48     private long leastSigBits;
     49 
     50     private transient int variant;
     51     private transient int version;
     52     private transient long timestamp;
     53     private transient int clockSequence;
     54     private transient long node;
     55     private transient int hash;
     56 
     57     /**
     58      * <p>
     59      * Constructs an instance with the specified bits.
     60      *
     61      * @param mostSigBits
     62      *            The 64 most significant bits of the UUID.
     63      * @param leastSigBits
     64      *            The 64 least significant bits of the UUID.
     65      */
     66     public UUID(long mostSigBits, long leastSigBits) {
     67         this.mostSigBits = mostSigBits;
     68         this.leastSigBits = leastSigBits;
     69         init();
     70     }
     71 
     72     /**
     73      * <p>
     74      * Sets up the transient fields of this instance based on the current values
     75      * of the {@code mostSigBits} and {@code leastSigBits} fields.
     76      */
     77     private void init() {
     78         // setup hash field
     79         int msbHash = (int) (mostSigBits ^ (mostSigBits >>> 32));
     80         int lsbHash = (int) (leastSigBits ^ (leastSigBits >>> 32));
     81         hash = msbHash ^ lsbHash;
     82 
     83         // setup variant field
     84         if ((leastSigBits & 0x8000000000000000L) == 0) {
     85             // MSB0 not set, NCS backwards compatibility variant
     86             variant = 0;
     87         } else if ((leastSigBits & 0x4000000000000000L) != 0) {
     88             // MSB1 set, either MS reserved or future reserved
     89             variant = (int) ((leastSigBits & 0xE000000000000000L) >>> 61);
     90         } else {
     91             // MSB1 not set, RFC 4122 variant
     92             variant = 2;
     93         }
     94 
     95         // setup version field
     96         version = (int) ((mostSigBits & 0x000000000000F000) >>> 12);
     97 
     98         if (variant != 2 && version != 1) {
     99             return;
    100         }
    101 
    102         // setup timestamp field
    103         long timeLow = (mostSigBits & 0xFFFFFFFF00000000L) >>> 32;
    104         long timeMid = (mostSigBits & 0x00000000FFFF0000L) << 16;
    105         long timeHigh = (mostSigBits & 0x0000000000000FFFL) << 48;
    106         timestamp = timeLow | timeMid | timeHigh;
    107 
    108         // setup clock sequence field
    109         clockSequence = (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
    110 
    111         // setup node field
    112         node = (leastSigBits & 0x0000FFFFFFFFFFFFL);
    113     }
    114 
    115     /**
    116      * <p>
    117      * Generates a variant 2, version 4 (randomly generated number) UUID as per
    118      * <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
    119      *
    120      * @return an UUID instance.
    121      */
    122     public static UUID randomUUID() {
    123         byte[] data = new byte[16];
    124         // lock on the class to protect lazy init
    125         synchronized (UUID.class) {
    126             if (rng == null) {
    127                 rng = new SecureRandom();
    128             }
    129         }
    130         rng.nextBytes(data);
    131         return makeUuid(data, 4);
    132     }
    133 
    134     /**
    135      * <p>
    136      * Generates a variant 2, version 3 (name-based, MD5-hashed) UUID as per <a
    137      * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
    138      *
    139      * @param name
    140      *            the name used as byte array to create an UUID.
    141      * @return an UUID instance.
    142      */
    143     public static UUID nameUUIDFromBytes(byte[] name) {
    144         if (name == null) {
    145             throw new NullPointerException();
    146         }
    147         try {
    148             MessageDigest md = MessageDigest.getInstance("MD5");
    149             return makeUuid(md.digest(name), 3);
    150         } catch (NoSuchAlgorithmException e) {
    151             throw new AssertionError(e);
    152         }
    153     }
    154 
    155     private static UUID makeUuid(byte[] hash, int version) {
    156         long msb = Memory.peekLong(hash, 0, ByteOrder.BIG_ENDIAN);
    157         long lsb = Memory.peekLong(hash, 8, ByteOrder.BIG_ENDIAN);
    158         // Set the version field.
    159         msb &= ~(0xfL << 12);
    160         msb |= ((long) version) << 12;
    161         // Set the variant field to 2. Note that the variant field is variable-width,
    162         // so supporting other variants is not just a matter of changing the constant 2 below!
    163         lsb &= ~(0x3L << 62);
    164         lsb |= 2L << 62;
    165         return new UUID(msb, lsb);
    166     }
    167 
    168     /**
    169      * <p>
    170      * Parses a UUID string with the format defined by {@link #toString()}.
    171      *
    172      * @param uuid
    173      *            the UUID string to parse.
    174      * @return an UUID instance.
    175      * @throws NullPointerException
    176      *             if {@code uuid} is {@code null}.
    177      * @throws IllegalArgumentException
    178      *             if {@code uuid} is not formatted correctly.
    179      */
    180     public static UUID fromString(String uuid) {
    181         if (uuid == null) {
    182             throw new NullPointerException();
    183         }
    184 
    185         int[] position = new int[5];
    186         int lastPosition = 1;
    187         int startPosition = 0;
    188 
    189         int i = 0;
    190         for (; i < position.length && lastPosition > 0; i++) {
    191             position[i] = uuid.indexOf("-", startPosition);
    192             lastPosition = position[i];
    193             startPosition = position[i] + 1;
    194         }
    195 
    196         // should have and only can have four "-" in UUID
    197         if (i != position.length || lastPosition != -1) {
    198             throw new IllegalArgumentException("Invalid UUID: " + uuid);
    199         }
    200 
    201         long m1 = Long.parseLong(uuid.substring(0, position[0]), 16);
    202         long m2 = Long.parseLong(uuid.substring(position[0] + 1, position[1]), 16);
    203         long m3 = Long.parseLong(uuid.substring(position[1] + 1, position[2]), 16);
    204 
    205         long lsb1 = Long.parseLong(uuid.substring(position[2] + 1, position[3]), 16);
    206         long lsb2 = Long.parseLong(uuid.substring(position[3] + 1), 16);
    207 
    208         long msb = (m1 << 32) | (m2 << 16) | m3;
    209         long lsb = (lsb1 << 48) | lsb2;
    210 
    211         return new UUID(msb, lsb);
    212     }
    213 
    214     /**
    215      * <p>
    216      * The 64 least significant bits of the UUID.
    217      *
    218      * @return the 64 least significant bits.
    219      */
    220     public long getLeastSignificantBits() {
    221         return leastSigBits;
    222     }
    223 
    224     /**
    225      * <p>
    226      * The 64 most significant bits of the UUID.
    227      *
    228      * @return the 64 most significant bits.
    229      */
    230     public long getMostSignificantBits() {
    231         return mostSigBits;
    232     }
    233 
    234     /**
    235      * <p>
    236      * The version of the variant 2 UUID as per <a
    237      * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>. If the variant
    238      * is not 2, then the version will be 0.
    239      * <ul>
    240      * <li>1 - Time-based UUID</li>
    241      * <li>2 - DCE Security UUID</li>
    242      * <li>3 - Name-based with MD5 hashing UUID ({@link #nameUUIDFromBytes(byte[])})</li>
    243      * <li>4 - Randomly generated UUID ({@link #randomUUID()})</li>
    244      * <li>5 - Name-based with SHA-1 hashing UUID</li>
    245      * </ul>
    246      *
    247      * @return an {@code int} value.
    248      */
    249     public int version() {
    250         return version;
    251     }
    252 
    253     /**
    254      * <p>
    255      * The variant of the UUID as per <a
    256      * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
    257      * <ul>
    258      * <li>0 - Reserved for NCS compatibility</li>
    259      * <li>2 - RFC 4122/Leach-Salz</li>
    260      * <li>6 - Reserved for Microsoft Corporation compatibility</li>
    261      * <li>7 - Reserved for future use</li>
    262      * </ul>
    263      *
    264      * @return an {@code int} value.
    265      */
    266     public int variant() {
    267         return variant;
    268     }
    269 
    270     /**
    271      * <p>
    272      * The timestamp value of the version 1, variant 2 UUID as per <a
    273      * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
    274      *
    275      * @return a {@code long} value.
    276      * @throws UnsupportedOperationException
    277      *             if {@link #version()} is not 1.
    278      */
    279     public long timestamp() {
    280         if (version != 1) {
    281             throw new UnsupportedOperationException();
    282         }
    283         return timestamp;
    284     }
    285 
    286     /**
    287      * <p>
    288      * The clock sequence value of the version 1, variant 2 UUID as per <a
    289      * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
    290      *
    291      * @return a {@code long} value.
    292      * @throws UnsupportedOperationException
    293      *             if {@link #version()} is not 1.
    294      */
    295     public int clockSequence() {
    296         if (version != 1) {
    297             throw new UnsupportedOperationException();
    298         }
    299         return clockSequence;
    300     }
    301 
    302     /**
    303      * <p>
    304      * The node value of the version 1, variant 2 UUID as per <a
    305      * href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
    306      *
    307      * @return a {@code long} value.
    308      * @throws UnsupportedOperationException
    309      *             if {@link #version()} is not 1.
    310      */
    311     public long node() {
    312         if (version != 1) {
    313             throw new UnsupportedOperationException();
    314         }
    315         return node;
    316     }
    317 
    318     /**
    319      * <p>
    320      * Compares this UUID to the specified UUID. The natural ordering of UUIDs
    321      * is based upon the value of the bits from most significant to least
    322      * significant.
    323      *
    324      * @param uuid
    325      *            the UUID to compare to.
    326      * @return a value of -1, 0 or 1 if this UUID is less than, equal to or
    327      *         greater than {@code uuid}.
    328      */
    329     public int compareTo(UUID uuid) {
    330         if (uuid == this) {
    331             return 0;
    332         }
    333 
    334         if (this.mostSigBits != uuid.mostSigBits) {
    335             return this.mostSigBits < uuid.mostSigBits ? -1 : 1;
    336         }
    337 
    338         assert this.mostSigBits == uuid.mostSigBits;
    339 
    340         if (this.leastSigBits != uuid.leastSigBits) {
    341             return this.leastSigBits < uuid.leastSigBits ? -1 : 1;
    342         }
    343 
    344         assert this.leastSigBits == uuid.leastSigBits;
    345 
    346         return 0;
    347     }
    348 
    349     /**
    350      * <p>
    351      * Compares this UUID to another object for equality. If {@code object}
    352      * is not {@code null}, is a UUID instance, and all bits are equal, then
    353      * {@code true} is returned.
    354      *
    355      * @param object
    356      *            the {@code Object} to compare to.
    357      * @return {@code true} if this UUID is equal to {@code object}
    358      *         or {@code false} if not.
    359      */
    360     @Override
    361     public boolean equals(Object object) {
    362         if (object == null) {
    363             return false;
    364         }
    365 
    366         if (this == object) {
    367             return true;
    368         }
    369 
    370         if (!(object instanceof UUID)) {
    371             return false;
    372         }
    373 
    374         UUID that = (UUID) object;
    375 
    376         return (this.leastSigBits == that.leastSigBits)
    377                 && (this.mostSigBits == that.mostSigBits);
    378     }
    379 
    380     /**
    381      * <p>
    382      * Returns a hash value for this UUID that is consistent with the
    383      * {@link #equals(Object)} method.
    384      *
    385      * @return an {@code int} value.
    386      */
    387     @Override
    388     public int hashCode() {
    389         return hash;
    390     }
    391 
    392     /**
    393      * <p>
    394      * Returns a string representation of this UUID in the following format, as
    395      * per <a href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122</a>.
    396      *
    397      * <pre>
    398      *            UUID                   = time-low &quot;-&quot; time-mid &quot;-&quot;
    399      *                                     time-high-and-version &quot;-&quot;
    400      *                                     clock-seq-and-reserved
    401      *                                     clock-seq-low &quot;-&quot; node
    402      *            time-low               = 4hexOctet
    403      *            time-mid               = 2hexOctet
    404      *            time-high-and-version  = 2hexOctet
    405      *            clock-seq-and-reserved = hexOctet
    406      *            clock-seq-low          = hexOctet
    407      *            node                   = 6hexOctet
    408      *            hexOctet               = hexDigit hexDigit
    409      *            hexDigit =
    410      *                &quot;0&quot; / &quot;1&quot; / &quot;2&quot; / &quot;3&quot; / &quot;4&quot; / &quot;5&quot; / &quot;6&quot; / &quot;7&quot; / &quot;8&quot; / &quot;9&quot; /
    411      *                &quot;a&quot; / &quot;b&quot; / &quot;c&quot; / &quot;d&quot; / &quot;e&quot; / &quot;f&quot; /
    412      *                &quot;A&quot; / &quot;B&quot; / &quot;C&quot; / &quot;D&quot; / &quot;E&quot; / &quot;F&quot;
    413      * </pre>
    414      *
    415      * @return a String instance.
    416      */
    417     @Override
    418     public String toString() {
    419         StringBuilder builder = new StringBuilder(36);
    420         String msbStr = Long.toHexString(mostSigBits);
    421         if (msbStr.length() < 16) {
    422             int diff = 16 - msbStr.length();
    423             for (int i = 0; i < diff; i++) {
    424                 builder.append('0');
    425             }
    426         }
    427         builder.append(msbStr);
    428         builder.insert(8, '-');
    429         builder.insert(13, '-');
    430         builder.append('-');
    431         String lsbStr = Long.toHexString(leastSigBits);
    432         if (lsbStr.length() < 16) {
    433             int diff = 16 - lsbStr.length();
    434             for (int i = 0; i < diff; i++) {
    435                 builder.append('0');
    436             }
    437         }
    438         builder.append(lsbStr);
    439         builder.insert(23, '-');
    440         return builder.toString();
    441     }
    442 
    443     /**
    444      * <p>
    445      * Resets the transient fields to match the behavior of the constructor.
    446      *
    447      * @param in
    448      *            the {@code InputStream} to read from.
    449      * @throws IOException
    450      *             if {@code in} throws it.
    451      * @throws ClassNotFoundException
    452      *             if {@code in} throws it.
    453      */
    454     private void readObject(ObjectInputStream in) throws IOException,
    455             ClassNotFoundException {
    456         // read in non-transient fields
    457         in.defaultReadObject();
    458         // setup transient fields
    459         init();
    460     }
    461 }
    462