]> git.argeo.org Git - lgpl/argeo-commons.git/blob - uuid/AbstractAsyncUuidFactory.java
Prepare next development cycle
[lgpl/argeo-commons.git] / uuid / AbstractAsyncUuidFactory.java
1 package org.argeo.api.uuid;
2
3 import java.security.DrbgParameters;
4 import java.security.DrbgParameters.Capability;
5 import java.security.SecureRandom;
6 import java.security.SecureRandomParameters;
7 import java.util.UUID;
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;
14
15 /**
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
22 * generation method.
23 */
24 public abstract class AbstractAsyncUuidFactory extends AbstractUuidFactory implements AsyncUuidFactory {
25 private SecureRandom secureRandom;
26 protected ConcurrentTimeUuidState timeUuidState;
27
28 private NodeIdSupplier nodeIdSupplier;
29
30 public AbstractAsyncUuidFactory() {
31 secureRandom = newSecureRandom();
32 timeUuidState = new ConcurrentTimeUuidState(secureRandom, null);
33 }
34 /*
35 * ABSTRACT METHODS
36 */
37
38 protected abstract SecureRandom newSecureRandom();
39
40 /*
41 * STATE
42 */
43 public void reset() {
44 if (nodeIdSupplier == null)
45 throw new IllegalStateException("No node id supplier available");
46 long nodeIdBase = nodeIdSupplier.get();
47 timeUuidState.reset(nodeIdBase);
48 }
49
50 public void setNodeIdSupplier(NodeIdSupplier nodeIdSupplier) {
51 this.nodeIdSupplier = nodeIdSupplier;
52 reset();
53 }
54
55 protected NodeIdSupplier getNodeIdSupplier() {
56 return nodeIdSupplier;
57 }
58
59 /*
60 * SYNC OPERATIONS
61 */
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();
70 }
71 }
72 }
73 return newRandomUUID(secureRandom);
74 }
75
76 public UUID randomUUIDWeak() {
77 return newRandomUUID(ThreadLocalRandom.current());
78 }
79
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());
84
85 assert uuid.version() == 1;
86 assert uuid.variant() == 2;
87 assert uuid.timestamp() == timeUuidState.getLastTimestamp();
88 assert uuid.clockSequence() == timeUuidState.getClockSequence();
89
90 return uuid;
91 }
92
93 /*
94 * ASYNC OPERATIONS (heavy)
95 */
96 protected CompletionStage<UUID> request(ForkJoinTask<UUID> newUuid) {
97 return CompletableFuture.supplyAsync(newUuid::invoke).minimalCompletionStage();
98 }
99
100 @Override
101 public CompletionStage<UUID> requestNameUUIDv5(UUID namespace, byte[] data) {
102 return request(futureNameUUIDv5(namespace, data));
103 }
104
105 @Override
106 public CompletionStage<UUID> requestNameUUIDv3(UUID namespace, byte[] data) {
107 return request(futureNameUUIDv3(namespace, data));
108 }
109
110 @Override
111 public CompletionStage<UUID> requestRandomUUIDStrong() {
112 return request(futureRandomUUIDStrong());
113 }
114
115 @Override
116 public CompletionStage<UUID> requestTimeUUID() {
117 return request(futureTimeUUID());
118 }
119
120 /*
121 * ASYNC OPERATIONS (light)
122 */
123 protected ForkJoinTask<UUID> submit(Callable<UUID> newUuid) {
124 return ForkJoinTask.adapt(newUuid);
125 }
126
127 @Override
128 public ForkJoinTask<UUID> futureNameUUIDv5(UUID namespace, byte[] data) {
129 return submit(() -> newNameUUIDv5(namespace, data));
130 }
131
132 @Override
133 public ForkJoinTask<UUID> futureNameUUIDv3(UUID namespace, byte[] data) {
134 return submit(() -> newNameUUIDv3(namespace, data));
135 }
136
137 @Override
138 public ForkJoinTask<UUID> futureRandomUUIDStrong() {
139 return submit(this::newRandomUUIDStrong);
140 }
141
142 @Override
143 public ForkJoinTask<UUID> futureTimeUUID() {
144 return submit(this::newTimeUUID);
145 }
146 }