From: Mathieu Baudier Date: Sun, 23 Jan 2022 05:38:12 +0000 (+0100) Subject: Move time UUID nodeid back to the factory X-Git-Tag: argeo-commons-2.3.5~73 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=8368d270c495fcb0c762c6e98783223321061a4a Move time UUID nodeid back to the factory --- diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/uuid/ConcurrentTimeUuidState.java b/org.argeo.api.acr/src/org/argeo/api/acr/uuid/ConcurrentTimeUuidState.java index bf4039678..d83356b5c 100644 --- a/org.argeo.api.acr/src/org/argeo/api/acr/uuid/ConcurrentTimeUuidState.java +++ b/org.argeo.api.acr/src/org/argeo/api/acr/uuid/ConcurrentTimeUuidState.java @@ -1,6 +1,5 @@ package org.argeo.api.acr.uuid; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.time.Clock; import java.time.Duration; @@ -15,10 +14,10 @@ public class ConcurrentTimeUuidState implements TimeUuidState { /** The maximum possible value of the clocksequence. */ private final static int MAX_CLOCKSEQUENCE = 16384; - private final byte[] nodeId = new byte[6]; private final ThreadLocal holder; private final Instant startInstant; + /** A start timestamp to which {@link System#nanoTime()}/100 can be added. */ private final long startTimeStamp; private final Clock clock; @@ -26,22 +25,12 @@ public class ConcurrentTimeUuidState implements TimeUuidState { private final SecureRandom secureRandom; - public ConcurrentTimeUuidState(byte[] nodeId, int offset, SecureRandom secureRandom, Clock clock) { + public ConcurrentTimeUuidState(SecureRandom secureRandom, Clock clock) { useClockForMeasurement = clock != null; this.clock = clock != null ? clock : Clock.systemUTC(); Objects.requireNonNull(secureRandom); this.secureRandom = secureRandom; - if (nodeId != null) { - // copy array in case it should change in the future - if (offset + 6 > nodeId.length) - throw new IllegalArgumentException( - "Node id array is too small: " + nodeId.length + ", offset=" + offset); - System.arraycopy(nodeId, offset, this.nodeId, 0, 6); - } else { - this.secureRandom.nextBytes(this.nodeId); - assert TimeUuidState.isNoMacAddressNodeId(this.nodeId); - } // compute the start reference startInstant = Instant.now(this.clock); @@ -57,7 +46,6 @@ public class ConcurrentTimeUuidState implements TimeUuidState { Holder value = new Holder(); value.lastTimestamp = startTimeStamp; value.clockSequence = newClockSequence(); - System.arraycopy(ConcurrentTimeUuidState.this.nodeId, 0, value.nodeId, 0, 6); return value; } }; @@ -116,16 +104,6 @@ public class ConcurrentTimeUuidState implements TimeUuidState { return (duration.getSeconds() * 10000000 + duration.getNano() / 100); } - protected SecureRandom initSecureRandom() { - SecureRandom secureRandom; - try { - secureRandom = SecureRandom.getInstanceStrong(); - } catch (NoSuchAlgorithmException e) { - secureRandom = new SecureRandom(); - } - return secureRandom; - } - /* * STATE OPERATIONS */ @@ -138,16 +116,15 @@ public class ConcurrentTimeUuidState implements TimeUuidState { * ACCESSORS */ - @Override - public byte[] getNodeId() { - byte[] arr = new byte[6]; - System.arraycopy(holder.get().nodeId, 0, arr, 0, 6); - return arr; - } +// @Override +// public byte[] getNodeId() { +// byte[] arr = new byte[6]; +// System.arraycopy(holder.get().nodeId, 0, arr, 0, 6); +// return arr; +// } @Override public long getClockSequence() { return holder.get().clockSequence; } - } diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/uuid/SimpleUuidFactory.java b/org.argeo.api.acr/src/org/argeo/api/acr/uuid/SimpleUuidFactory.java index 9e86b0bd2..9339704f4 100644 --- a/org.argeo.api.acr/src/org/argeo/api/acr/uuid/SimpleUuidFactory.java +++ b/org.argeo.api.acr/src/org/argeo/api/acr/uuid/SimpleUuidFactory.java @@ -28,19 +28,14 @@ import java.util.UUID; public class SimpleUuidFactory implements UuidFactory { private final static Logger logger = System.getLogger(SimpleUuidFactory.class.getName()); public final static UuidFactory DEFAULT = new SimpleUuidFactory(null, -1, null); -// private final static int MAX_CLOCKSEQUENCE = 16384; private SecureRandom secureRandom; - private final byte[] hardwareAddress; - -// private final AtomicInteger clockSequence; - - /** A start timestamp to which {@link System#nanoTime()}/100 can be added. */ -// private final long startTimeStamp; - - private final TimeUuidState macAddressTimeUuidState; - private final TimeUuidState defaultTimeUuidState; + private final TimeUuidState timeUuidState; +// private NodeId macAddressNodeId; +// private NodeId defaultNodeId; + private byte[] macAddressNodeId; + private byte[] defaultNodeId; public SimpleUuidFactory(byte[] nodeId, int offset, Clock clock) { try { @@ -56,21 +51,16 @@ public class SimpleUuidFactory implements UuidFactory { } } -// clockSequence = new AtomicInteger(secureRandom.nextInt(MAX_CLOCKSEQUENCE)); - hardwareAddress = getHardwareAddress(); - - macAddressTimeUuidState = hardwareAddress != null - ? new ConcurrentTimeUuidState(hardwareAddress, 0, secureRandom, clock) - : null; - defaultTimeUuidState = nodeId != null ? new ConcurrentTimeUuidState(nodeId, offset, secureRandom, clock) - : macAddressTimeUuidState != null ? macAddressTimeUuidState - // we use random as a last resort - : new ConcurrentTimeUuidState(null, -1, secureRandom, clock); - - // GREGORIAN_START = ZonedDateTime.of(1582, 10, 15, 0, 0, 0, 0, ZoneOffset.UTC); -// Duration duration = Duration.between(TimeUuidState.GREGORIAN_START, Instant.now()); -// long nowVm = System.nanoTime() / 100; -// startTimeStamp = (duration.getSeconds() * 10000000 + duration.getNano() / 100) - nowVm; + byte[] hardwareAddress = getHardwareAddress(); +// macAddressNodeId = hardwareAddress != null ? new NodeId(hardwareAddress, 0) : null; + macAddressNodeId = toNodeId(hardwareAddress, 0); + +// defaultNodeId = nodeId != null ? new NodeId(nodeId, offset) : macAddressNodeId; + defaultNodeId = nodeId != null ? toNodeId(nodeId, offset) : toNodeId(macAddressNodeId, 0); + if (defaultNodeId == null) + throw new IllegalStateException("No default node id specified"); + + timeUuidState = new ConcurrentTimeUuidState(secureRandom, clock); } /* @@ -103,7 +93,7 @@ public class SimpleUuidFactory implements UuidFactory { // tests // assert uuid.node() == BitSet.valueOf(node).toLongArray()[0]; - //assert uuid.node() == longFromBytes(node); + // assert uuid.node() == longFromBytes(node); assert uuid.timestamp() == timestamp; assert uuid.clockSequence() == clockSequence : "uuid.clockSequence()=" + uuid.clockSequence() + " clockSequence=" + clockSequence; @@ -114,46 +104,16 @@ public class SimpleUuidFactory implements UuidFactory { @Override public UUID timeUUIDwithMacAddress() { - if (macAddressTimeUuidState == null) + if (macAddressNodeId == null) throw new UnsupportedOperationException("No MAC address is available"); -// long timestamp = startTimeStamp + System.nanoTime() / 100; - return timeUUID(macAddressTimeUuidState.useTimestamp(), macAddressTimeUuidState.getClockSequence(), - macAddressTimeUuidState.getNodeId(), 0); + return timeUUID(timeUuidState.useTimestamp(), timeUuidState.getClockSequence(), macAddressNodeId, 0); } -// public UUID timeUUID(long timestamp, Random random) { -// byte[] node = new byte[6]; -// random.nextBytes(node); -// node[0] = (byte) (node[0] | 1); -//// long clockSequence = nextClockSequence(); -// return timeUUID(timestamp, macAddressTimeUuidState.getClockSequence(), node, 0); -// } - @Override public UUID timeUUID() { -// long timestamp = startTimeStamp + System.nanoTime() / 100; -// return timeUUID(timeUuidState.useTimestamp()); -// } -// -// public UUID timeUUID(long timestamp) { -// if (hardwareAddress == null) -// return timeUUID(timestamp, secureRandom); -// long clockSequence = nextClockSequence(); - return timeUUID(defaultTimeUuidState.useTimestamp(), defaultTimeUuidState.getClockSequence(), - defaultTimeUuidState.getNodeId(), 0); + return timeUUID(timeUuidState.useTimestamp(), timeUuidState.getClockSequence(), defaultNodeId, 0); } -// public UUID timeUUID(long timestamp, NetworkInterface nic) { -// byte[] node; -// try { -// node = nic.getHardwareAddress(); -// } catch (SocketException e) { -// throw new IllegalStateException("Cannot get hardware address", e); -// } -//// long clockSequence = nextClockSequence(); -// return timeUUID(timestamp, macAddressTimeUuidState.getClockSequence(), node, 0); -// } - public UUID timeUUID(Temporal time, long clockSequence, byte[] node) { Duration duration = Duration.between(TimeUuidState.GREGORIAN_START, time); // Number of 100 ns intervals in one second: 1000000000 / 100 = 10000000 @@ -176,16 +136,6 @@ public class SimpleUuidFactory implements UuidFactory { } } - -// private synchronized long nextClockSequence() { -// int i = clockSequence.incrementAndGet(); -// while (i < 0 || i >= MAX_CLOCKSEQUENCE) { -// clockSequence.set(secureRandom.nextInt(MAX_CLOCKSEQUENCE)); -// i = clockSequence.incrementAndGet(); -// } -// return (long) i; -// } - /* * NAME BASED (version 3 and 5) */ @@ -247,7 +197,6 @@ public class SimpleUuidFactory implements UuidFactory { @Override public UUID randomUUID() { return randomUUID(secureRandom); - // return UuidFactory.super.randomUUID(); } /* @@ -397,4 +346,35 @@ public class SimpleUuidFactory implements UuidFactory { } return new String(hexChars); } + + private byte[] toNodeId(byte[] source, int offset) { + if (source == null) + return null; + if (offset < 0 || offset + 6 > source.length) + throw new ArrayIndexOutOfBoundsException(offset); + byte[] nodeId = new byte[6]; + System.arraycopy(source, offset, nodeId, 0, 6); + return nodeId; + } + +// static class NodeId extends ThreadLocal { +// private byte[] source; +// private int offset; +// +// public NodeId(byte[] source, int offset) { +// Objects.requireNonNull(source); +// this.source = source; +// this.offset = offset; +// if (offset < 0 || offset + 6 > source.length) +// throw new ArrayIndexOutOfBoundsException(offset); +// } +// +// @Override +// protected byte[] initialValue() { +// byte[] value = new byte[6]; +// System.arraycopy(source, offset, value, 0, 6); +// return value; +// } +// +// } } diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/uuid/TimeUuidState.java b/org.argeo.api.acr/src/org/argeo/api/acr/uuid/TimeUuidState.java index d883b8d85..74e6b6980 100644 --- a/org.argeo.api.acr/src/org/argeo/api/acr/uuid/TimeUuidState.java +++ b/org.argeo.api.acr/src/org/argeo/api/acr/uuid/TimeUuidState.java @@ -15,8 +15,6 @@ public interface TimeUuidState { /** Start of the Gregorian time, used by time-based UUID (v1). */ final static Instant GREGORIAN_START = ZonedDateTime.of(1582, 10, 15, 0, 0, 0, 0, ZoneOffset.UTC).toInstant(); - byte[] getNodeId(); - long useTimestamp(); long getClockSequence(); @@ -26,18 +24,9 @@ public interface TimeUuidState { } static class Holder { - byte[] nodeId = new byte[6]; long lastTimestamp; long clockSequence; - public byte[] getNodeId() { - return nodeId; - } - - public void setNodeId(byte[] nodeId) { - this.nodeId = nodeId; - } - public long getLastTimestamp() { return lastTimestamp; }