1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.util;
18
19 import java.net.InetAddress;
20 import java.net.NetworkInterface;
21 import java.net.SocketException;
22 import java.net.UnknownHostException;
23 import java.nio.ByteBuffer;
24 import java.security.SecureRandom;
25 import java.util.Enumeration;
26 import java.util.Random;
27 import java.util.UUID;
28 import java.util.concurrent.atomic.AtomicInteger;
29
30 import org.apache.logging.log4j.Logger;
31 import org.apache.logging.log4j.status.StatusLogger;
32 import org.apache.logging.log4j.util.PropertiesUtil;
33
34
35
36
37
38 public final class UuidUtil {
39
40
41
42 public static final String UUID_SEQUENCE = "org.apache.logging.log4j.uuidSequence";
43
44 private static final Logger LOGGER = StatusLogger.getLogger();
45
46 private static final String ASSIGNED_SEQUENCES = "org.apache.logging.log4j.assignedSequences";
47
48 private static final AtomicInteger COUNT = new AtomicInteger(0);
49 private static final long TYPE1 = 0x1000L;
50 private static final byte VARIANT = (byte) 0x80;
51 private static final int SEQUENCE_MASK = 0x3FFF;
52 private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L;
53 private static final long INITIAL_UUID_SEQNO = PropertiesUtil.getProperties().getLongProperty(UUID_SEQUENCE, 0);
54
55 private static final long LEAST;
56
57 private static final long LOW_MASK = 0xffffffffL;
58 private static final long MID_MASK = 0xffff00000000L;
59 private static final long HIGH_MASK = 0xfff000000000000L;
60 private static final int NODE_SIZE = 8;
61 private static final int SHIFT_2 = 16;
62 private static final int SHIFT_4 = 32;
63 private static final int SHIFT_6 = 48;
64 private static final int HUNDRED_NANOS_PER_MILLI = 10000;
65
66 static {
67 byte[] mac = NetUtils.getMacAddress();
68 final Random randomGenerator = new SecureRandom();
69 if (mac == null || mac.length == 0) {
70 mac = new byte[6];
71 randomGenerator.nextBytes(mac);
72 }
73 final int length = mac.length >= 6 ? 6 : mac.length;
74 final int index = mac.length >= 6 ? mac.length - 6 : 0;
75 final byte[] node = new byte[NODE_SIZE];
76 node[0] = VARIANT;
77 node[1] = 0;
78 for (int i = 2; i < NODE_SIZE; ++i) {
79 node[i] = 0;
80 }
81 System.arraycopy(mac, index, node, index + 2, length);
82 final ByteBuffer buf = ByteBuffer.wrap(node);
83 long rand = INITIAL_UUID_SEQNO;
84 String assigned = PropertiesUtil.getProperties().getStringProperty(ASSIGNED_SEQUENCES);
85 long[] sequences;
86 if (assigned == null) {
87 sequences = new long[0];
88 } else {
89 final String[] array = assigned.split(Patterns.COMMA_SEPARATOR);
90 sequences = new long[array.length];
91 int i = 0;
92 for (final String value : array) {
93 sequences[i] = Long.parseLong(value);
94 ++i;
95 }
96 }
97 if (rand == 0) {
98 rand = randomGenerator.nextLong();
99 }
100 rand &= SEQUENCE_MASK;
101 boolean duplicate;
102 do {
103 duplicate = false;
104 for (final long sequence : sequences) {
105 if (sequence == rand) {
106 duplicate = true;
107 break;
108 }
109 }
110 if (duplicate) {
111 rand = (rand + 1) & SEQUENCE_MASK;
112 }
113 } while (duplicate);
114 assigned = assigned == null ? Long.toString(rand) : assigned + ',' + Long.toString(rand);
115 System.setProperty(ASSIGNED_SEQUENCES, assigned);
116
117 LEAST = buf.getLong() | rand << SHIFT_6;
118 }
119
120
121
122 private UuidUtil() {
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 public static UUID getTimeBasedUuid() {
142
143 final long time = ((System.currentTimeMillis() * HUNDRED_NANOS_PER_MILLI) +
144 NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) + (COUNT.incrementAndGet() % HUNDRED_NANOS_PER_MILLI);
145 final long timeLow = (time & LOW_MASK) << SHIFT_4;
146 final long timeMid = (time & MID_MASK) >> SHIFT_2;
147 final long timeHi = (time & HIGH_MASK) >> SHIFT_6;
148 final long most = timeLow | timeMid | TYPE1 | timeHi;
149 return new UUID(most, LEAST);
150 }
151 }
152