package rocks.inspectit.shared.all.util; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.util.List; /** * Provides information about the System and JVM. * <p> * <b>IMPORTANT:</b> The class code is copied/taken/based from * <a href="https://commons.apache.org/proper/commons-lang/">Apache Commons Lang</a> * {@link org.apache.commons.lang.SystemUtils} class. License info can be found * <a href="http://www.apache.org/licenses/">here</a>. * */ public final class UnderlyingSystemInfo { /** * Amount of heap in bytes till the compressed oops are activated by default with 64bit Sun JVM. */ private static final long MAX_COMPRESSED_OOPS_JAVA7_MEMORY = 34359738368L; /** * Enumeration for Java version. * * @author Ivan Senic * */ public enum JavaVersion { /** * Denotes Java version 1.1. */ JAVA_1_1, /** * Denotes Java version 1.2. */ JAVA_1_2, /** * Denotes Java version 1.3. */ JAVA_1_3, /** * Denotes Java version 1.4. */ JAVA_1_4, /** * Denotes Java version 1.5. */ JAVA_1_5, /** * Denotes Java version 1.6. */ JAVA_1_6, /** * Denotes Java version 1.7. */ JAVA_1_7, /** * Denotes unknown java version. */ OTHER; } /** * Enumeration for Java provider. * * @author Ivan Senic * */ public enum JvmProvider { /** * Denotes JVM from Sun. */ SUN, /** * Denotes JVM from Oracle-Corporation. */ ORACLE, /** * Denotes JVM from IBM. */ IBM, /** * Denotes JVM from other provider. */ OTHER; } /** * Java vendor. */ public static final String JAVA_VENDOR = getSystemProperty("java.vendor"); /** * Java version. */ public static final String JAVA_VERSION_FULL = getSystemProperty("java.version"); /** * Java version trimmed. */ public static final String JAVA_VERSION_TRIMMED = getJavaVersionTrimmed(); /** * Java version in {@link JavaVersion} enumeration. */ public static final JavaVersion JAVA_VERSION = getJavaVersion(); /** * JVM provider in {@link JvmProvider} enumeration. */ public static final JvmProvider JVM_PROVIDER = getJvmProvider(); /** * <p> * Is <code>true</code> if the Java is 64bit. Works only if VM is IBM or Sun. * </p> * */ public static final boolean IS_64BIT = is64Bit(); /** * <p> * Is <code>true</code> if the Java is 64bit and compressed oops are used. Works only if VM is * IBM or Sun. * </p> * */ public static final boolean IS_COMPRESSED_OOPS = isCompressedOops(); /** * Private constructor. */ private UnderlyingSystemInfo() { } /** * Returns the JVM provider. * * @return Returns the JVM provider. */ private static JvmProvider getJvmProvider() { if (getJavaVendorMatches("Sun")) { return JvmProvider.SUN; } else if (getJavaVendorMatches("Oracle Corporation")) { return JvmProvider.ORACLE; } else if (getJavaVendorMatches("IBM")) { return JvmProvider.IBM; } else { return JvmProvider.OTHER; } } /** * Returns the Java version. * * @return Returns the Java version. */ private static JavaVersion getJavaVersion() { if (getJavaVersionMatches("1.1")) { return JavaVersion.JAVA_1_1; } else if (getJavaVersionMatches("1.2")) { return JavaVersion.JAVA_1_2; } else if (getJavaVersionMatches("1.3")) { return JavaVersion.JAVA_1_3; } else if (getJavaVersionMatches("1.4")) { return JavaVersion.JAVA_1_4; } else if (getJavaVersionMatches("1.5")) { return JavaVersion.JAVA_1_5; } else if (getJavaVersionMatches("1.6")) { return JavaVersion.JAVA_1_6; } else if (getJavaVersionMatches("1.7")) { return JavaVersion.JAVA_1_7; } else { return JavaVersion.OTHER; } } /** * Matches the vendor name provided with the vendor of the JVM. * * @param vendor * Vendor to check. * @return True if the {@link #JAVA_VENDOR} is not <code>null</code> and vendor name matches. */ private static boolean getJavaVendorMatches(String vendor) { if (null != JAVA_VENDOR) { return JAVA_VENDOR.indexOf(vendor) != -1; } return false; } /** * Returns if the JVM is a 64bit. Note that this method returns <code>false</code> if the JVM is * not from Sun or IBM. * * @return Returns if the JVM is a 64bit. Note that this method returns <code>false</code> if * the JVM is not from Sun or IBM. */ private static boolean is64Bit() { switch (JVM_PROVIDER) { case SUN: return System.getProperty("sun.arch.data.model").indexOf("64") != -1; case ORACLE: return System.getProperty("sun.arch.data.model").indexOf("64") != -1; case IBM: return System.getProperty("com.ibm.vm.bitmode").indexOf("64") != -1; default: return false; } } /** * Tests if the compressed pointers are used. Note that this method will return true only if the * JVM is 64bit, ignoring the fact that the 32bit JVM can also have * <code>+UseCompressedOops</code> argument. This method has been tested with Sun & IBM virtual * machine, and behavior with different providers is unknown. * <p> * IMPORTANT (SUN & ORACLE): Compressed oops is supported and enabled by default in Java SE 6u23 * and later. In Java SE 7, use of compressed oops is the default for 64-bit JVM processes when * -Xmx isn't specified and for values of -Xmx less than 32 gigabytes. For JDK 6 before the 6u23 * release, use the -XX:+UseCompressedOops flag with the java command to enable the feature. * <p> * IMPORTANT (IBM): From Java 6 SR 5, 64-bit JVMs recognize the following Oracle JVM options: * -XX:+UseCompressedOops This enables compressed references in 64-bit JVMs. It is identical to * specifying the -Xcompressedrefs option. -XX:-UseCompressedOops This prevents use of * compressed references in 64-bit JVMs. * * @return True only if JVM is 64bit and compressed oops are used. */ private static boolean isCompressedOops() { if (IS_64BIT) { RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); if (null != runtimeMXBean) { List<String> arguments = runtimeMXBean.getInputArguments(); for (String argument : arguments) { if ((argument.indexOf("+UseCompressedOops") != -1) || (argument.indexOf("compressedrefs") != -1)) { return true; } else if (argument.indexOf("-UseCompressedOops") != -1) { return false; } } } switch (getJvmProvider()) { case SUN: case ORACLE: if (getJavaVersion() == JavaVersion.JAVA_1_7) { long max = Runtime.getRuntime().maxMemory(); return (max == Long.MAX_VALUE) || (max < MAX_COMPRESSED_OOPS_JAVA7_MEMORY); } else if (getJavaVersion() == JavaVersion.JAVA_1_6) { try { int subversionIndexStart = JAVA_VERSION_TRIMMED.indexOf('_'); boolean isAbove6u23 = Integer.parseInt(JAVA_VERSION_TRIMMED.substring(subversionIndexStart + 1)) >= 23; return isAbove6u23; } catch (NumberFormatException e) { break; } } break; default: break; } } return false; } /** * <p> * Decides if the Java version matches. * </p> * * @param versionPrefix * the prefix for the java version * @return true if matches, or false if not or can't determine */ private static boolean getJavaVersionMatches(String versionPrefix) { return isJavaVersionMatch(JAVA_VERSION_TRIMMED, versionPrefix); } /** * <p> * Decides if the Java version matches. * </p> * <p> * This method is package private instead of private to support unit test invocation. * </p> * * @param version * the actual Java version * @param versionPrefix * the prefix for the expected Java version * @return true if matches, or false if not or can't determine */ private static boolean isJavaVersionMatch(String version, String versionPrefix) { if (version == null) { return false; } return version.startsWith(versionPrefix); } /** * Trims the text of the java version to start with numbers. * * @return the trimmed java version */ private static String getJavaVersionTrimmed() { if (JAVA_VERSION_FULL != null) { for (int i = 0; i < JAVA_VERSION_FULL.length(); i++) { char ch = JAVA_VERSION_FULL.charAt(i); if ((ch >= '0') && (ch <= '9')) { return JAVA_VERSION_FULL.substring(i); } } } return null; } /** * <p> * Gets a System property, defaulting to <code>null</code> if the property cannot be read. * </p> * * <p> * If a <code>SecurityException</code> is caught, the return value is <code>null</code> and a * message is written to <code>System.err</code>. * </p> * * @param property * the system property name * @return the system property value or <code>null</code> if a security problem occurs */ private static String getSystemProperty(String property) { try { return System.getProperty(property); } catch (SecurityException ex) { return null; } } }