1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.helpers;
18
19 import java.lang.reflect.Method;
20 import java.net.InetAddress;
21 import java.net.NetworkInterface;
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
31
32
33
34 public final class UUIDUtil {
35
36
37
38 public static final String UUID_SEQUENCE = "org.apache.logging.log4j.uuidSequence";
39
40 private static final String ASSIGNED_SEQUENCES = "org.apache.logging.log4j.assignedSequences";
41
42 private static AtomicInteger count = new AtomicInteger(0);
43
44 private static final long TYPE1 = 0x1000L;
45
46 private static final byte VARIANT = (byte) 0x80;
47
48 private static final int SEQUENCE_MASK = 0x3FFF;
49
50 private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L;
51
52 private static long uuidSequence = Long.getLong(UUID_SEQUENCE, 0);
53
54 private static long least;
55
56 private static final long LOW_MASK = 0xffffffffL;
57 private static final long MID_MASK = 0xffff00000000L;
58 private static final long HIGH_MASK = 0xfff000000000000L;
59 private static final int NODE_SIZE = 8;
60 private static final int SHIFT_2 = 16;
61 private static final int SHIFT_4 = 32;
62 private static final int SHIFT_6 = 48;
63 private static final int HUNDRED_NANOS_PER_MILLI = 10000;
64
65 static {
66 byte[] mac = null;
67 try {
68 InetAddress address = InetAddress.getLocalHost();
69 try {
70 NetworkInterface ni = NetworkInterface.getByInetAddress(address);
71 if (ni != null && !ni.isLoopback() && ni.isUp()) {
72 Method method = ni.getClass().getMethod("getHardwareAddress");
73 if (method != null) {
74 mac = (byte[]) method.invoke(ni);
75 }
76 }
77
78 if (mac == null) {
79 Enumeration<NetworkInterface> enumeration = NetworkInterface.getNetworkInterfaces();
80 while (enumeration.hasMoreElements() && mac == null) {
81 ni = enumeration.nextElement();
82 if (ni != null && ni.isUp() && !ni.isLoopback()) {
83 Method method = ni.getClass().getMethod("getHardwareAddress");
84 if (method != null) {
85 mac = (byte[]) method.invoke(ni);
86 }
87 }
88 }
89 }
90 } catch (Exception ex) {
91 ex.printStackTrace();
92
93 }
94 if (mac == null || mac.length == 0) {
95 mac = address.getAddress();
96 }
97 } catch (UnknownHostException e) {
98
99 }
100 Random randomGenerator = new SecureRandom();
101 if (mac == null || mac.length == 0) {
102 mac = new byte[6];
103 randomGenerator.nextBytes(mac);
104 }
105 int length = mac.length >= 6 ? 6 : mac.length;
106 int index = mac.length >= 6 ? mac.length - 6 : 0;
107 byte[] node = new byte[NODE_SIZE];
108 node[0] = VARIANT;
109 node[1] = 0;
110 for (int i = 2; i < NODE_SIZE; ++i) {
111 node[i] = 0;
112 }
113 System.arraycopy(mac, index, node, index + 2, length);
114 ByteBuffer buf = ByteBuffer.wrap(node);
115 long rand = uuidSequence;
116 Runtime runtime = Runtime.getRuntime();
117 synchronized (runtime) {
118 String assigned = System.getProperty(ASSIGNED_SEQUENCES);
119 long[] sequences;
120 if (assigned == null) {
121 sequences = new long[0];
122 } else {
123 String[] array = assigned.split(",");
124 sequences = new long[array.length];
125 int i = 0;
126 for (String value : array) {
127 sequences[i] = Long.parseLong(value);
128 ++i;
129 }
130 }
131 if (rand == 0) {
132 rand = randomGenerator.nextLong();
133 }
134 rand &= SEQUENCE_MASK;
135 boolean duplicate;
136 do {
137 duplicate = false;
138 for (long sequence : sequences) {
139 if (sequence == rand) {
140 duplicate = true;
141 }
142 }
143 if (duplicate) {
144 rand = (rand + 1) & SEQUENCE_MASK;
145 }
146 } while (duplicate);
147 assigned = assigned == null ? Long.toString(rand) : assigned + "," + Long.toString(rand);
148 System.setProperty(ASSIGNED_SEQUENCES, assigned);
149 }
150
151 least = buf.getLong() | rand << SHIFT_6;
152 }
153
154
155
156 private UUIDUtil() {
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 public static UUID getTimeBasedUUID() {
176
177 long time = ((System.currentTimeMillis() * HUNDRED_NANOS_PER_MILLI) + NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) +
178 (count.incrementAndGet() % HUNDRED_NANOS_PER_MILLI);
179 long timeLow = (time & LOW_MASK) << SHIFT_4;
180 long timeMid = (time & MID_MASK) >> SHIFT_2;
181 long timeHi = (time & HIGH_MASK) >> SHIFT_6;
182 long most = timeLow | timeMid | TYPE1 | timeHi;
183 return new UUID(most, least);
184 }
185 }
186