IntegerUuid.java
/*
* This file is part of Waarp Project (named also Waarp or GG).
*
* Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
* tags. See the COPYRIGHT.txt in the distribution for a full listing of
* individual contributors.
*
* All Waarp Project is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Waarp . If not, see <http://www.gnu.org/licenses/>.
*/
package org.waarp.common.guid;
import org.waarp.common.utility.Hexa;
import org.waarp.common.utility.StringUtils;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
/**
* UUID Generator (also Global UUID Generator) but limited to 1 Integer (32
* bits) <br>
* <br>
* Inspired from com.groupon locality-uuid which used combination of internal
* counter value - process id -
* and Timestamp. see https://github.com/groupon/locality-uuid.java <br>
* <br>
* But force sequence and take care of errors and improves some performance
* issues.<br>
* <br>
* Limit is about 4000000/s UUID
*/
public final class IntegerUuid {
/**
* Counter part
*/
private static final AtomicInteger COUNTER =
new AtomicInteger(StringUtils.RANDOM.nextInt());
/**
* Byte size of UUID
*/
private static final int UUIDSIZE = 4;
/**
* real UUID
*/
private final byte[] uuid = { 0, 0, 0, 0 };
static final synchronized int getCounter() {
if (COUNTER.compareAndSet(Integer.MAX_VALUE, Integer.MIN_VALUE)) {
return Integer.MAX_VALUE;
} else {
return COUNTER.getAndIncrement();
}
}
/**
* Constructor that generates a new UUID using the current process id, MAC
* address, and timestamp
*/
public IntegerUuid() {
// atomically
final int count = getCounter();
uuid[0] = (byte) (count >> 24);
uuid[1] = (byte) (count >> 16);
uuid[2] = (byte) (count >> 8);
uuid[3] = (byte) count;
}
/**
* Constructor that takes a byte array as this UUID's content
*
* @param bytes UUID content
*/
public IntegerUuid(final byte[] bytes) {
if (bytes.length != UUIDSIZE) {
throw new RuntimeException(
"Attempted to parse malformed UUID: " + Arrays.toString(bytes));
}
System.arraycopy(bytes, 0, uuid, 0, UUIDSIZE);
}
public IntegerUuid(final int value) {
uuid[0] = (byte) (value >> 24);
uuid[1] = (byte) (value >> 16);
uuid[2] = (byte) (value >> 8);
uuid[3] = (byte) value;
}
public IntegerUuid(final String idsource) {
final String id = idsource.trim();
if (id.length() != UUIDSIZE * 2) {
throw new IllegalArgumentException(
"Attempted to parse malformed UUID: " + id);
}
System.arraycopy(Hexa.fromHex(id), 0, uuid, 0, UUIDSIZE);
}
@Override
public String toString() {
return Hexa.toHex(uuid);
}
/**
* copy the uuid of this UUID, so that it can't be changed, and return it
*
* @return raw byte array of UUID
*/
public final byte[] getBytes() {
return Arrays.copyOf(uuid, UUIDSIZE);
}
/**
* extract timestamp from raw UUID bytes and return as int
*
* @return millisecond UTC timestamp from generation of the UUID
*/
public final long getTimestamp() {
long time;
time = ((long) uuid[0] & 0xFF) << 24;
time |= ((long) uuid[2] & 0xFF) << 16;
time |= ((long) uuid[2] & 0xFF) << 8;
time |= (long) uuid[3] & 0xFF;
return time;
}
@Override
public final boolean equals(final Object o) {
if (!(o instanceof IntegerUuid)) {
return false;
}
return this == o || Arrays.equals(uuid, ((IntegerUuid) o).uuid);
}
@Override
public final int hashCode() {
return Arrays.hashCode(uuid);
}
/**
* @return the equivalent UUID as int
*/
public final int getInt() {
int value = ((int) uuid[0] & 0xFF) << 24;
value |= ((long) uuid[1] & 0xFF) << 16;
value |= ((long) uuid[2] & 0xFF) << 8;
value |= (long) uuid[3] & 0xFF;
return value;
}
}