package org.argeo.api.uuid;
-import static java.lang.System.Logger.Level.DEBUG;
-import static java.lang.System.Logger.Level.INFO;
-import static java.lang.System.Logger.Level.WARNING;
-
-import java.lang.System.Logger;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
import java.security.DrbgParameters;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.util.BitSet;
-import java.util.Enumeration;
import java.util.Objects;
import java.util.UUID;
* A configurable implementation of an {@link AsyncUuidFactory}, which can be
* used as a base class for more optimised implementations.
*
- * @see https://datatracker.ietf.org/doc/html/rfc4122
+ * @see "https://datatracker.ietf.org/doc/html/rfc4122"
*/
-public class ConcurrentUuidFactory extends AbstractAsyncUuidFactory {
- private final static Logger logger = System.getLogger(ConcurrentUuidFactory.class.getName());
+public class ConcurrentUuidFactory extends AbstractAsyncUuidFactory implements TypedUuidFactory {
+// private final static Logger logger = System.getLogger(ConcurrentUuidFactory.class.getName());
+
+ public ConcurrentUuidFactory(long initialClockRange, byte[] nodeId) {
+ this(initialClockRange, nodeId, 0);
+ }
- private Long nodeIdBase;
+ /** With a random node id. */
+ public ConcurrentUuidFactory(long initialClockRange) {
+ this(initialClockRange, NodeIdSupplier.randomNodeId());
+ }
- public ConcurrentUuidFactory(byte[] nodeId, int offset) {
+ public ConcurrentUuidFactory(long initialClockRange, byte[] nodeId, int offset) {
Objects.requireNonNull(nodeId);
if (offset + 6 > nodeId.length)
throw new IllegalArgumentException("Offset too big: " + offset);
byte[] defaultNodeId = toNodeIdBytes(nodeId, offset);
- nodeIdBase = NodeIdSupplier.toNodeIdBase(defaultNodeId);
- setNodeIdSupplier(() -> nodeIdBase);
- assert newTimeUUID().node() == BitSet.valueOf(defaultNodeId).toLongArray()[0];
+ long nodeIdBase = NodeIdSupplier.toNodeIdBase(defaultNodeId);
+ setNodeIdSupplier(() -> nodeIdBase, initialClockRange);
}
+ /**
+ * Empty constructor for use with component life cycle. A {@link NodeIdSupplier}
+ * must be set externally, otherwise time based UUID won't work.
+ */
public ConcurrentUuidFactory() {
- byte[] defaultNodeId = getIpBytes();
- nodeIdBase = NodeIdSupplier.toNodeIdBase(defaultNodeId);
- setNodeIdSupplier(() -> nodeIdBase);
- assert newTimeUUID().node() == BitSet.valueOf(defaultNodeId).toLongArray()[0];
+ super();
}
+// public ConcurrentUuidFactory() {
+// byte[] defaultNodeId = getIpBytes();
+// nodeIdBase = NodeIdSupplier.toNodeIdBase(defaultNodeId);
+// setNodeIdSupplier(() -> nodeIdBase);
+// assert newTimeUUID().node() == BitSet.valueOf(defaultNodeId).toLongArray()[0];
+// }
+
/*
* DEFAULT
*/
}
@Override
- protected SecureRandom newSecureRandom() {
+ protected SecureRandom createSecureRandom() {
SecureRandom secureRandom;
try {
secureRandom = SecureRandom.getInstance("DRBG",
DrbgParameters.instantiation(256, DrbgParameters.Capability.PR_AND_RESEED, "UUID".getBytes()));
} catch (NoSuchAlgorithmException e) {
try {
- logger.log(DEBUG, "DRBG secure random not found, using strong");
+// logger.log(DEBUG, "DRBG secure random not found, using strong");
secureRandom = SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e1) {
- logger.log(WARNING, "No strong secure random was found, using default");
+// logger.log(WARNING, "No strong secure random was found, using default");
secureRandom = new SecureRandom();
}
+ } catch (java.lang.NoClassDefFoundError e) {// Android
+ secureRandom = new SecureRandom();
}
return secureRandom;
}
- /** Returns an SHA1 digest of one of the IP addresses. */
- protected byte[] getIpBytes() {
- Enumeration<NetworkInterface> netInterfaces = null;
- try {
- netInterfaces = NetworkInterface.getNetworkInterfaces();
- } catch (SocketException e) {
- throw new IllegalStateException(e);
- }
- if (netInterfaces == null)
- throw new IllegalStateException("No interfaces");
-
- InetAddress selectedIpv6 = null;
- InetAddress selectedIpv4 = null;
- netInterfaces: while (netInterfaces.hasMoreElements()) {
- NetworkInterface netInterface = netInterfaces.nextElement();
- byte[] hardwareAddress = null;
- try {
- hardwareAddress = netInterface.getHardwareAddress();
- if (hardwareAddress != null) {
- // first IPv6
- addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
- InetAddress ip = addr.getAddress();
- if (ip instanceof Inet6Address) {
- Inet6Address ipv6 = (Inet6Address) ip;
- if (ipv6.isAnyLocalAddress() || ipv6.isLinkLocalAddress() || ipv6.isLoopbackAddress())
- continue addr;
- selectedIpv6 = ipv6;
- break netInterfaces;
- }
-
- }
- // then IPv4
- addr: for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
- InetAddress ip = addr.getAddress();
- if (ip instanceof Inet4Address) {
- Inet4Address ipv4 = (Inet4Address) ip;
- if (ipv4.isAnyLocalAddress() || ipv4.isLinkLocalAddress() || ipv4.isLoopbackAddress())
- continue addr;
- selectedIpv4 = ipv4;
- }
-
- }
- }
- } catch (SocketException e) {
- throw new IllegalStateException(e);
- }
- }
- InetAddress selectedIp = selectedIpv6 != null ? selectedIpv6 : selectedIpv4;
- if (selectedIp == null)
- throw new IllegalStateException("No IP address found");
- byte[] digest = sha1(selectedIp.getAddress());
- logger.log(INFO, "Use IP " + selectedIp + " hashed as " + toHexString(digest) + " as node id");
- byte[] nodeId = toNodeIdBytes(digest, 0);
- // marks that this is not based on MAC address
- forceToNoMacAddress(nodeId, 0);
- return nodeId;
- }
}
\ No newline at end of file