Reseed secure random for each random UUID.
[lgpl/argeo-commons.git] / org.argeo.api.uuid / src / org / argeo / api / uuid / AbstractAsyncUuidFactory.java
index 2cdb59f77f08b5d4ff2eeaedfe548e2107c3d51d..1948eafbd8e82de76afe00e21d4d7620b9259d83 100644 (file)
@@ -1,6 +1,9 @@
 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;
@@ -20,7 +23,9 @@ import java.util.concurrent.ThreadLocalRandom;
  */
 public abstract class AbstractAsyncUuidFactory extends AbstractUuidFactory implements AsyncUuidFactory {
        private SecureRandom secureRandom;
-       protected TimeUuidState timeUuidState;
+       protected ConcurrentTimeUuidState timeUuidState;
+
+       private NodeIdSupplier nodeIdSupplier;
 
        public AbstractAsyncUuidFactory() {
                secureRandom = newSecureRandom();
@@ -30,16 +35,37 @@ public abstract class AbstractAsyncUuidFactory extends AbstractUuidFactory imple
         * ABSTRACT METHODS
         */
 
-       protected abstract UUID newTimeUUID();
+       protected abstract SecureRandom newSecureRandom();
 
-       protected abstract UUID newTimeUUIDwithMacAddress();
+       /*
+        * STATE
+        */
+       public void reset() {
+               if (nodeIdSupplier == null)
+                       throw new IllegalStateException("No node id supplier available");
+               long nodeIdBase = nodeIdSupplier.get();
+               timeUuidState.reset(nodeIdBase);
+       }
 
-       protected abstract SecureRandom newSecureRandom();
+       public void setNodeIdSupplier(NodeIdSupplier nodeIdSupplier) {
+               this.nodeIdSupplier = nodeIdSupplier;
+               reset();
+       }
 
        /*
         * SYNC OPERATIONS
         */
        protected UUID newRandomUUIDStrong() {
+               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 newRandomUUID(secureRandom);
        }
 
@@ -47,6 +73,19 @@ public abstract class AbstractAsyncUuidFactory extends AbstractUuidFactory imple
                return newRandomUUID(ThreadLocalRandom.current());
        }
 
+       protected UUID newTimeUUID() {
+               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;
+       }
+
        /*
         * ASYNC OPERATIONS (heavy)
         */
@@ -74,11 +113,6 @@ public abstract class AbstractAsyncUuidFactory extends AbstractUuidFactory imple
                return request(futureTimeUUID());
        }
 
-       @Override
-       public CompletionStage<UUID> requestTimeUUIDwithMacAddress() {
-               return request(futureTimeUUIDwithMacAddress());
-       }
-
        /*
         * ASYNC OPERATIONS (light)
         */
@@ -105,26 +139,4 @@ public abstract class AbstractAsyncUuidFactory extends AbstractUuidFactory imple
        public ForkJoinTask<UUID> futureTimeUUID() {
                return submit(this::newTimeUUID);
        }
-
-       @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();
-//     }
-
 }