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

org.broadinstitute.pgen.NativeLibraryUtils Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2023, Broad Institute, Inc. All rights reserved.
 */

package org.broadinstitute.pgen;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.SystemUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;

/**
 * Utilities to provide architecture-dependent native functions
 * 
 * IMPORTANT: be careful when modifiying this code, since most of it is used to extract a resource from a jar,
 * and as a result is neither covered by tests, nor ever executed by this project. It is only used to load
 * the native components when the jar produced by this project is used in another project.
 */
public final class NativeLibraryUtils {

    private NativeLibraryUtils(){}

    private record Resource(String path, Class relativeClass) {
        /**
         * Get the contents of this resource as an InputStream
         * @throws IllegalArgumentException if resource cannot be read
         * @return an input stream that will read the contents of this resource
         */
        public InputStream getResourceContentsAsStream() {
            //final Class clazz = getRelativeClass();

            final InputStream inputStream;
            if (relativeClass == null) {
                inputStream = ClassLoader.getSystemResourceAsStream(path);
                if (inputStream == null)
                    throw new IllegalArgumentException("Resource not found: " + path);
            } else {
                inputStream = relativeClass.getResourceAsStream(path);
                if (inputStream == null)
                    throw new IllegalArgumentException("Resource not found relative to " + relativeClass + ": " + path);

            }

            return inputStream;
        }

        /**
         * Writes the an embedded resource to a file.
         * File is not scheduled for deletion and must be cleaned up by the caller.
         * @param resource Embedded resource.
         * @param file File path to write.
         */
        public void writeResource(File file) {
            InputStream inputStream = getResourceContentsAsStream();
            OutputStream outputStream = null;
            try {
                outputStream = FileUtils.openOutputStream(file);
                org.apache.commons.io.IOUtils.copy(inputStream, outputStream);
            } catch (IOException e) {
                throw new RuntimeException(String.format("Unable to copy resource '%s' to '%s'", path, file), e);
            } finally {
                org.apache.commons.io.IOUtils.closeQuietly(inputStream);
                org.apache.commons.io.IOUtils.closeQuietly(outputStream);
            }
        }
    }

    /**
     * @return true if we're running on a Mac operating system, otherwise false
     */
    public static boolean runningOnMac() {
        return SystemUtils.IS_OS_MAC;
    }

    /**
     * @return true if we're running on a Linux operating system, otherwise false
     */
    public static boolean runningOnLinux() {
        return SystemUtils.IS_OS_LINUX;
    }

    /**
     * Loads a native library stored on our classpath by extracting it to a temporary location and invoking
     * {@link System#load} on it
     *
     * @param libraryPathInJar absolute path to the library file on the classpath
     * @return true if the library was extracted and loaded successfully, otherwise false
     */
    public static boolean loadLibraryFromClasspath( final String libraryPathInJar ) {
    //    Utils.nonNull(libraryPathInJar);
    //    Utils.validateArg(libraryPathInJar.startsWith("/"), "library path in jar must be absolute");

        try {
            final File extractedLibrary = writeTempResourceFromPath(libraryPathInJar, NativeLibraryUtils.class);
            extractedLibrary.deleteOnExit();
            System.load(extractedLibrary.getAbsolutePath());
        }
        catch ( UnsatisfiedLinkError e ) {
            return false;
        }

        return true;
    }

    /**
     * Create a resource from a path and a relative class, and write it to a temporary file.
     * If the relative class is null then the system classloader will be used and the path must be absolute.
     * The temporary file is automatically scheduled for deletion on exit.
     * @param resourcePath Relative or absolute path to the class.
     * @param relativeClass Relative class to use as a class loader and for a relative package.
     * @return a temporary file containing the contents of the resource, which is automatically scheduled
     * for deletion on exit.
     */
    private static File writeTempResourceFromPath(final String resourcePath, final Class relativeClass) {
        //Utils.nonNull(resourcePath, "A resource path must be provided");
        try {
            final Resource resource = new Resource(resourcePath, relativeClass);
            final File tmpDir = createTempDir("nativeResource");
            final File tempFile = File.createTempFile(FilenameUtils.getBaseName(resource.path()), "." + FilenameUtils.getExtension(resource.path()), tmpDir);
            tempFile.deleteOnExit();

            resource.writeResource(tempFile);
            return tempFile;
        } catch (final IOException e) {
            throw new RuntimeException("failure to write resource", e);
        }
    }

    /**
     * Creates a temp directory with the given prefix.
     *
     * The directory and any contents will be automatically deleted at shutdown.
     *
     * This will not work if the temp dir is not representable as a File.
     *
     * @param prefix       Prefix for the directory name.
     * @return The created temporary directory.
     */
    //@VisibleForTesting
    static File createTempDir(String prefix) {
        try {
            final Path tmpDir = Files.createTempDirectory(prefix).normalize();
            tmpDir.toFile().deleteOnExit();
            return tmpDir.toFile();
        } catch (final IOException | SecurityException e) {
            throw new RuntimeException(String.format(
                "Bad tmp dir: %s", e.getMessage()), e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy