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

com.datadoghq.profiler.Platform Maven / Gradle / Ivy

package com.datadoghq.profiler;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;

import java.util.ArrayList;
import java.util.List;

public final class Platform {

  public enum GC {
    SERIAL("marksweep"),
    PARALLEL("ps"),
    CMS("concurrentmarksweep"),
    G1("g1"),
    SHENANDOAH("shenandoah"),
    Z("z"),
    UNKNOWN("");

    private final String identifierPrefix;

    GC(String identifierPrefix) {
      this.identifierPrefix = identifierPrefix;
    }

    static GC current() {
      for (GarbageCollectorMXBean mxBean : ManagementFactory.getGarbageCollectorMXBeans()) {
        if (mxBean.isValid()) {
          String name = mxBean.getName().toLowerCase();
          for (GC gc : GC.values()) {
            if (gc != UNKNOWN && name.startsWith(gc.identifierPrefix)) {
              return gc;
            }
          }
        }
      }
      return UNKNOWN;
    }
  }

  private static final Version JAVA_VERSION = parseJavaVersion(System.getProperty("java.version"));
  private static final JvmRuntime RUNTIME = new JvmRuntime();

  private static final GC GARBAGE_COLLECTOR = GC.current();

  private static final boolean HAS_JFR = checkForJfr();
  private static final boolean IS_NATIVE_IMAGE_BUILDER = checkForNativeImageBuilder();

  public static GC activeGarbageCollector() {
    return GARBAGE_COLLECTOR;
  }

  public static boolean hasJfr() {
    return HAS_JFR;
  }

  public static boolean isNativeImageBuilder() {
    return IS_NATIVE_IMAGE_BUILDER;
  }

  private static boolean checkForJfr() {
    try {
      /* Check only for the open-sources JFR implementation.
       * If it is ever needed to support also the closed sourced JDK 8 version the check should be
       * enhanced.
       * Need this custom check because ClassLoaderMatchers.hasClassNamed() does not support bootstrap class loader yet.
       * Note: the downside of this is that we load some JFR classes at startup.
       */
      return ClassLoader.getSystemClassLoader().getResource("jdk/jfr/Event.class") != null;
    } catch (Throwable e) {
      return false;
    }
  }

  private static boolean checkForNativeImageBuilder() {
    try {
      return "org.graalvm.nativeimage.builder".equals(System.getProperty("jdk.module.main"));
    } catch (Throwable e) {
      return false;
    }
  }

  /* The method splits java version string by digits. Delimiters are: dot, underscore and plus */
  private static List splitDigits(String str) {
    List results = new ArrayList<>();

    int len = str.length();

    int value = 0;
    for (int i = 0; i < len; i++) {
      char ch = str.charAt(i);
      if (ch >= '0' && ch <= '9') {
        value = value * 10 + (ch - '0');
      } else if (ch == '.' || ch == '_' || ch == '+') {
        results.add(value);
        value = 0;
      } else {
        throw new NumberFormatException();
      }
    }
    results.add(value);
    return results;
  }

  static Version parseJavaVersion(String javaVersion) {
    // Remove pre-release part, usually -ea
    final int indexOfDash = javaVersion.indexOf('-');
    if (indexOfDash >= 0) {
      javaVersion = javaVersion.substring(0, indexOfDash);
    }

    int major = 0;
    int minor = 0;
    int update = 0;

    try {
      List nums = splitDigits(javaVersion);
      major = nums.get(0);

      // for java 1.6/1.7/1.8
      if (major == 1) {
        major = nums.get(1);
        minor = nums.get(2);
        update = nums.get(3);
      } else {
        minor = nums.get(1);
        update = nums.get(2);
      }
    } catch (NumberFormatException | IndexOutOfBoundsException e) {
      // unable to parse version string - do nothing
    }
    return new Version(major, minor, update);
  }

  static final class Version {
    public final int major, minor, update;

    public Version(int major, int minor, int update) {
      this.major = major;
      this.minor = minor;
      this.update = update;
    }

    public boolean is(int major) {
      return this.major == major;
    }

    public boolean is(int major, int minor) {
      return this.major == major && this.minor == minor;
    }

    public boolean is(int major, int minor, int update) {
      return this.major == major && this.minor == minor && this.update == update;
    }

    public boolean isAtLeast(int major, int minor, int update) {
      return isAtLeast(this.major, this.minor, this.update, major, minor, update);
    }

    public boolean isBetween(
        int fromMajor, int fromMinor, int fromUpdate, int toMajor, int toMinor, int toUpdate) {
      return isAtLeast(toMajor, toMinor, toUpdate, fromMajor, fromMinor, fromUpdate)
          && isAtLeast(fromMajor, fromMinor, fromUpdate)
          && !isAtLeast(toMajor, toMinor, toUpdate);
    }

    private static boolean isAtLeast(
        int major, int minor, int update, int atLeastMajor, int atLeastMinor, int atLeastUpdate) {
      return (major > atLeastMajor)
          || (major == atLeastMajor && minor > atLeastMinor)
          || (major == atLeastMajor && minor == atLeastMinor && update >= atLeastUpdate);
    }
  }

  static final class JvmRuntime {
    /*
     * Example:
     *    jvm     -> "AdoptOpenJDK 1.8.0_265-b01"
     *
     *    name    -> "OpenJDK"
     *    vendor  -> "AdoptOpenJDK"
     *    version -> "1.8.0_265"
     *    patches -> "b01"
     */
    public final String name;

    public final String vendor;
    public final String version;
    public final String patches;

    public JvmRuntime() {
      this(
          System.getProperty("java.version"),
          System.getProperty("java.runtime.version"),
          System.getProperty("java.runtime.name"),
          System.getProperty("java.vm.vendor"));
    }

    // Only visible for testing
    JvmRuntime(String javaVer, String rtVer, String name, String vendor) {
      this.name = name == null ? "" : name;
      this.vendor = vendor == null ? "" : vendor;
      javaVer = javaVer == null ? "" : javaVer;
      this.version = javaVer;
      rtVer = javaVer.isEmpty() || rtVer == null ? javaVer : rtVer;
      int patchStart = javaVer.length() + 1;
      this.patches = (patchStart >= rtVer.length()) ? "" : rtVer.substring(javaVer.length() + 1);
    }
  }

  public static boolean isJavaVersion(int major) {
    return JAVA_VERSION.is(major);
  }

  public static boolean isJavaVersion(int major, int minor) {
    return JAVA_VERSION.is(major, minor);
  }

  public static boolean isJavaVersion(int major, int minor, int update) {
    return JAVA_VERSION.is(major, minor, update);
  }

  public static boolean isJavaVersionAtLeast(int major) {
    return isJavaVersionAtLeast(major, 0, 0);
  }

  public static boolean isJavaVersionAtLeast(int major, int minor) {
    return isJavaVersionAtLeast(major, minor, 0);
  }

  public static boolean isJavaVersionAtLeast(int major, int minor, int update) {
    return JAVA_VERSION.isAtLeast(major, minor, update);
  }

  /**
   * Check if the Java version is between {@code fromMajor} (inclusive) and {@code toMajor}
   * (exclusive).
   *
   * @param fromMajor major from version (inclusive)
   * @param toMajor major to version (exclusive)
   * @return if the current java version is between the from version (inclusive) and the to version
   *     exclusive
   */
  public static boolean isJavaVersionBetween(int fromMajor, int toMajor) {
    return isJavaVersionBetween(fromMajor, 0, toMajor, 0);
  }

  /**
   * Check if the Java version is between {@code fromMajor.fromMinor} (inclusive) and {@code
   * toMajor.toMinor} (exclusive).
   *
   * @param fromMajor major from version (inclusive)
   * @param fromMinor minor from version (inclusive)
   * @param toMajor major to version (exclusive)
   * @param toMinor minor to version (exclusive)
   * @return if the current java version is between the from version (inclusive) and the to version
   *     exclusive
   */
  public static boolean isJavaVersionBetween(
      int fromMajor, int fromMinor, int toMajor, int toMinor) {
    return isJavaVersionBetween(fromMajor, fromMinor, 0, toMajor, toMinor, 0);
  }

  /**
   * Check if the Java version is between {@code fromMajor.fromMinor.fromUpdate} (inclusive) and
   * {@code toMajor.toMinor.toUpdate} (exclusive).
   *
   * @param fromMajor major from version (inclusive)
   * @param fromMinor minor from version (inclusive)
   * @param fromUpdate update from version (inclusive)
   * @param toMajor major to version (exclusive)
   * @param toMinor minor to version (exclusive)
   * @param toUpdate update to version (exclusive)
   * @return if the current java version is between the from version (inclusive) and the to version
   *     exclusive
   */
  public static boolean isJavaVersionBetween(
      int fromMajor, int fromMinor, int fromUpdate, int toMajor, int toMinor, int toUpdate) {
    return JAVA_VERSION.isBetween(fromMajor, fromMinor, fromUpdate, toMajor, toMinor, toUpdate);
  }

  public static boolean isLinux() {
    return System.getProperty("os.name").toLowerCase().contains("linux");
  }

  public static boolean isWindows() {
    // https://mkyong.com/java/how-to-detect-os-in-java-systemgetpropertyosname/
    final String os = System.getProperty("os.name").toLowerCase();
    return os.contains("win");
  }

  public static boolean isMac() {
    final String os = System.getProperty("os.name").toLowerCase();
    return os.contains("mac");
  }

  public static boolean isOracleJDK8() {
    return isJavaVersion(8)
        && RUNTIME.vendor.contains("Oracle")
        && !RUNTIME.name.contains("OpenJDK");
  }

  public static boolean isJ9() {
    return System.getProperty("java.vm.name").contains("J9");
  }

  public static boolean isZing() {
    return System.getProperty("java.vm.name").contains("Zing");
  }

  public static String getLangVersion() {
    return String.valueOf(JAVA_VERSION.major);
  }

  public static String getRuntimeVendor() {
    return RUNTIME.vendor;
  }

  public static String getRuntimeVersion() {
    return RUNTIME.version;
  }

  public static String getRuntimePatches() {
    return RUNTIME.patches;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy