]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.api.uuid/src/org/argeo/api/uuid/AbstractUuidFactory.java
Improve build and local deployment
[lgpl/argeo-commons.git] / org.argeo.api.uuid / src / org / argeo / api / uuid / AbstractUuidFactory.java
1 package org.argeo.api.uuid;
2
3 import java.security.MessageDigest;
4 import java.security.NoSuchAlgorithmException;
5 import java.time.Duration;
6 import java.time.temporal.Temporal;
7 import java.util.BitSet;
8 import java.util.Objects;
9 import java.util.Random;
10 import java.util.UUID;
11
12 /**
13 * Implementation of the basic RFC4122 algorithms.
14 *
15 * @see "https://datatracker.ietf.org/doc/html/rfc4122"
16 */
17 public abstract class AbstractUuidFactory implements UuidFactory {
18
19 /*
20 * TIME-BASED (version 1)
21 */
22
23 private final static long MOST_SIG_VERSION1 = (1l << 12);
24 private final static long LEAST_SIG_RFC4122_VARIANT = (1l << 63);
25
26 @Deprecated
27 protected UUID createTimeUUID(long timestamp, long clockSequence, byte[] node, int offset) {
28 Objects.requireNonNull(node, "Node array cannot be null");
29 if (node.length < offset + 6)
30 throw new IllegalArgumentException("Node array must be at least 6 bytes long");
31
32 long mostSig = MOST_SIG_VERSION1 // base for version 1 UUID
33 | ((timestamp & 0xFFFFFFFFL) << 32) // time_low
34 | (((timestamp >> 32) & 0xFFFFL) << 16) // time_mid
35 | ((timestamp >> 48) & 0x0FFFL);// time_hi_and_version
36
37 long leastSig = LEAST_SIG_RFC4122_VARIANT // base for Leach–Salz UUID
38 | (((clockSequence & 0x3F00) >> 8) << 56) // clk_seq_hi_res
39 | ((clockSequence & 0xFF) << 48) // clk_seq_low
40 | (node[offset] & 0xFFL) //
41 | ((node[offset + 1] & 0xFFL) << 8) //
42 | ((node[offset + 2] & 0xFFL) << 16) //
43 | ((node[offset + 3] & 0xFFL) << 24) //
44 | ((node[offset + 4] & 0xFFL) << 32) //
45 | ((node[offset + 5] & 0xFFL) << 40); //
46 UUID uuid = new UUID(mostSig, leastSig);
47
48 // tests
49 assert uuid.version() == 1;
50 assert uuid.variant() == 2;
51 assert uuid.node() == BitSet.valueOf(node).toLongArray()[0];
52 assert uuid.timestamp() == timestamp;
53 assert uuid.clockSequence() == clockSequence;
54 return uuid;
55 }
56
57 @Deprecated
58 protected UUID timeUUID(Temporal time, long clockSequence, byte[] node, int offset) {
59 // TODO add checks
60 Duration duration = Duration.between(TimeUuid.TIMESTAMP_ZERO, time);
61 // Number of 100 ns intervals in one second: 1000000000 / 100 = 10000000
62 long timestamp = duration.getSeconds() * 10000000 + duration.getNano() / 100;
63 return createTimeUUID(timestamp, clockSequence, node, offset);
64 }
65
66 /*
67 * NAME BASED (version 3 and 5)
68 */
69 protected UUID createNameUUIDv5(UUID namespace, byte[] name) {
70 return createNameUUIDv5Static(namespace, name);
71 }
72
73 static UUID createNameUUIDv5Static(UUID namespace, byte[] name) {
74 Objects.requireNonNull(namespace, "Namespace cannot be null");
75 Objects.requireNonNull(name, "Name cannot be null");
76
77 byte[] bytes = sha1(UuidBinaryUtils.toBytes(namespace), name);
78 bytes[6] &= 0x0f;
79 bytes[6] |= 0x50;// v5
80 bytes[8] &= 0x3f;
81 bytes[8] |= 0x80;// variant 1
82 UUID result = UuidBinaryUtils.fromBytes(bytes, 0);
83 return result;
84 }
85
86 protected UUID createNameUUIDv3(UUID namespace, byte[] name) {
87 return createNameUUIDv3Static(namespace, name);
88 }
89
90 static UUID createNameUUIDv3Static(UUID namespace, byte[] name) {
91 Objects.requireNonNull(namespace, "Namespace cannot be null");
92 Objects.requireNonNull(name, "Name cannot be null");
93
94 byte[] arr = new byte[name.length + 16];
95 UuidBinaryUtils.copyBytes(namespace, arr, 0);
96 System.arraycopy(name, 0, arr, 16, name.length);
97 return UUID.nameUUIDFromBytes(arr);
98 }
99
100 /*
101 * RANDOM v4
102 */
103 protected UUID createRandomUUID(Random random) {
104 byte[] arr = new byte[16];
105 random.nextBytes(arr);
106 arr[6] &= 0x0f;
107 arr[6] |= 0x40;// v4
108 arr[8] &= 0x3f;
109 arr[8] |= 0x80;// variant 1
110 return UuidBinaryUtils.fromBytes(arr);
111 }
112
113 /*
114 * DIGEST UTILITIES
115 */
116
117 private final static String MD5 = "MD5";
118 private final static String SHA1 = "SHA1";
119
120 protected static byte[] sha1(byte[]... bytes) {
121 MessageDigest digest = getSha1Digest();
122 for (byte[] arr : bytes)
123 digest.update(arr);
124 byte[] checksum = digest.digest();
125 return checksum;
126 }
127
128 protected static byte[] md5(byte[]... bytes) {
129 MessageDigest digest = getMd5Digest();
130 for (byte[] arr : bytes)
131 digest.update(arr);
132 byte[] checksum = digest.digest();
133 return checksum;
134 }
135
136 protected static MessageDigest getSha1Digest() {
137 return getDigest(SHA1);
138 }
139
140 protected static MessageDigest getMd5Digest() {
141 return getDigest(MD5);
142 }
143
144 private static MessageDigest getDigest(String name) {
145 try {
146 return MessageDigest.getInstance(name);
147 } catch (NoSuchAlgorithmException e) {
148 throw new UnsupportedOperationException(name + " digest is not avalaible", e);
149 }
150 }
151
152 }