1 package org
.argeo
.api
.uuid
;
3 import java
.security
.DrbgParameters
;
4 import java
.security
.DrbgParameters
.Capability
;
5 import java
.security
.SecureRandom
;
6 import java
.security
.SecureRandomParameters
;
8 import java
.util
.concurrent
.Callable
;
9 import java
.util
.concurrent
.CompletableFuture
;
10 import java
.util
.concurrent
.CompletionStage
;
11 import java
.util
.concurrent
.ForkJoinPool
;
12 import java
.util
.concurrent
.ForkJoinTask
;
13 import java
.util
.concurrent
.ThreadLocalRandom
;
16 * Execute {@link UUID} creations in {@link ForkJoinPool#commonPool()}. The goal
17 * is to provide good performance while staying within the parallelism defined
18 * for the system, so as to overwhelm it if many UUIDs are requested.
19 * Additionally, with regard to time based UUIDs, since we use
20 * {@link ConcurrentTimeUuidState}, which maintains one "clock sequence" per
21 * thread, we want to limit the number of threads accessing the actual
24 public abstract class AbstractAsyncUuidFactory
extends AbstractUuidFactory
implements AsyncUuidFactory
{
25 private SecureRandom secureRandom
;
26 protected ConcurrentTimeUuidState timeUuidState
;
28 private NodeIdSupplier nodeIdSupplier
;
30 public AbstractAsyncUuidFactory() {
31 secureRandom
= newSecureRandom();
32 timeUuidState
= new ConcurrentTimeUuidState(secureRandom
, null);
38 protected abstract SecureRandom
newSecureRandom();
44 if (nodeIdSupplier
== null)
45 throw new IllegalStateException("No node id supplier available");
46 long nodeIdBase
= nodeIdSupplier
.get();
47 timeUuidState
.reset(nodeIdBase
);
50 public void setNodeIdSupplier(NodeIdSupplier nodeIdSupplier
) {
51 this.nodeIdSupplier
= nodeIdSupplier
;
55 protected NodeIdSupplier
getNodeIdSupplier() {
56 return nodeIdSupplier
;
62 protected UUID
newRandomUUIDStrong() {
63 SecureRandomParameters parameters
= secureRandom
.getParameters();
64 if (parameters
!= null) {
65 if (parameters
instanceof DrbgParameters
.Instantiation
) {
66 Capability capability
= ((DrbgParameters
.Instantiation
) parameters
).getCapability();
67 if (capability
.equals(DrbgParameters
.Capability
.PR_AND_RESEED
)
68 || capability
.equals(DrbgParameters
.Capability
.RESEED_ONLY
)) {
69 secureRandom
.reseed();
73 return newRandomUUID(secureRandom
);
76 public UUID
randomUUIDWeak() {
77 return newRandomUUID(ThreadLocalRandom
.current());
80 protected UUID
newTimeUUID() {
81 if (nodeIdSupplier
== null)
82 throw new IllegalStateException("No node id supplier available");
83 UUID uuid
= new UUID(timeUuidState
.getMostSignificantBits(), timeUuidState
.getLeastSignificantBits());
85 assert uuid
.version() == 1;
86 assert uuid
.variant() == 2;
87 assert uuid
.timestamp() == timeUuidState
.getLastTimestamp();
88 assert uuid
.clockSequence() == timeUuidState
.getClockSequence();
94 * ASYNC OPERATIONS (heavy)
96 protected CompletionStage
<UUID
> request(ForkJoinTask
<UUID
> newUuid
) {
97 return CompletableFuture
.supplyAsync(newUuid
::invoke
).minimalCompletionStage();
101 public CompletionStage
<UUID
> requestNameUUIDv5(UUID namespace
, byte[] data
) {
102 return request(futureNameUUIDv5(namespace
, data
));
106 public CompletionStage
<UUID
> requestNameUUIDv3(UUID namespace
, byte[] data
) {
107 return request(futureNameUUIDv3(namespace
, data
));
111 public CompletionStage
<UUID
> requestRandomUUIDStrong() {
112 return request(futureRandomUUIDStrong());
116 public CompletionStage
<UUID
> requestTimeUUID() {
117 return request(futureTimeUUID());
121 * ASYNC OPERATIONS (light)
123 protected ForkJoinTask
<UUID
> submit(Callable
<UUID
> newUuid
) {
124 return ForkJoinTask
.adapt(newUuid
);
128 public ForkJoinTask
<UUID
> futureNameUUIDv5(UUID namespace
, byte[] data
) {
129 return submit(() -> newNameUUIDv5(namespace
, data
));
133 public ForkJoinTask
<UUID
> futureNameUUIDv3(UUID namespace
, byte[] data
) {
134 return submit(() -> newNameUUIDv3(namespace
, data
));
138 public ForkJoinTask
<UUID
> futureRandomUUIDStrong() {
139 return submit(this::newRandomUUIDStrong
);
143 public ForkJoinTask
<UUID
> futureTimeUUID() {
144 return submit(this::newTimeUUID
);