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.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 import org.apache.logging.log4j.util.PropertiesUtil;
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 final 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 final long uuidSequence = PropertiesUtil.getProperties().getLongProperty(UUID_SEQUENCE, 0);
55
56 private static final 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 String assigned = PropertiesUtil.getProperties().getStringProperty(ASSIGNED_SEQUENCES);
119 long[] sequences;
120 if (assigned == null) {
121 sequences = new long[0];
122 } else {
123 final String[] array = assigned.split(Patterns.COMMA_SEPARATOR);
124 sequences = new long[array.length];
125 int i = 0;
126 for (final 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 (final long sequence : sequences) {
139 if (sequence == rand) {
140 duplicate = true;
141 break;
142 }
143 }
144 if (duplicate) {
145 rand = (rand + 1) & SEQUENCE_MASK;
146 }
147 } while (duplicate);
148 assigned = assigned == null ? Long.toString(rand) : assigned + ',' + Long.toString(rand);
149 System.setProperty(ASSIGNED_SEQUENCES, assigned);
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 final long time = ((System.currentTimeMillis() * HUNDRED_NANOS_PER_MILLI) +
178 NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) + (count.incrementAndGet() % HUNDRED_NANOS_PER_MILLI);
179 final long timeLow = (time & LOW_MASK) << SHIFT_4;
180 final long timeMid = (time & MID_MASK) >> SHIFT_2;
181 final long timeHi = (time & HIGH_MASK) >> SHIFT_6;
182 final long most = timeLow | timeMid | TYPE1 | timeHi;
183 return new UUID(most, least);
184 }
185 }
186