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

org.terracotta.management.sequence.Defaults Maven / Gradle / Ivy

/*
 * 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.sequence;

import java.lang.management.ManagementFactory;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.ServiceLoader;

/**
 * @author Mathieu Carbou
 */
class Defaults {

  private static final int PID_BITLENGTH = 16;
  private static final long PID_BITMASK = (1L << PID_BITLENGTH) - 1;

  static final int SEQ_BITLENGTH = 18;
  static final long SEQ_BITMASK = (1L << SEQ_BITLENGTH) - 1;

  static final int INSTANCE_BITLENGTH = 18;
  static final int INSTANCE_BITMASK = (1 << INSTANCE_BITLENGTH) - 1;

  static final NodeIdSource MAC_PID_NODE_ID_SOURCE = new NodeIdSource() {
    @Override
    public long getNodeId() {
      // at least 6 bytes
      byte[] mac = readFirstNonLoopbackMacAddress();
      long nodeId = 0;
      // we consider the 6 last bytes only,
      for (int i = Math.max(0, mac.length - 6); i < mac.length; i++) {
        nodeId = (nodeId << 8) | (mac[i] & 0XFF);
      }
      // keeps a positive node id with the 0x7fffffffffffffffL mask
      return ((nodeId << PID_BITLENGTH) & Long.MAX_VALUE) | (readPID() & PID_BITMASK);
    }
  };

  static final NodeIdSource BEST_NODE_ID_SOURCE = new NodeIdSource() {
    final NodeIdSource delegate = findBest(NodeIdSource.class, MAC_PID_NODE_ID_SOURCE);

    @Override
    public long getNodeId() {
      return delegate.getNodeId();
    }
  };

  static final TimeSource SYSTEM_TIME_SOURCE = new TimeSource() {
    @Override
    public long getTimestamp() {
      return System.currentTimeMillis();
    }
  };

  static final TimeSource BEST_TIME_SOURCE = new TimeSource() {
    final TimeSource delegate = findBest(TimeSource.class, SYSTEM_TIME_SOURCE);

    @Override
    public long getTimestamp() {
      return delegate.getTimestamp();
    }
  };

  private static final Comparator NETWORK_INTERFACE_COMPARATOR = new Comparator() {
    @Override
    public int compare(NetworkInterface o1, NetworkInterface o2) {
      return o1.getName().compareTo(o2.getName());
    }
  };

  static byte[] readFirstNonLoopbackMacAddress() {
    List networkInterfaces;
    try {
      networkInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
    } catch (SocketException e) {
      throw new IllegalStateException("Machine has no network interfaces!", e);
    }

    // order interfaces by name
    Collections.sort(networkInterfaces, NETWORK_INTERFACE_COMPARATOR);

    // find the first accessible non-loopback interface having a mac address
    // we try first to skip all virtual interfaces since they can be easily dynamically created on-demand
    // the goal of this method is to try return the same value each time as possible
    // we consider only "parent" interfaces
    for (NetworkInterface networkInterface : networkInterfaces) {
      try {
        byte[] mac;
        if (!networkInterface.isLoopback()
            && !networkInterface.isPointToPoint()
            && !networkInterface.isVirtual()
            && networkInterface.getParent() == null
            && (mac = networkInterface.getHardwareAddress()) != null
            && mac.length >= 6) {
          return mac;
        }
      } catch (SocketException ignored) {
      }
    }

    // if we do not succeed, we enlarge our search
    for (NetworkInterface networkInterface : networkInterfaces) {
      try {
        byte[] mac;
        if (!networkInterface.isLoopback()
            && (mac = networkInterface.getHardwareAddress()) != null
            && mac.length >= 6) {
          return mac;
        }
      } catch (SocketException ignored) {
      }
    }

    throw new IllegalStateException("Unable to read a MAC address");
  }

  static long readPID() {
    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;
  }

  private static  T findBest(Class type, T def) {
    // try first a JVM sysprop
    String cName = System.getProperty(type.getName());
    if (cName != null) {
      try {
        return type.cast(Defaults.class.getClassLoader().loadClass(cName).newInstance());
      } catch (Exception e) {
        throw new IllegalArgumentException("Unable to instantiate  " + type.getSimpleName() + " " + cName + " set from system property");
      }
    } else {
      // otherwise, try a service implementation
      try {
        return ServiceLoader.load(type).iterator().next();
      } catch (Exception ignored) {
      }
    }
    // or returns default
    return def;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy