2 * Copyright © 2016-2018 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.openecomp.sdc.logging.context;
19 import java.net.InetAddress;
20 import java.net.NetworkInterface;
21 import java.net.SocketException;
22 import java.net.UnknownHostException;
23 import java.util.Enumeration;
24 import java.util.Optional;
25 import java.util.function.Supplier;
28 * Holds a reference to local host address as returned by Java runtime. A value of host address will be cached for the
29 * interval specified in the constructor or {@link #DEFAULT_REFRESH_INTERVAL}. The caching helps to avoid many low-level
30 * calls, but at the same time pick up any IP or FQDN changes. Although the underlying JDK implementation uses caching
31 * too, the refresh interval for logging may be much longer due to the nature of the use.
36 @SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace", "squid:S106", "squid:S1148", "squid:S1166"})
37 public class HostAddressCache {
39 private static final long DEFAULT_REFRESH_INTERVAL = 60000L; // 1 min
41 private final long interval;
43 private volatile CacheEntry cachedAddress;
45 private final Supplier<InetAddress> readAddress;
47 public HostAddressCache() {
48 this(DEFAULT_REFRESH_INTERVAL);
52 * Creates a cache for host address with a custom refresh interval.
54 public HostAddressCache(long refreshInterval) {
55 this.interval = refreshInterval;
56 this.readAddress = HostAddressCache::read;
57 this.cachedAddress = new CacheEntry(System.currentTimeMillis(), readAddress.get());
61 * Package level constructor used for unit test in order to avoid static mock
64 * @param refreshInterval
66 HostAddressCache(Supplier<InetAddress> readAddress, long refreshInterval) {
67 this.interval = refreshInterval;
68 this.readAddress = readAddress;
69 this.cachedAddress = new CacheEntry(System.currentTimeMillis(), this.readAddress.get());
73 * Returns an address (host name and IP address) of the local system.
75 * @return local host address or <code>null</code> if it could not be read for some reason
77 public synchronized Optional<InetAddress> get() {
79 long current = System.currentTimeMillis();
80 if (current - cachedAddress.lastUpdated < interval) {
81 return Optional.ofNullable(cachedAddress.address);
84 InetAddress address = readAddress.get(); // register the attempt even if null, i.e. failed to get a meaningful address
85 cachedAddress = new CacheEntry(current, address);
86 return Optional.ofNullable(address);
89 private static InetAddress read() {
92 return InetAddress.getLocalHost();
93 } catch (UnknownHostException e) {
95 "[WARNING] Failed to get local host address. Using a fallback. If you are on Linux, make sure "
96 + "/etc/hosts contains the host name of your machine, "
97 + "e.g. '127.0.0.1 localhost my-host.example.com'.");
99 e.printStackTrace(); // can't really use logging
100 return getFallbackLocalHost();
104 private static InetAddress getFallbackLocalHost() {
108 Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
110 while (networkInterfaces.hasMoreElements()) {
112 InetAddress address = getAddress(networkInterfaces.nextElement());
113 if (address != null) {
120 } catch (SocketException e) {
121 e.printStackTrace(); // can't really use logging
126 private static InetAddress getAddress(NetworkInterface networkInterface) throws SocketException {
128 if (networkInterface.isLoopback() || networkInterface.isUp()) {
132 Enumeration<InetAddress> interfaceAddresses = networkInterface.getInetAddresses();
133 while (interfaceAddresses.hasMoreElements()) {
135 InetAddress address = interfaceAddresses.nextElement();
136 if (isHostAddress(address)) {
144 private static boolean isHostAddress(InetAddress address) {
145 return !address.isLoopbackAddress() && !address.isAnyLocalAddress() && !address.isLinkLocalAddress()
146 && !address.isMulticastAddress();
149 private static class CacheEntry {
151 private final long lastUpdated;
152 private final InetAddress address;
154 private CacheEntry(long lastUpdated, InetAddress address) {
155 this.lastUpdated = lastUpdated;
156 this.address = address;