]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.api.uuid/src/org/argeo/api/uuid/AbstractAsyncUuidFactory.java
Improve build and local deployment
[lgpl/argeo-commons.git] / org.argeo.api.uuid / src / org / argeo / api / 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 private long currentClockSequenceRange = 0;
30
31 public AbstractAsyncUuidFactory() {
32 secureRandom = createSecureRandom();
33 timeUuidState = new ConcurrentTimeUuidState(secureRandom, null);
34 }
35 /*
36 * ABSTRACT METHODS
37 */
38
39 protected abstract SecureRandom createSecureRandom();
40
41 /*
42 * STATE
43 */
44 public void reset() {
45 if (nodeIdSupplier == null)
46 throw new IllegalStateException("No node id supplier available");
47 long nodeIdBase = nodeIdSupplier.get();
48 timeUuidState.reset(nodeIdBase, currentClockSequenceRange);
49 }
50
51 public void setNodeIdSupplier(NodeIdSupplier nodeIdSupplier) {
52 this.nodeIdSupplier = nodeIdSupplier;
53 reset();
54 }
55
56 public void setNodeIdSupplier(NodeIdSupplier nodeIdSupplier, long range) {
57 this.currentClockSequenceRange = range >= 0 ? range & 0x3F00 : range;
58 setNodeIdSupplier(nodeIdSupplier);
59 }
60
61 protected NodeIdSupplier getNodeIdSupplier() {
62 return nodeIdSupplier;
63 }
64
65 /**
66 * If positive, only clock_hi is taken from the argument (range amp; 0x3F00), if
67 * negative, the full range of possible values is used.
68 */
69 public void setCurrentClockSequenceRange(long range) {
70 this.currentClockSequenceRange = range >= 0 ? range & 0x3F00 : range;
71 reset();
72 }
73
74 /*
75 * SYNC OPERATIONS
76 */
77 protected UUID createRandomUUIDStrong() {
78 SecureRandomParameters parameters = secureRandom.getParameters();
79 if (parameters != null) {
80 if (parameters instanceof DrbgParameters.Instantiation) {
81 Capability capability = ((DrbgParameters.Instantiation) parameters).getCapability();
82 if (capability.equals(DrbgParameters.Capability.PR_AND_RESEED)
83 || capability.equals(DrbgParameters.Capability.RESEED_ONLY)) {
84 secureRandom.reseed();
85 }
86 }
87 }
88 return createRandomUUID(secureRandom);
89 }
90
91 public UUID randomUUIDWeak() {
92 return createRandomUUID(ThreadLocalRandom.current());
93 }
94
95 protected UUID createTimeUUID() {
96 if (nodeIdSupplier == null)
97 throw new IllegalStateException("No node id supplier available");
98 UUID uuid = new UUID(timeUuidState.getMostSignificantBits(), timeUuidState.getLeastSignificantBits());
99
100 assert uuid.version() == 1;
101 assert uuid.variant() == 2;
102 assert uuid.timestamp() == timeUuidState.getLastTimestamp();
103 assert uuid.clockSequence() == timeUuidState.getClockSequence();
104
105 return uuid;
106 }
107
108 /*
109 * ASYNC OPERATIONS (heavy)
110 */
111 protected CompletionStage<UUID> request(ForkJoinTask<UUID> newUuid) {
112 return CompletableFuture.supplyAsync(newUuid::invoke).minimalCompletionStage();
113 }
114
115 @Override
116 public CompletionStage<UUID> requestNameUUIDv5(UUID namespace, byte[] data) {
117 return request(futureNameUUIDv5(namespace, data));
118 }
119
120 @Override
121 public CompletionStage<UUID> requestNameUUIDv3(UUID namespace, byte[] data) {
122 return request(futureNameUUIDv3(namespace, data));
123 }
124
125 @Override
126 public CompletionStage<UUID> requestRandomUUIDStrong() {
127 return request(futureRandomUUIDStrong());
128 }
129
130 @Override
131 public CompletionStage<UUID> requestTimeUUID() {
132 return request(futureTimeUUID());
133 }
134
135 /*
136 * ASYNC OPERATIONS (light)
137 */
138 protected ForkJoinTask<UUID> submit(Callable<UUID> newUuid) {
139 return ForkJoinTask.adapt(newUuid);
140 }
141
142 @Override
143 public ForkJoinTask<UUID> futureNameUUIDv5(UUID namespace, byte[] data) {
144 return submit(() -> createNameUUIDv5(namespace, data));
145 }
146
147 @Override
148 public ForkJoinTask<UUID> futureNameUUIDv3(UUID namespace, byte[] data) {
149 return submit(() -> createNameUUIDv3(namespace, data));
150 }
151
152 @Override
153 public ForkJoinTask<UUID> futureRandomUUIDStrong() {
154 return submit(this::createRandomUUIDStrong);
155 }
156
157 @Override
158 public ForkJoinTask<UUID> futureTimeUUID() {
159 return submit(this::createTimeUUID);
160 }
161 }