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 LOW_MASK = 0xffffffffL;
56 private static final long MID_MASK = 0xffff00000000L;
57 private static final long HIGH_MASK = 0xfff000000000000L;
58 private static final int NODE_SIZE = 8;
59 private static final int SHIFT_2 = 16;
60 private static final int SHIFT_4 = 32;
61 private static final int SHIFT_6 = 48;
62 private static final int HUNDRED_NANOS_PER_MILLI = 10000;
63
64 private static final long LEAST = initialize(NetUtils.getMacAddress());
65
66
67 private UuidUtil() {
68 }
69
70
71
72
73
74
75
76 static long initialize(byte[] mac) {
77 final Random randomGenerator = new SecureRandom();
78 if (mac == null || mac.length == 0) {
79 mac = new byte[6];
80 randomGenerator.nextBytes(mac);
81 }
82 final int length = mac.length >= 6 ? 6 : mac.length;
83 final int index = mac.length >= 6 ? mac.length - 6 : 0;
84 final byte[] node = new byte[NODE_SIZE];
85 node[0] = VARIANT;
86 node[1] = 0;
87 for (int i = 2; i < NODE_SIZE; ++i) {
88 node[i] = 0;
89 }
90 System.arraycopy(mac, index, node, 2, length);
91 final ByteBuffer buf = ByteBuffer.wrap(node);
92 long rand = INITIAL_UUID_SEQNO;
93 String assigned = PropertiesUtil.getProperties().getStringProperty(ASSIGNED_SEQUENCES);
94 long[] sequences;
95 if (assigned == null) {
96 sequences = new long[0];
97 } else {
98 final String[] array = assigned.split(Patterns.COMMA_SEPARATOR);
99 sequences = new long[array.length];
100 int i = 0;
101 for (final String value : array) {
102 sequences[i] = Long.parseLong(value);
103 ++i;
104 }
105 }
106 if (rand == 0) {
107 rand = randomGenerator.nextLong();
108 }
109 rand &= SEQUENCE_MASK;
110 boolean duplicate;
111 do {
112 duplicate = false;
113 for (final long sequence : sequences) {
114 if (sequence == rand) {
115 duplicate = true;
116 break;
117 }
118 }
119 if (duplicate) {
120 rand = (rand + 1) & SEQUENCE_MASK;
121 }
122 } while (duplicate);
123 assigned = assigned == null ? Long.toString(rand) : assigned + ',' + Long.toString(rand);
124 System.setProperty(ASSIGNED_SEQUENCES, assigned);
125
126 return buf.getLong() | rand << SHIFT_6;
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 public static UUID getTimeBasedUuid() {
146
147 final long time = ((System.currentTimeMillis() * HUNDRED_NANOS_PER_MILLI) +
148 NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) + (COUNT.incrementAndGet() % HUNDRED_NANOS_PER_MILLI);
149 final long timeLow = (time & LOW_MASK) << SHIFT_4;
150 final long timeMid = (time & MID_MASK) >> SHIFT_2;
151 final long timeHi = (time & HIGH_MASK) >> SHIFT_6;
152 final long most = timeLow | timeMid | TYPE1 | timeHi;
153 return new UUID(most, LEAST);
154 }
155 }
156