package org.argeo.api.uuid;
+import java.security.DrbgParameters;
+import java.security.DrbgParameters.Capability;
import java.security.SecureRandom;
+import java.security.SecureRandomParameters;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
*/
public abstract class AbstractAsyncUuidFactory extends AbstractUuidFactory implements AsyncUuidFactory {
private SecureRandom secureRandom;
- protected TimeUuidState timeUuidState;
+ protected ConcurrentTimeUuidState timeUuidState;
+
+ private NodeIdSupplier nodeIdSupplier;
+ private long currentClockSequenceRange = 0;
public AbstractAsyncUuidFactory() {
- secureRandom = newSecureRandom();
+ secureRandom = createSecureRandom();
timeUuidState = new ConcurrentTimeUuidState(secureRandom, null);
}
/*
* ABSTRACT METHODS
*/
- protected abstract UUID newTimeUUID();
+ protected abstract SecureRandom createSecureRandom();
+
+ /*
+ * STATE
+ */
+ public void reset() {
+ if (nodeIdSupplier == null)
+ throw new IllegalStateException("No node id supplier available");
+ long nodeIdBase = nodeIdSupplier.get();
+ timeUuidState.reset(nodeIdBase, currentClockSequenceRange);
+ }
- protected abstract UUID newTimeUUIDwithMacAddress();
+ public void setNodeIdSupplier(NodeIdSupplier nodeIdSupplier) {
+ this.nodeIdSupplier = nodeIdSupplier;
+ reset();
+ }
- protected abstract SecureRandom newSecureRandom();
+ public void setNodeIdSupplier(NodeIdSupplier nodeIdSupplier, long range) {
+ this.currentClockSequenceRange = range >= 0 ? range & 0x3F00 : range;
+ setNodeIdSupplier(nodeIdSupplier);
+ }
+
+ protected NodeIdSupplier getNodeIdSupplier() {
+ return nodeIdSupplier;
+ }
+
+ /**
+ * If positive, only clock_hi is taken from the argument (range amp; 0x3F00), if
+ * negative, the full range of possible values is used.
+ */
+ public void setCurrentClockSequenceRange(long range) {
+ this.currentClockSequenceRange = range >= 0 ? range & 0x3F00 : range;
+ reset();
+ }
/*
* SYNC OPERATIONS
*/
- protected UUID newRandomUUIDStrong() {
- return newRandomUUID(secureRandom);
+ protected UUID createRandomUUIDStrong() {
+ SecureRandomParameters parameters = secureRandom.getParameters();
+ if (parameters != null) {
+ if (parameters instanceof DrbgParameters.Instantiation) {
+ Capability capability = ((DrbgParameters.Instantiation) parameters).getCapability();
+ if (capability.equals(DrbgParameters.Capability.PR_AND_RESEED)
+ || capability.equals(DrbgParameters.Capability.RESEED_ONLY)) {
+ secureRandom.reseed();
+ }
+ }
+ }
+ return createRandomUUID(secureRandom);
}
public UUID randomUUIDWeak() {
- return newRandomUUID(ThreadLocalRandom.current());
+ return createRandomUUID(ThreadLocalRandom.current());
+ }
+
+ protected UUID createTimeUUID() {
+ if (nodeIdSupplier == null)
+ throw new IllegalStateException("No node id supplier available");
+ UUID uuid = new UUID(timeUuidState.getMostSignificantBits(), timeUuidState.getLeastSignificantBits());
+
+ assert uuid.version() == 1;
+ assert uuid.variant() == 2;
+ assert uuid.timestamp() == timeUuidState.getLastTimestamp();
+ assert uuid.clockSequence() == timeUuidState.getClockSequence();
+
+ return uuid;
}
/*
return request(futureTimeUUID());
}
- @Override
- public CompletionStage<UUID> requestTimeUUIDwithMacAddress() {
- return request(futureTimeUUIDwithMacAddress());
- }
-
/*
* ASYNC OPERATIONS (light)
*/
@Override
public ForkJoinTask<UUID> futureNameUUIDv5(UUID namespace, byte[] data) {
- return submit(() -> newNameUUIDv5(namespace, data));
+ return submit(() -> createNameUUIDv5(namespace, data));
}
@Override
public ForkJoinTask<UUID> futureNameUUIDv3(UUID namespace, byte[] data) {
- return submit(() -> newNameUUIDv3(namespace, data));
+ return submit(() -> createNameUUIDv3(namespace, data));
}
@Override
public ForkJoinTask<UUID> futureRandomUUIDStrong() {
- return submit(this::newRandomUUIDStrong);
+ return submit(this::createRandomUUIDStrong);
}
@Override
public ForkJoinTask<UUID> futureTimeUUID() {
- return submit(this::newTimeUUID);
+ return submit(this::createTimeUUID);
}
-
- @Override
- public ForkJoinTask<UUID> futureTimeUUIDwithMacAddress() {
- return submit(this::newTimeUUIDwithMacAddress);
- }
-
-// @Override
-// public UUID timeUUID() {
-// if (ConcurrentTimeUuidState.isTimeUuidThread.get())
-// return newTimeUUID();
-// else
-// return futureTimeUUID().join();
-// }
-//
-// @Override
-// public UUID timeUUIDwithMacAddress() {
-// if (ConcurrentTimeUuidState.isTimeUuidThread.get())
-// return newTimeUUIDwithMacAddress();
-// else
-// return futureTimeUUIDwithMacAddress().join();
-// }
-
}