All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rpc.turbo.util.uuid.ObjectId128 Maven / Gradle / Ivy

There is a newer version: 0.0.9
Show newest version
package rpc.turbo.util.uuid;

import static rpc.turbo.util.HexUtils.byteToHexLE;
import static rpc.turbo.util.UnsafeUtils.unsafe;
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;

import java.io.Serializable;
import java.net.NetworkInterface;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Objects;

import io.netty.buffer.ByteBuf;
import rpc.turbo.util.SystemClock;
import rpc.turbo.util.UnsafeStringUtils;
import rpc.turbo.util.concurrent.ConcurrentIntegerSequencer;

/**
 * 

* A globally unique identifier for objects. *

* *

* Consists of 128bit(16 bytes), divided as follows: *

* * * * * * * * * * * * * * * * * * * * * * * * * * *
ObjectID layout
0123456789101112131415
timemachinepidinc
* *

* Instances of this class are immutable. *

* */ public final class ObjectId128 implements Serializable { private static final long serialVersionUID = -6453295018947782081L; private static final int LOW_ORDER_THREE_BYTES = 0x00FFFFFF; private static final int MACHINE_IDENTIFIER; private static final short PROCESS_IDENTIFIER; private static final long UNION_HIGH; private static final ConcurrentIntegerSequencer NEXT_COUNTER = new ConcurrentIntegerSequencer( new SecureRandom().nextInt()); public final long timestamp; public final long union; /** * Gets a new object id. * * @return the new id */ public static ObjectId128 next() { int next = NEXT_COUNTER.next() & LOW_ORDER_THREE_BYTES; long union = UNION_HIGH | next; return new ObjectId128(SystemClock.fast().mills(), union); } public ObjectId128(final long timestamp, final long union) { this.timestamp = timestamp; this.union = union; } public ObjectId128(final ByteBuf buffer) { Objects.requireNonNull(buffer, "buffer"); timestamp = buffer.readLong(); union = buffer.readLong(); } public long getTimestamp() { return timestamp; } public long getUnion() { return union; } public void writeTo(final ByteBuf buffer) { buffer.writeLong(timestamp); buffer.writeLong(union); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (timestamp ^ (timestamp >>> 32)); result = prime * result + (int) (union ^ (union >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ObjectId128 other = (ObjectId128) obj; if (timestamp != other.timestamp) return false; if (union != other.union) return false; return true; } /** * 128位编码, 长度为32 * * @return */ public String toHexString() { byte[] bytes = new byte[32]; unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 0, byteToHexLE(timestamp >> 52)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 2, byteToHexLE(timestamp >> 48)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 4, byteToHexLE(timestamp >> 40)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 6, byteToHexLE(timestamp >> 32)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 8, byteToHexLE(timestamp >> 24)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 10, byteToHexLE(timestamp >> 16)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 12, byteToHexLE(timestamp >> 8)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 14, byteToHexLE(timestamp)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 16, byteToHexLE(union >> 52)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 18, byteToHexLE(union >> 48)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 20, byteToHexLE(union >> 40)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 22, byteToHexLE(union >> 32)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 24, byteToHexLE(union >> 24)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 26, byteToHexLE(union >> 16)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 28, byteToHexLE(union >> 8)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 30, byteToHexLE(union)); String hex = UnsafeStringUtils.toLatin1String(bytes); return hex; } @Override public String toString() { return toHexString(); } static { try { MACHINE_IDENTIFIER = createMachineIdentifier(); PROCESS_IDENTIFIER = createProcessIdentifier(); UNION_HIGH = ((MACHINE_IDENTIFIER & 0xFF_FF_FFL) << 40) | ((PROCESS_IDENTIFIER & 0xFF_FFL) << 24); } catch (Exception e) { throw new RuntimeException(e); } } private static int createMachineIdentifier() { // build a 2-byte machine piece based on NICs info int machinePiece; try { StringBuilder sb = new StringBuilder(); Enumeration e = NetworkInterface.getNetworkInterfaces(); while (e.hasMoreElements()) { NetworkInterface ni = e.nextElement(); sb.append(ni.toString()); byte[] mac = ni.getHardwareAddress(); if (mac != null) { ByteBuffer bb = ByteBuffer.wrap(mac); try { sb.append(bb.getChar()); sb.append(bb.getChar()); sb.append(bb.getChar()); } catch (BufferUnderflowException shortHardwareAddressException) { // NOPMD // mac with less than 6 bytes. continue } } } machinePiece = sb.toString().hashCode(); } catch (Throwable t) { // exception sometimes happens with IBM JVM, use random machinePiece = (new SecureRandom().nextInt()); System.err.println("Failed to get machine identifier from network interface, using random number instead " + Arrays.toString(t.getStackTrace())); } machinePiece = machinePiece & LOW_ORDER_THREE_BYTES; return machinePiece; } // Creates the process identifier. This does not have to be unique per class // loader because // NEXT_COUNTER will provide the uniqueness. private static short createProcessIdentifier() { short processId; try { String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); if (processName.contains("@")) { processId = (short) Integer.parseInt(processName.substring(0, processName.indexOf('@'))); } else { processId = (short) java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode(); } } catch (Throwable t) { processId = (short) new SecureRandom().nextInt(); System.err.println("Failed to get process identifier from JMX, using random number instead " + Arrays.toString(t.getStackTrace())); } return processId; } public static void main(String[] args) { ObjectId128 id = next(); System.out.println(id.toHexString()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy