/
PartlyRandom96BitsRequestIdGenerator.java
106 lines (93 loc) · 4.01 KB
/
PartlyRandom96BitsRequestIdGenerator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
* Copyright (c) 2020. https://rxmicro.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.rxmicro.rest.server.feature.request.id.generator;
import io.rxmicro.rest.server.feature.RequestIdGenerator;
import java.security.SecureRandom;
import java.util.Base64;
/**
* This request id generator returns 96 bit request id with 52 random and 44 deterministic bits.
*
* <p>
* This request id generator uses the {@link SecureRandom} instance to get random bytes, so a generation of the next request id
* can be block by operation system for example, if the entropy source is {@code /dev/random} on various Unix-like operating systems.
* Read more: <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/SecureRandom.html">
* https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/SecureRandom.html
* </a>
*
* <p>
* If a {@link DeterministicValueProvider#CURRENT_TIME_IN_MILLIS_PROVIDER} is used as
* ${@link DeterministicValueProvider} that least significant {@code 44 bits} can contains milliseconds for {@code 557.46} years.
*
* <p>
* Hex format of generated request id:
* <pre>
* RR RD RR DD RR DD RR DD RR DD RR DD
* </pre>
* where {@code R} - random 4 bits and {@code D} - deterministic 4 bits
*
* <p>
* Example of generated request ids:
* <ul>
* <li>qQF3dmlR_IjVNjxY</li>
* <li>jeH1dnBRnIjwNiFY</li>
* <li>AmG2dvVR34g_NiNY</li>
* <li>YYHFdilR5ogUNtlZ</li>
* <li>VdFrdoVRoYhVNuNZ</li>
* <li>viGVdt5RuYi5NjxZ</li>
* </ul>
*
* @author nedis
* @see SecureRandom
* @see Base64#getUrlEncoder()
* @since 0.7.3
*/
public final class PartlyRandom96BitsRequestIdGenerator implements RequestIdGenerator {
private static final byte DEFAULT_REQUEST_ID_LENGTH_IN_BYTES = 12;
private final DeterministicValueProvider deterministicValueProvider;
private final Base64.Encoder encoder;
private final SecureRandom secureRandom;
/**
* Creates an instance of {@link PartlyRandom96BitsRequestIdGenerator} with the specified deterministic value provider.
*
* @param deterministicValueProvider the specified deterministic value provider
*/
public PartlyRandom96BitsRequestIdGenerator(final DeterministicValueProvider deterministicValueProvider) {
this.deterministicValueProvider = deterministicValueProvider;
this.encoder = Base64.getUrlEncoder().withoutPadding();
this.secureRandom = new SecureRandom();
}
@Override
public String getNextId() {
final byte[] bytes = new byte[DEFAULT_REQUEST_ID_LENGTH_IN_BYTES];
secureRandom.nextBytes(bytes);
final long deterministicValue = deterministicValueProvider.getValue();
// RR RD RR DD RR DD RR DD RR DD RR DD
// 0 1 2 3 4 5 6 7 8 9 10 11
bytes[1] = (byte) ((((deterministicValue & 0x0000FF0000000000L) >>> 40) & 0x0FL) | (bytes[1] & 0xF0L));
bytes[3] = (byte) ((deterministicValue & 0x000000FF00000000L) >>> 32);
bytes[5] = (byte) ((deterministicValue & 0x00000000FF000000L) >>> 24);
bytes[7] = (byte) ((deterministicValue & 0x0000000000FF0000L) >>> 16);
bytes[9] = (byte) ((deterministicValue & 0x000000000000FF00L) >>> 8);
bytes[11] = (byte) ((deterministicValue & 0x00000000000000FFL));
return encoder.encodeToString(bytes);
}
@Override
public String toString() {
return "PartlyRandom96BitsRequestIdGenerator{" +
"deterministicValueProvider=" + deterministicValueProvider +
'}';
}
}