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
;
58 protected UUID
newRandomUUIDStrong() {
59 SecureRandomParameters parameters
= secureRandom
.getParameters();
60 if (parameters
!= null) {
61 if (parameters
instanceof DrbgParameters
.Instantiation
) {
62 Capability capability
= ((DrbgParameters
.Instantiation
) parameters
).getCapability();
63 if (capability
.equals(DrbgParameters
.Capability
.PR_AND_RESEED
)
64 || capability
.equals(DrbgParameters
.Capability
.RESEED_ONLY
)) {
65 secureRandom
.reseed();
69 return newRandomUUID(secureRandom
);
72 public UUID
randomUUIDWeak() {
73 return newRandomUUID(ThreadLocalRandom
.current());
76 protected UUID
newTimeUUID() {
77 if (nodeIdSupplier
== null)
78 throw new IllegalStateException("No node id supplier available");
79 UUID uuid
= new UUID(timeUuidState
.getMostSignificantBits(), timeUuidState
.getLeastSignificantBits());
81 assert uuid
.version() == 1;
82 assert uuid
.variant() == 2;
83 assert uuid
.timestamp() == timeUuidState
.getLastTimestamp();
84 assert uuid
.clockSequence() == timeUuidState
.getClockSequence();
90 * ASYNC OPERATIONS (heavy)
92 protected CompletionStage
<UUID
> request(ForkJoinTask
<UUID
> newUuid
) {
93 return CompletableFuture
.supplyAsync(newUuid
::invoke
).minimalCompletionStage();
97 public CompletionStage
<UUID
> requestNameUUIDv5(UUID namespace
, byte[] data
) {
98 return request(futureNameUUIDv5(namespace
, data
));
102 public CompletionStage
<UUID
> requestNameUUIDv3(UUID namespace
, byte[] data
) {
103 return request(futureNameUUIDv3(namespace
, data
));
107 public CompletionStage
<UUID
> requestRandomUUIDStrong() {
108 return request(futureRandomUUIDStrong());
112 public CompletionStage
<UUID
> requestTimeUUID() {
113 return request(futureTimeUUID());
117 * ASYNC OPERATIONS (light)
119 protected ForkJoinTask
<UUID
> submit(Callable
<UUID
> newUuid
) {
120 return ForkJoinTask
.adapt(newUuid
);
124 public ForkJoinTask
<UUID
> futureNameUUIDv5(UUID namespace
, byte[] data
) {
125 return submit(() -> newNameUUIDv5(namespace
, data
));
129 public ForkJoinTask
<UUID
> futureNameUUIDv3(UUID namespace
, byte[] data
) {
130 return submit(() -> newNameUUIDv3(namespace
, data
));
134 public ForkJoinTask
<UUID
> futureRandomUUIDStrong() {
135 return submit(this::newRandomUUIDStrong
);
139 public ForkJoinTask
<UUID
> futureTimeUUID() {
140 return submit(this::newTimeUUID
);