| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.kafka.common; |
| |
| import java.nio.ByteBuffer; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Base64; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * This class defines an immutable universally unique identifier (UUID). It represents a 128-bit value. |
| * More specifically, the random UUIDs generated by this class are variant 2 (Leach-Salz) version 4 UUIDs. |
| * This is the same type of UUID as the ones generated by java.util.UUID. The toString() method prints |
| * using the base64 string encoding. Likewise, the fromString method expects a base64 string encoding. |
| */ |
| public class Uuid implements Comparable<Uuid> { |
| |
| /** |
| * A reserved UUID. Will never be returned by the randomUuid method. |
| */ |
| public static final Uuid ONE_UUID = new Uuid(0L, 1L); |
| |
| /** |
| * A UUID for the metadata topic in KRaft mode. Will never be returned by the randomUuid method. |
| */ |
| public static final Uuid METADATA_TOPIC_ID = ONE_UUID; |
| |
| /** |
| * A UUID that represents a null or empty UUID. Will never be returned by the randomUuid method. |
| */ |
| public static final Uuid ZERO_UUID = new Uuid(0L, 0L); |
| |
| /** |
| * The set of reserved UUIDs that will never be returned by the randomUuid method. |
| */ |
| public static final Set<Uuid> RESERVED = Set.of(ZERO_UUID, ONE_UUID); |
| |
| private final long mostSignificantBits; |
| private final long leastSignificantBits; |
| |
| /** |
| * Constructs a 128-bit type 4 UUID where the first long represents the most significant 64 bits |
| * and the second long represents the least significant 64 bits. |
| */ |
| public Uuid(long mostSigBits, long leastSigBits) { |
| this.mostSignificantBits = mostSigBits; |
| this.leastSignificantBits = leastSigBits; |
| } |
| |
| private static Uuid unsafeRandomUuid() { |
| java.util.UUID jUuid = java.util.UUID.randomUUID(); |
| return new Uuid(jUuid.getMostSignificantBits(), jUuid.getLeastSignificantBits()); |
| } |
| |
| /** |
| * Static factory to retrieve a type 4 (pseudo randomly generated) UUID. |
| * |
| * This will not generate a UUID equal to 0, 1, or one whose string representation starts with a dash ("-") |
| */ |
| public static Uuid randomUuid() { |
| Uuid uuid = unsafeRandomUuid(); |
| while (RESERVED.contains(uuid) || uuid.toString().startsWith("-")) { |
| uuid = unsafeRandomUuid(); |
| } |
| return uuid; |
| } |
| |
| /** |
| * Returns the most significant bits of the UUID's 128 value. |
| */ |
| public long getMostSignificantBits() { |
| return this.mostSignificantBits; |
| } |
| |
| /** |
| * Returns the least significant bits of the UUID's 128 value. |
| */ |
| public long getLeastSignificantBits() { |
| return this.leastSignificantBits; |
| } |
| |
| /** |
| * Returns true iff obj is another Uuid represented by the same two long values. |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| if ((null == obj) || (obj.getClass() != this.getClass())) |
| return false; |
| Uuid id = (Uuid) obj; |
| return this.mostSignificantBits == id.mostSignificantBits && |
| this.leastSignificantBits == id.leastSignificantBits; |
| } |
| |
| /** |
| * Returns a hash code for this UUID |
| */ |
| @Override |
| public int hashCode() { |
| long xor = mostSignificantBits ^ leastSignificantBits; |
| return (int) (xor >> 32) ^ (int) xor; |
| } |
| |
| /** |
| * Returns a base64 string encoding of the UUID. |
| */ |
| @Override |
| public String toString() { |
| return Base64.getUrlEncoder().withoutPadding().encodeToString(getBytesFromUuid()); |
| } |
| |
| /** |
| * Creates a UUID based on a base64 string encoding used in the toString() method. |
| */ |
| public static Uuid fromString(String str) { |
| if (str.length() > 24) { |
| throw new IllegalArgumentException("Input string with prefix `" |
| + str.substring(0, 24) + "` is too long to be decoded as a base64 UUID"); |
| } |
| |
| ByteBuffer uuidBytes = ByteBuffer.wrap(Base64.getUrlDecoder().decode(str)); |
| if (uuidBytes.remaining() != 16) { |
| throw new IllegalArgumentException("Input string `" + str + "` decoded as " |
| + uuidBytes.remaining() + " bytes, which is not equal to the expected 16 bytes " |
| + "of a base64-encoded UUID"); |
| } |
| |
| return new Uuid(uuidBytes.getLong(), uuidBytes.getLong()); |
| } |
| |
| private byte[] getBytesFromUuid() { |
| // Extract bytes for uuid which is 128 bits (or 16 bytes) long. |
| ByteBuffer uuidBytes = ByteBuffer.wrap(new byte[16]); |
| uuidBytes.putLong(this.mostSignificantBits); |
| uuidBytes.putLong(this.leastSignificantBits); |
| return uuidBytes.array(); |
| } |
| |
| @Override |
| public int compareTo(Uuid other) { |
| if (mostSignificantBits > other.mostSignificantBits) { |
| return 1; |
| } else if (mostSignificantBits < other.mostSignificantBits) { |
| return -1; |
| } else if (leastSignificantBits > other.leastSignificantBits) { |
| return 1; |
| } else if (leastSignificantBits < other.leastSignificantBits) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Convert a list of Uuid to an array of Uuid. |
| * |
| * @param list The input list |
| * @return The output array |
| */ |
| public static Uuid[] toArray(List<Uuid> list) { |
| if (list == null) return null; |
| Uuid[] array = new Uuid[list.size()]; |
| for (int i = 0; i < list.size(); i++) { |
| array[i] = list.get(i); |
| } |
| return array; |
| } |
| |
| /** |
| * Convert an array of Uuids to a list of Uuid. |
| * |
| * @param array The input array |
| * @return The output list |
| */ |
| public static List<Uuid> toList(Uuid[] array) { |
| if (array == null) return null; |
| List<Uuid> list = new ArrayList<>(array.length); |
| list.addAll(Arrays.asList(array)); |
| return list; |
| } |
| } |