001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.helpers; 018 019 import org.apache.logging.log4j.util.PropertiesUtil; 020 021 import java.lang.reflect.Method; 022 import java.net.InetAddress; 023 import java.net.NetworkInterface; 024 import java.net.UnknownHostException; 025 import java.nio.ByteBuffer; 026 import java.security.SecureRandom; 027 import java.util.Enumeration; 028 import java.util.Random; 029 import java.util.UUID; 030 import java.util.concurrent.atomic.AtomicInteger; 031 032 /** 033 * Generates a unique id. The generated UUID will be unique for approximately 8,925 years so long as 034 * less than 4095 ids are generated per millisecond on the same device (as identified by its MAC adddress). 035 */ 036 public final class UUIDUtil { 037 /** 038 * System property that may be used to seed the uuid generation with an integer value. 039 */ 040 public static final String UUID_SEQUENCE = "org.apache.logging.log4j.uuidSequence"; 041 042 private static final String ASSIGNED_SEQUENCES = "org.apache.logging.log4j.assignedSequences"; 043 044 private static AtomicInteger count = new AtomicInteger(0); 045 046 private static final long TYPE1 = 0x1000L; 047 048 private static final byte VARIANT = (byte) 0x80; 049 050 private static final int SEQUENCE_MASK = 0x3FFF; 051 052 private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L; 053 054 private static long uuidSequence = PropertiesUtil.getProperties().getLongProperty(UUID_SEQUENCE, 0); 055 056 private static long least; 057 058 private static final long LOW_MASK = 0xffffffffL; 059 private static final long MID_MASK = 0xffff00000000L; 060 private static final long HIGH_MASK = 0xfff000000000000L; 061 private static final int NODE_SIZE = 8; 062 private static final int SHIFT_2 = 16; 063 private static final int SHIFT_4 = 32; 064 private static final int SHIFT_6 = 48; 065 private static final int HUNDRED_NANOS_PER_MILLI = 10000; 066 067 static { 068 byte[] mac = null; 069 try { 070 final InetAddress address = InetAddress.getLocalHost(); 071 try { 072 NetworkInterface ni = NetworkInterface.getByInetAddress(address); 073 if (ni != null && !ni.isLoopback() && ni.isUp()) { 074 final Method method = ni.getClass().getMethod("getHardwareAddress"); 075 if (method != null) { 076 mac = (byte[]) method.invoke(ni); 077 } 078 } 079 080 if (mac == null) { 081 final Enumeration<NetworkInterface> enumeration = NetworkInterface.getNetworkInterfaces(); 082 while (enumeration.hasMoreElements() && mac == null) { 083 ni = enumeration.nextElement(); 084 if (ni != null && ni.isUp() && !ni.isLoopback()) { 085 final Method method = ni.getClass().getMethod("getHardwareAddress"); 086 if (method != null) { 087 mac = (byte[]) method.invoke(ni); 088 } 089 } 090 } 091 } 092 } catch (final Exception ex) { 093 ex.printStackTrace(); 094 // Ignore exception 095 } 096 if (mac == null || mac.length == 0) { 097 mac = address.getAddress(); 098 } 099 } catch (final UnknownHostException e) { 100 // Ignore exception 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 /* This class cannot be instantiated */ 158 private UUIDUtil() { 159 } 160 161 /** 162 * Generates Type 1 UUID. The time contains the number of 100NS intervals that have occurred 163 * since 00:00:00.00 UTC, 10 October 1582. Each UUID on a particular machine is unique to the 100NS interval 164 * until they rollover around 3400 A.D. 165 * <ol> 166 * <li>Digits 1-12 are the lower 48 bits of the number of 100 ns increments since the start of the UUID 167 * epoch.</li> 168 * <li>Digit 13 is the version (with a value of 1).</li> 169 * <li>Digits 14-16 are a sequence number that is incremented each time a UUID is generated.</li> 170 * <li>Digit 17 is the variant (with a value of binary 10) and 10 bits of the sequence number</li> 171 * <li>Digit 18 is final 16 bits of the sequence number.</li> 172 * <li>Digits 19-32 represent the system the application is running on. 173 * </ol> 174 * 175 * @return universally unique identifiers (UUID) 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