All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.terracotta.management.model.cluster.ClientIdentifier Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
/*
 * Copyright Terracotta, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.terracotta.management.model.cluster;

import org.terracotta.management.model.Objects;

import javax.xml.bind.DatatypeConverter;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Client identifier:
 *
 * @author Mathieu Carbou
 */
public final class ClientIdentifier implements Serializable {

  private static final Logger LOGGER = Logger.getLogger(ClientIdentifier.class.getName());

  private final long pid;
  private final String applicationName;
  private final String hostAddress;

  private ClientIdentifier(long pid, String hostAddress, String applicationName) {
    this.hostAddress = Objects.requireNonNull(hostAddress);
    this.pid = pid;
    this.applicationName = Objects.requireNonNull(applicationName);
  }

  public String getHostAddress() {
    return hostAddress;
  }

  public long getPid() {
    return pid;
  }

  public String getApplicationName() {
    return applicationName;
  }

  public String getClientId() {
    return getVmId() + ":" + getApplicationName();
  }

  public String getVmId() {
    return getPid() + "@" + getHostAddress();
  }

  @Override
  public String toString() {
    return getClientId();
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    ClientIdentifier that = (ClientIdentifier) o;
    return pid == that.pid && applicationName.equals(that.applicationName) && hostAddress.equals(that.hostAddress);
  }

  @Override
  public int hashCode() {
    int result = (int) (pid ^ (pid >>> 32));
    result = 31 * result + applicationName.hashCode();
    result = 31 * result + hostAddress.hashCode();
    return result;
  }

  public static ClientIdentifier create(long pid, String hostAddress, String uuid) {
    return new ClientIdentifier(pid, hostAddress, uuid);
  }

  public static ClientIdentifier create() {
    return create(generateNewUUID());
  }

  public static ClientIdentifier create(String applicationName) {
    try {
      InetAddress inetAddress = discoverLANAddress();
      return new ClientIdentifier(discoverPID(), inetAddress.getHostAddress(), applicationName);
    } catch (UnknownHostException e) {
      return new ClientIdentifier(discoverPID(), "127.0.0.1", applicationName);
    }

  }

  public static ClientIdentifier valueOf(String identifier) {
    try {
      int copy = identifier.indexOf('@');
      int colon = identifier.indexOf(':', copy + 1);
      return new ClientIdentifier(Long.parseLong(identifier.substring(0, copy)), identifier.substring(copy + 1, colon), identifier.substring(colon + 1));
    } catch (RuntimeException e) {
      throw new IllegalArgumentException(identifier);
    }
  }

  static String discoverHostName() {
    String hostname = null;

    try {
      String procname = "hostname";
      if (System.getProperty("os.name", "").toLowerCase().contains("win")) {
        procname += ".exe";
      }
      Process process = Runtime.getRuntime().exec(procname);
      if (process.waitFor() == 0) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        InputStream in = process.getInputStream();
        int r;
        while ((r = in.read()) != -1) {
          baos.write(r);
        }
        in.close();
        hostname = new String(baos.toByteArray(), "UTF-8");
      }
    } catch (Exception e) {
      // if anything goes wrong, just ignore
      if (LOGGER.isLoggable(Level.FINEST)) {
        LOGGER.log(Level.FINEST, "ERR getHostName(): " + e.getMessage(), e);
      }
    }

    if (hostname != null) {
      return hostname;
    }

    try {
      InetAddress address = discoverLANAddress();
      String resolved = address.getCanonicalHostName();
      if (!address.getHostAddress().equals(resolved)) {
        // this check is ok, getCanonicalHostName() does return getHostAddress() in case of failure
        hostname = resolved;
      }
    } catch (Exception ignored) {
    }

    return hostname;
  }

  static String generateNewUUID() {
    UUID j = UUID.randomUUID();
    byte[] data = new byte[16];
    long msb = j.getMostSignificantBits();
    long lsb = j.getLeastSignificantBits();
    for (int i = 0; i < 8; i++) {
      data[i] = (byte) (msb & 0xff);
      msb >>>= 8;
    }
    for (int i = 8; i < 16; i++) {
      data[i] = (byte) (lsb & 0xff);
      lsb >>>= 8;
    }
    return DatatypeConverter.printBase64Binary(data)
        // java-8 and otehr - compatible B64 url decoder using - and _ instead of + and /
        // padding can be ignored to shorter the UUID
        .replace('+', '-').replace('/', '_').replace("=", "");
  }

  static long discoverPID() {
    String name = ManagementFactory.getRuntimeMXBean().getName();
    long pid = 0;
    for (int i = 0; i < name.length() && Character.isDigit(name.charAt(i)); i++) {
      pid = pid * 10 + Character.getNumericValue(name.charAt(i));
    }
    return pid;
  }

  /**
   * http://stackoverflow.com/questions/9481865/getting-the-ip-address-of-the-current-machine-using-java
   * 

* Returns an InetAddress object encapsulating what is most likely the machine's LAN IP address. *

* This method is intended for use as a replacement of JDK method InetAddress.getLocalHost, because * that method is ambiguous on Linux systems. Linux systems enumerate the loopback network interface the same * way as regular LAN network interfaces, but the JDK InetAddress.getLocalHost method does not * specify the algorithm used to select the address returned under such circumstances, and will often return the * loopback address, which is not valid for network communication. Details * here. *

* This method will scan all IP addresses on all network interfaces on the host machine to determine the IP address * most likely to be the machine's LAN address. If the machine has multiple IP addresses, this method will prefer * a site-local IP address (e.g. 192.168.x.x or 10.10.x.x, usually IPv4) if the machine has one (and will return the * first site-local address if the machine has more than one), but if the machine does not hold a site-local * address, this method will return simply the first non-loopback address found (IPv4 or IPv6). *

* If this method cannot find a non-loopback address using this selection algorithm, it will fall back to * calling and returning the result of JDK method InetAddress.getLocalHost. *

* * @throws UnknownHostException If the LAN address of the machine cannot be found. */ static InetAddress discoverLANAddress() throws UnknownHostException { InetAddress inetAddress = InetAddress.getLocalHost(); if (!inetAddress.isLoopbackAddress() && inetAddress.isSiteLocalAddress()) { return inetAddress; } try { InetAddress candidateAddress = null; // Iterate all NICs (network interface cards)... for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) { NetworkInterface iface = (NetworkInterface) ifaces.nextElement(); // Iterate all IP addresses assigned to each card... for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) { InetAddress inetAddr = (InetAddress) inetAddrs.nextElement(); if (!inetAddr.isLoopbackAddress()) { if (inetAddr.isSiteLocalAddress()) { // Found non-loopback site-local address. Return it immediately... return inetAddr; } else if (candidateAddress == null) { // Found non-loopback address, but not necessarily site-local. // Store it as a candidate to be returned if site-local address is not subsequently found... candidateAddress = inetAddr; // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates, // only the first. For subsequent iterations, candidate will be non-null. } } } } if (candidateAddress != null) { // We did not find a site-local address, but we found some other non-loopback address. // Server might have a non-site-local address assigned to its NIC (or it might be running // IPv6 which deprecates the "site-local" concept). // Return this non-loopback candidate address... return candidateAddress; } // At this point, we did not find a non-loopback address. // Fall back to returning whatever InetAddress.getLocalHost() returns... InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); if (jdkSuppliedAddress == null) { throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null."); } return jdkSuppliedAddress; } catch (Exception e) { UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e); unknownHostException.initCause(e); throw unknownHostException; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy