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

com.fluxtion.agrona.SystemUtil Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2024 Real Logic Limited.
 *
 * 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
 *
 * https://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 com.fluxtion.agrona;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * Utilities for inspecting the system.
 */
public final class SystemUtil
{
    /**
     * PID value if a process id could not be determined. This value should be equal to a kernel only process
     * id for the platform so that it does not indicate a real process id.
     */
    public static final long PID_NOT_FOUND = 0;

    /**
     * Value a {@link System#getProperties()} can be set to so that {@code null} will be returned as if the property
     * was not set.
     *
     * @see #getProperty(String)
     */
    public static final String NULL_PROPERTY_VALUE = "@null";

    private static final String SUN_PID_PROP_NAME = "sun.java.launcher.pid";
    private static final long MAX_G_VALUE = 8589934591L;
    private static final long MAX_M_VALUE = 8796093022207L;
    private static final long MAX_K_VALUE = 9007199254739968L;

    private static final String OS_NAME;
    private static final String OS_ARCH;
    private static final long PID;

    static
    {
        OS_NAME = System.getProperty("os.name").toLowerCase();
        OS_ARCH = System.getProperty("os.arch", "unknown");

        long pid = PID_NOT_FOUND;
        try
        {
            final Class processHandleClass = Class.forName("java.lang.ProcessHandle");
            final Method currentMethod = processHandleClass.getMethod("current");
            final Object processHandle = currentMethod.invoke(null);
            final Method pidMethod = processHandleClass.getMethod("pid");
            pid = (Long)pidMethod.invoke(processHandle);
        }
        catch (final Throwable ignore)
        {
            try
            {
                final String pidPropertyValue = System.getProperty(SUN_PID_PROP_NAME);
                if (null != pidPropertyValue)
                {
                    pid = Long.parseLong(pidPropertyValue);
                }
                else
                {
                    final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
                    pid = Long.parseLong(jvmName.split("@")[0]);
                }
            }
            catch (final Throwable ignore2)
            {
            }
        }

        PID = pid;
    }

    private SystemUtil()
    {
    }

    /**
     * Get the name of the operating system as a lower case String.
     * 

* This is what is returned from {@code System.getProperty("os.name").toLowerCase()}. * * @return the name of the operating system as a lower case String. */ public static String osName() { return OS_NAME; } /** * Returns the name of the operating system architecture. *

* This is the same a calling the {@code System.getProperty("os.arch", "unknown")}. * * @return name of the operating system architecture or {@code unknown}. */ public static String osArch() { return OS_ARCH; } /** * Return the current process id from the OS. * * @return current process id or {@link #PID_NOT_FOUND} if PID was not found. * @see #PID_NOT_FOUND */ public static long getPid() { return PID; } /** * Is the operating system likely to be Windows based on {@link #osName()}. * * @return {@code true} if the operating system is likely to be Windows based on {@link #osName()}. */ public static boolean isWindows() { return OS_NAME.startsWith("win"); } /** * Is the operating system likely to be Linux based on {@link #osName()}. * * @return {@code true} if the operating system is likely to be Linux based on {@link #osName()}. */ public static boolean isLinux() { return OS_NAME.contains("linux"); } /** * Is the operating system architecture ({@link #osArch()}) represents an x86-based system. * * @return {@code true} if the operating system architecture represents an x86-based system. */ public static boolean isX64Arch() { return isX64Arch(OS_ARCH); } /** * Is a debugger attached to the JVM? * * @return {@code true} if attached otherwise false. */ public static boolean isDebuggerAttached() { final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); for (final String arg : runtimeMXBean.getInputArguments()) { if (arg.contains("-agentlib:jdwp")) { return true; } } return false; } /** * Return the system property for java.io.tmpdir ensuring a {@link File#separator} is at the end. * * @return tmp directory for the runtime. */ public static String tmpDirName() { String tmpDirName = System.getProperty("java.io.tmpdir"); if (!tmpDirName.endsWith(File.separator)) { tmpDirName += File.separator; } return tmpDirName; } /** * Get a formatted dump of all threads with associated state and stack traces. * * @return a formatted dump of all threads with associated state and stack traces. */ public static String threadDump() { final StringBuilder sb = new StringBuilder(); threadDump(sb); return sb.toString(); } /** * Write a formatted dump of all threads with associated state and stack traces to a provided {@link StringBuilder}. * * @param sb to write the thread dump to. */ public static void threadDump(final StringBuilder sb) { final ThreadMXBean mxBean = ManagementFactory.getThreadMXBean(); for (final ThreadInfo threadInfo : mxBean.getThreadInfo(mxBean.getAllThreadIds(), Integer.MAX_VALUE)) { if (null != threadInfo) { sb.append('"').append(threadInfo.getThreadName()).append("\": ").append(threadInfo.getThreadState()); for (final StackTraceElement stackTraceElement : threadInfo.getStackTrace()) { sb.append("\n at ").append(stackTraceElement.toString()); } sb.append("\n\n"); } } } /** * Load system properties from a given filename or url with default to {@link PropertyAction#REPLACE}. *

* File is first searched for in resources using the system {@link ClassLoader}, * then file system, then URL. All are loaded if multiples found. * * @param filenameOrUrl that holds properties. */ public static void loadPropertiesFile(final String filenameOrUrl) { loadPropertiesFile(PropertyAction.REPLACE, filenameOrUrl); } /** * Load system properties from a given filename or url. *

* File is first searched for in resources using the system {@link ClassLoader}, * then file system, then URL. All are loaded if multiples found. * * @param propertyAction to take with each loaded property. * @param filenameOrUrl that holds properties. */ public static void loadPropertiesFile(final PropertyAction propertyAction, final String filenameOrUrl) { final URL resource = ClassLoader.getSystemClassLoader().getResource(filenameOrUrl); if (null != resource) { try (InputStream in = resource.openStream()) { loadProperties(propertyAction, in); } catch (final Exception ignore) { } } final File file = new File(filenameOrUrl); if (file.exists()) { try (InputStream in = Files.newInputStream(file.toPath())) { loadProperties(propertyAction, in); } catch (final Exception ignore) { } } try (InputStream in = new URI(filenameOrUrl).toURL().openStream()) { loadProperties(propertyAction, in); } catch (final Exception ignore) { } } /** * Load system properties from a given set of filenames or URLs with default to {@link PropertyAction#REPLACE}. * * @param filenamesOrUrls that holds properties. * @see #loadPropertiesFile(String) */ public static void loadPropertiesFiles(final String... filenamesOrUrls) { loadPropertiesFiles(PropertyAction.REPLACE, filenamesOrUrls); } /** * Load system properties from a given set of filenames or URLs. * * @param propertyAction to take with each loaded property. * @param filenamesOrUrls that holds properties. * @see #loadPropertiesFile(String) */ public static void loadPropertiesFiles(final PropertyAction propertyAction, final String... filenamesOrUrls) { for (final String filenameOrUrl : filenamesOrUrls) { loadPropertiesFile(propertyAction, filenameOrUrl); } } /** * Get the value of a {@link System#getProperty(String)} with the exception that if the value is * {@link #NULL_PROPERTY_VALUE} then return {@code null}. * * @param propertyName to get the value for. * @return the value of a {@link System#getProperty(String)} with the exception that if the value is * {@link #NULL_PROPERTY_VALUE} then return {@code null}. */ public static String getProperty(final String propertyName) { final String propertyValue = System.getProperty(propertyName); return NULL_PROPERTY_VALUE.equals(propertyValue) ? null : propertyValue; } /** * Get the value of a {@link System#getProperty(String, String)} with the exception that if the value is * {@link #NULL_PROPERTY_VALUE} then return {@code null}, otherwise if the value is not set then return the default * value. * * @param propertyName to get the value for. * @param defaultValue to use if the property is not set. * @return the value of a {@link System#getProperty(String, String)} with the exception that if the value is * {@link #NULL_PROPERTY_VALUE} then return {@code null}, otherwise if the value is not set then return the default * value. */ public static String getProperty(final String propertyName, final String defaultValue) { final String propertyValue = System.getProperty(propertyName); if (NULL_PROPERTY_VALUE.equals(propertyValue)) { return null; } return null == propertyValue ? defaultValue : propertyValue; } /** * Get a size value as an int from a system property. Supports a 'g', 'm', and 'k' suffix to indicate * gigabytes, megabytes, or kilobytes respectively. * * @param propertyName to lookup. * @param defaultValue to be applied if the system property is not set. * @return the int value. * @throws NumberFormatException if the value is out of range or mal-formatted. */ public static int getSizeAsInt(final String propertyName, final int defaultValue) { final String propertyValue = System.getProperty(propertyName); if (propertyValue != null) { final long value = parseSize(propertyName, propertyValue); if (value < 0 || value > Integer.MAX_VALUE) { throw new NumberFormatException( propertyName + " must positive and less than Integer.MAX_VALUE: " + value); } return (int)value; } return defaultValue; } /** * Get a size value as a long from a system property. Supports a 'g', 'm', and 'k' suffix to indicate * gigabytes, megabytes, or kilobytes respectively. * * @param propertyName to lookup. * @param defaultValue to be applied if the system property is not set. * @return the long value. * @throws NumberFormatException if the value is out of range or mal-formatted. */ public static long getSizeAsLong(final String propertyName, final long defaultValue) { final String propertyValue = System.getProperty(propertyName); if (propertyValue != null) { final long value = parseSize(propertyName, propertyValue); if (value < 0) { throw new NumberFormatException(propertyName + " must be positive: " + value); } return value; } return defaultValue; } /** * Parse a string representation of a value with optional suffix of 'g', 'm', and 'k' suffix to indicate * gigabytes, megabytes, or kilobytes respectively. * * @param propertyName that associated with the size value. * @param propertyValue to be parsed. * @return the long value. * @throws NumberFormatException if the value is out of range or mal-formatted. */ public static long parseSize(final String propertyName, final String propertyValue) { final int lengthMinusSuffix = propertyValue.length() - 1; final char lastCharacter = propertyValue.charAt(lengthMinusSuffix); if (Character.isDigit(lastCharacter)) { return Long.parseLong(propertyValue); } final long value = AsciiEncoding.parseLongAscii(propertyValue, 0, lengthMinusSuffix); switch (lastCharacter) { case 'k': case 'K': if (value > MAX_K_VALUE) { throw new NumberFormatException(propertyName + " would overflow a long: " + propertyValue); } return value * 1024; case 'm': case 'M': if (value > MAX_M_VALUE) { throw new NumberFormatException(propertyName + " would overflow a long: " + propertyValue); } return value * 1024 * 1024; case 'g': case 'G': if (value > MAX_G_VALUE) { throw new NumberFormatException(propertyName + " would overflow a long: " + propertyValue); } return value * 1024 * 1024 * 1024; default: throw new NumberFormatException( propertyName + ": " + propertyValue + " should end with: k, m, or g."); } } /** * Get a string representation of a time duration with an optional suffix of 's', 'ms', 'us', or 'ns' suffix to * indicate seconds, milliseconds, microseconds, or nanoseconds respectively. *

* If the resulting duration is greater than {@link Long#MAX_VALUE} then {@link Long#MAX_VALUE} is used. * * @param propertyName associated with the duration value. * @param defaultValue to be used if the property is not present. * @return the long value. * @throws NumberFormatException if the value is negative or malformed. */ public static long getDurationInNanos(final String propertyName, final long defaultValue) { final String propertyValue = System.getProperty(propertyName); if (propertyValue != null) { final long value = parseDuration(propertyName, propertyValue); if (value < 0) { throw new NumberFormatException(propertyName + " must be positive: " + value); } return value; } return defaultValue; } /** * Parse a string representation of a time duration with an optional suffix of 's', 'ms', 'us', or 'ns' to * indicate seconds, milliseconds, microseconds, or nanoseconds respectively. *

* If the resulting duration is greater than {@link Long#MAX_VALUE} then {@link Long#MAX_VALUE} is used. * * @param propertyName associated with the duration value. * @param propertyValue to be parsed. * @return the long value. * @throws NumberFormatException if the value is negative or malformed. */ public static long parseDuration(final String propertyName, final String propertyValue) { final char lastCharacter = propertyValue.charAt(propertyValue.length() - 1); if (Character.isDigit(lastCharacter)) { return Long.parseLong(propertyValue); } if (lastCharacter != 's' && lastCharacter != 'S') { throw new NumberFormatException( propertyName + ": " + propertyValue + " should end with: s, ms, us, or ns."); } final char secondLastCharacter = propertyValue.charAt(propertyValue.length() - 2); if (Character.isDigit(secondLastCharacter)) { final long value = AsciiEncoding.parseLongAscii(propertyValue, 0, propertyValue.length() - 1); return TimeUnit.SECONDS.toNanos(value); } final long value = AsciiEncoding.parseLongAscii(propertyValue, 0, propertyValue.length() - 2); switch (secondLastCharacter) { case 'n': case 'N': return value; case 'u': case 'U': return TimeUnit.MICROSECONDS.toNanos(value); case 'm': case 'M': return TimeUnit.MILLISECONDS.toNanos(value); default: throw new NumberFormatException( propertyName + ": " + propertyValue + " should end with: s, ms, us, or ns."); } } static boolean isX64Arch(final String arch) { return arch.equals("amd64") || arch.equals("x86_64") || arch.equals("x64"); } private static void loadProperties(final PropertyAction propertyAction, final InputStream in) throws IOException { final Properties systemProperties = System.getProperties(); final Properties properties = new Properties(); properties.load(in); properties.forEach( (k, v) -> { switch (propertyAction) { case PRESERVE: if (!systemProperties.containsKey(k)) { systemProperties.setProperty((String)k, (String)v); } break; default: case REPLACE: systemProperties.setProperty((String)k, (String)v); break; } }); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy