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