Class JLineNativeLoader

java.lang.Object
org.jline.nativ.JLineNativeLoader

public class JLineNativeLoader extends Object
Manages the loading of JLine's native libraries (*.dll, *.jnilib, *.so) according to the current operating system (Windows, Linux, macOS) and architecture.

This class handles the discovery, extraction, and loading of the appropriate native library for the current platform. The native libraries are essential for certain terminal operations that require direct system calls.

Usage

Call initialize() before using JLine features that require native support:
 JLineNativeLoader.initialize();
 

Library Loading Process

The loader attempts to find and load the native library in the following order:
  1. From the path specified by the library.jline.path system property
  2. From the JAR file's embedded native libraries
  3. From the Java library path (java.library.path)

Configuration Options

The following system properties can be used to configure the native library loading:
  • library.jline.path - Custom directory path where native libraries are located. The loader will check both [library.jline.path]/[os]/[arch] and [library.jline.path] directly.
  • library.jline.name - Custom name for the native library file. If not specified, the default name will be used (e.g., "jlinenative.dll" on Windows).
  • jline.tmpdir - Custom temporary directory for extracting native libraries. If not specified, java.io.tmpdir will be used.
  • java.library.path - Standard Java property for native library search paths, used as a last resort.

Platform Detection

The loader automatically detects the current operating system and architecture using OSInfo to determine which native library to load. Supported platforms include:
  • Operating Systems: Windows, macOS (Darwin), Linux, AIX
  • Architectures: x86, x86_64 (amd64), ARM (various versions), PowerPC, and others

Temporary Files

When loading from the JAR file, the native library is extracted to a temporary location. These temporary files:
  • Include version and UUID in the filename to avoid conflicts
  • Are automatically cleaned up on JVM exit
  • Old unused libraries from previous runs are cleaned up

Troubleshooting

If the library fails to load, an exception is thrown with details about:
  • The detected OS and architecture
  • All paths that were searched
  • The specific error that occurred

Java Module System (JPMS) Considerations

When using JLine with the Java Module System, you may need to add the --enable-native-access=ALL-UNNAMED JVM option to allow the native library loading.
See Also:
  • Field Details

    • logger

      private static final Logger logger
    • loaded

      private static boolean loaded
    • nativeLibraryPath

      private static String nativeLibraryPath
    • nativeLibrarySourceUrl

      private static String nativeLibrarySourceUrl
  • Constructor Details

    • JLineNativeLoader

      public JLineNativeLoader()
  • Method Details

    • initialize

      public static boolean initialize()
      Loads the JLine native library for the current platform.

      This method should be called before using any JLine features that require native support. It handles the discovery, extraction, and loading of the appropriate native library.

      The method is thread-safe and idempotent - calling it multiple times has no additional effect after the first successful call. A background thread is started to clean up old native library files from previous runs.

      If the library cannot be loaded, a RuntimeException is thrown with detailed information about the failure, including the OS, architecture, and paths that were searched.

      Example usage:

       try {
           JLineNativeLoader.initialize();
           // JLine features that require native support can be used here
       } catch (RuntimeException e) {
           // Handle the case where native library cannot be loaded
           System.err.println("JLine native support not available: " + e.getMessage());
       }
       
      Returns:
      True if the JLine native library is successfully loaded; this will always be true if the method returns normally, as it throws an exception on failure.
      Throws:
      RuntimeException - If the native library cannot be loaded for any reason.
    • getNativeLibraryPath

      public static String getNativeLibraryPath()
      Returns the absolute path to the loaded native library file.

      This method can be used to determine which specific native library file was successfully loaded. It's particularly useful for debugging and logging purposes.

      Note: This method will return null if called before initialize() or if the library failed to load.

      Returns:
      The absolute path to the loaded native library file, or null if the library hasn't been loaded.
    • getNativeLibrarySourceUrl

      public static String getNativeLibrarySourceUrl()
      Returns the source URL from which the native library was loaded.

      This is typically a jar:file: URL pointing to the location within the JAR file from which the native library was extracted. This information can be useful for debugging and logging purposes.

      Note: This method will return null if called before initialize() or if the library failed to load, or if the library was loaded from the filesystem rather than extracted from a JAR.

      Returns:
      The source URL of the loaded native library, or null if not applicable or if the library hasn't been loaded.
    • getTempDir

      private static File getTempDir()
      Returns the temporary directory used for extracting native libraries.

      The directory is determined by checking the following system properties in order:

      1. jline.tmpdir - Custom JLine-specific temporary directory
      2. java.io.tmpdir - Standard Java temporary directory
      Returns:
      A File object representing the temporary directory.
    • cleanup

      static void cleanup()
      Cleans up old native library files from previous runs.

      This method is called automatically by initialize() to remove old native library files that might have been left behind, particularly on Windows where DLL files are not always properly removed on JVM exit (see bug #80).

      The cleanup process:

      1. Scans the temporary directory for files matching the pattern "jlinenative-[version]*"
      2. Checks if each file has an associated lock file (.lck extension)
      3. Deletes files that don't have an associated lock file, as they are from previous runs

      This method is run in a low-priority daemon thread to avoid impacting application startup time.

    • readNBytes

      private static int readNBytes(InputStream in, byte[] b) throws IOException
      Throws:
      IOException
    • contentsEquals

      private static String contentsEquals(InputStream in1, InputStream in2) throws IOException
      Throws:
      IOException
    • extractAndLoadLibraryFile

      private static boolean extractAndLoadLibraryFile(String libFolderForCurrentOS, String libraryFileName, String targetFolder)
      Extracts a native library from the JAR file and loads it.

      This method handles the process of extracting a native library from within the JAR file to a temporary location on the filesystem, and then loading it using System.load(String).

      The extraction process includes several important steps:

      1. Creating a unique filename for the extracted library to avoid conflicts
      2. Creating a lock file to indicate that the library is in use
      3. Extracting the library content from the JAR to the temporary file
      4. Setting appropriate file permissions (readable, writable, executable)
      5. Verifying that the extraction was successful by comparing file contents
      6. Loading the extracted library using System.load(String)

      The extracted files are marked for deletion on JVM exit using File.deleteOnExit(), but on some platforms (particularly Windows), this may not always work reliably.

      Parameters:
      libFolderForCurrentOS - The path within the JAR file to the native library for the current OS/architecture.
      libraryFileName - The filename of the native library.
      targetFolder - The target folder where the library will be extracted.
      Returns:
      True if the library was successfully extracted and loaded; false otherwise.
    • randomUUID

      private static String randomUUID()
    • newExclusiveStream

      static OutputStream newExclusiveStream(File file) throws IOException
      Opens an output stream that creates a brand new file, failing if the path already exists. CREATE_NEW maps to an exclusive create at the OS level, so a symlink or a regular file planted at the target path in the shared temp directory is rejected rather than followed.
      Throws:
      IOException
    • copy

      private static void copy(InputStream in, OutputStream out) throws IOException
      Throws:
      IOException
    • loadNativeLibrary

      private static boolean loadNativeLibrary(File libPath)
      Loads a native library from a specific file path.

      This method attempts to load a native library using System.load(String), which requires an absolute path to the library file. If successful, it sets the nativeLibraryPath field to the absolute path of the loaded library.

      The method handles the following cases:

      • If the file doesn't exist, it returns false without attempting to load
      • If loading fails with an UnsatisfiedLinkError, it logs the error and returns false
      • If loading succeeds, it sets the path and returns true
      Parameters:
      libPath - A File object representing the absolute path to the native library file.
      Returns:
      True if the library was successfully loaded; false otherwise.
    • loadJLineNativeLibrary

      private static void loadJLineNativeLibrary() throws Exception
      Core method that handles the JLine native library loading process.

      This method implements the library loading strategy, attempting to load the native library from various locations in a specific order. It's called by initialize() and should not be called directly.

      The loading process follows this sequence:

      1. If the library is already loaded, return immediately
      2. Try loading from the custom path specified by library.jline.path system property:
        • First check [library.jline.path]/[os]/[arch]/[library.name]
        • Then check [library.jline.path]/[library.name]
      3. Try extracting and loading from the JAR file's embedded native libraries
      4. Try loading from each path in the java.library.path system property
      5. If all attempts fail, throw an exception with detailed information
      Throws:
      Exception - If the native library cannot be loaded from any location. The exception includes details about the OS, architecture, and paths searched.
    • hasResource

      private static boolean hasResource(String path)
    • getMajorVersion

      public static int getMajorVersion()
      Returns the major version number of the JLine library.

      This method extracts the major version number from the full version string. For example, if the version is "3.21.0", this method returns 3.

      The version information is read from the Maven POM properties file in the JAR. If the version cannot be determined, 1 is returned as a default value.

      Returns:
      The major version number of the JLine library, or 1 if it cannot be determined.
      See Also:
    • getMinorVersion

      public static int getMinorVersion()
      Returns the minor version number of the JLine library.

      This method extracts the minor version number from the full version string. For example, if the version is "3.21.0", this method returns 21.

      The version information is read from the Maven POM properties file in the JAR. If the version cannot be determined or doesn't have a minor component, 0 is returned as a default value.

      Returns:
      The minor version number of the JLine library, or 0 if it cannot be determined.
      See Also:
    • getVersion

      public static String getVersion()
      Returns the full version string of the JLine library.

      This method retrieves the version information from the Maven POM properties file in the JAR at "/META-INF/maven/org.jline/jline-native/pom.properties".

      The version string is cleaned to include only numeric values and dots (e.g., "3.21.0"). If the version information cannot be determined (e.g., the properties file is missing or cannot be read), "unknown" is returned.

      This version information is used in the naming of temporary native library files to ensure proper versioning and avoid conflicts between different JLine versions.

      Returns:
      The version string of the JLine library, or "unknown" if it cannot be determined.
    • join

      private static String join(List<String> list, String separator)
    • log

      private static void log(Level level, String message, Throwable t)