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 private static final Logger LOGGER = StatusLogger.getLogger();
40
41
42
43 public static final String UUID_SEQUENCE = "org.apache.logging.log4j.uuidSequence";
44
45 private static final String ASSIGNED_SEQUENCES = "org.apache.logging.log4j.assignedSequences";
46
47 private static final AtomicInteger count = new AtomicInteger(0);
48
49 private static final long TYPE1 = 0x1000L;
50
51 private static final byte VARIANT = (byte) 0x80;
52
53 private static final int SEQUENCE_MASK = 0x3FFF;
54
55 private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L;
56
57 private static final long uuidSequence = PropertiesUtil.getProperties().getLongProperty(UUID_SEQUENCE, 0);
58
59 private static final long least;
60
61 private static final long LOW_MASK = 0xffffffffL;
62 private static final long MID_MASK = 0xffff00000000L;
63 private static final long HIGH_MASK = 0xfff000000000000L;
64 private static final int NODE_SIZE = 8;
65 private static final int SHIFT_2 = 16;
66 private static final int SHIFT_4 = 32;
67 private static final int SHIFT_6 = 48;
68 private static final int HUNDRED_NANOS_PER_MILLI = 10000;
69
70 static {
71 byte[] mac = getLocalMacAddress();
72 final Random randomGenerator = new SecureRandom();
73 if (mac == null || mac.length == 0) {
74 mac = new byte[6];
75 randomGenerator.nextBytes(mac);
76 }
77 final int length = mac.length >= 6 ? 6 : mac.length;
78 final int index = mac.length >= 6 ? mac.length - 6 : 0;
79 final byte[] node = new byte[NODE_SIZE];
80 node[0] = VARIANT;
81 node[1] = 0;
82 for (int i = 2; i < NODE_SIZE; ++i) {
83 node[i] = 0;
84 }
85 System.arraycopy(mac, index, node, index + 2, length);
86 final ByteBuffer buf = ByteBuffer.wrap(node);
87 long rand = uuidSequence;
88 String assigned = PropertiesUtil.getProperties().getStringProperty(ASSIGNED_SEQUENCES);
89 long[] sequences;
90 if (assigned == null) {
91 sequences = new long[0];
92 } else {
93 final String[] array = assigned.split(Patterns.COMMA_SEPARATOR);
94 sequences = new long[array.length];
95 int i = 0;
96 for (final String value : array) {
97 sequences[i] = Long.parseLong(value);
98 ++i;
99 }
100 }
101 if (rand == 0) {
102 rand = randomGenerator.nextLong();
103 }
104 rand &= SEQUENCE_MASK;
105 boolean duplicate;
106 do {
107 duplicate = false;
108 for (final long sequence : sequences) {
109 if (sequence == rand) {
110 duplicate = true;
111 break;
112 }
113 }
114 if (duplicate) {
115 rand = (rand + 1) & SEQUENCE_MASK;
116 }
117 } while (duplicate);
118 assigned = assigned == null ? Long.toString(rand) : assigned + ',' + Long.toString(rand);
119 System.setProperty(ASSIGNED_SEQUENCES, assigned);
120
121 least = buf.getLong() | rand << SHIFT_6;
122 }
123
124
125
126 private UuidUtil() {
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
157
158
159
160
161
162
163 private static byte[] getLocalMacAddress() {
164 byte[] mac = null;
165 try {
166 final InetAddress localHost = InetAddress.getLocalHost();
167 try {
168 final NetworkInterface localInterface = NetworkInterface.getByInetAddress(localHost);
169 if (isUpAndNotLoopback(localInterface)) {
170 mac = localInterface.getHardwareAddress();
171 }
172 if (mac == null) {
173 final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
174 while (networkInterfaces.hasMoreElements() && mac == null) {
175 final NetworkInterface nic = networkInterfaces.nextElement();
176 if (isUpAndNotLoopback(nic)) {
177 mac = nic.getHardwareAddress();
178 }
179 }
180 }
181 } catch (final SocketException e) {
182 LOGGER.catching(e);
183 }
184 if (mac == null || mac.length == 0) {
185 mac = localHost.getAddress();
186 }
187 } catch (final UnknownHostException ignored) {
188 }
189 return mac;
190 }
191
192 private static boolean isUpAndNotLoopback(final NetworkInterface ni) throws SocketException {
193 return ni != null && !ni.isLoopback() && ni.isUp();
194 }
195 }
196