org.apache.kafka.common.Uuid Maven / Gradle / Ivy
/*
* 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.Base64;
/**
* 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 {
/**
* A UUID for the metadata topic in KRaft mode. Will never be returned by the randomUuid method.
*/
public static final Uuid METADATA_TOPIC_ID = new Uuid(0L, 1L);
/**
* 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);
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 (uuid.equals(METADATA_TOPIC_ID) || uuid.equals(ZERO_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;
}
}
}