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

org.nuiton.j2r.jni.RNative Maven / Gradle / Ivy

/*
 * #%L
 * Nuiton Java-2-R
 * %%
 * Copyright (C) 2006 - 2013 CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */
package org.nuiton.j2r.jni;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Backport code from JNA project to load native file from classpath.
 * 
 * See https://github.com/twall/jna/blob/master/src/com/sun/jna/Native.java
 * 
 * @author Chatellier Eric
 */
public class RNative {

    private static Log log = LogFactory.getLog(RNative.class);

    public static final String RESOURCE_PREFIX;

    public static final boolean IS_WINDOWS;
    
    public static final boolean IS_LINUX;

    static {
        String osName = System.getProperty("os.name");
        IS_WINDOWS = osName.startsWith("Windows");
        IS_LINUX = osName.startsWith("Linux");
        RESOURCE_PREFIX = getNativeLibraryResourcePrefix();
    }

    static String getNativeLibraryResourcePrefix() {
        return getNativeLibraryResourcePrefix(System.getProperty("os.arch"));
    }

    /**
     * Generate a canonical String prefix based on the given OS
     * type/arch/name.
     * 
     * @param arch from os.arch System property
     */
    static String getNativeLibraryResourcePrefix(String arch) {
        String osPrefix;
        arch = arch.toLowerCase().trim();
        if ("x86_64".equals(arch) || "amd64".equals(arch)) {
            arch = "x86-64";
        } else {
            arch = "x86";
        }

        if (IS_WINDOWS) {
            osPrefix = "win32-" + arch;
        } else if (IS_LINUX) {
            osPrefix = "linux-" + arch;
        } else {
            throw new UnsatisfiedLinkError("Unsupported platform/arch");
        }

        return osPrefix;
    }
    
    static boolean loadNativeRLibraryFromClasspath() {
        boolean result = false;
        try {
            String libName = "/" + RESOURCE_PREFIX + "/" + System.mapLibraryName("jri");
            File lib = extractFromResourcePath(libName, RNative.class.getClassLoader());
            if (lib == null) {
                if (lib == null) {
                    throw new UnsatisfiedLinkError("Could not find R native support");
                }
            }

            System.load(lib.getAbsolutePath());
            if (log.isInfoEnabled()) {
                log.info("Loaded jri native library from classpath (" + libName + ")");
            }
            result = true;
        } catch(IOException ex) {
            // can't copy lib file on local filesystem
            throw new UnsatisfiedLinkError(ex.getMessage());
        } catch(UnsatisfiedLinkError ex) {
            // dependency libR.so (or R.dll) not found, R not installed ?
            if (log.isErrorEnabled()) {
                log.error("Can't load jri lib dependencies. R not found or not installed", ex);
            }
        }
        return result;
    }
    
    /**
     * Attempt to extract a native library from the resource path using the
     * given class loader.  
     * @param name Base name of native library to extract.  May also be an
     * absolute resource path (i.e. starts with "/"), in which case the
     * no transformations of the library name are performed.  If only the base
     * name is given, the resource path is attempted both with and without
     * {@code Platform#RESOURCE_PREFIX}, after mapping the library name via
     * {@code NativeLibrary#mapSharedLibraryName(String)}.
     * @param loader Class loader to use to load resources
     * @return File indicating extracted resource on disk
     * @throws IOException if resource not found
     */
    public static File extractFromResourcePath(String name, ClassLoader loader) throws IOException {
        if (loader == null) {
            loader = Thread.currentThread().getContextClassLoader();
            // Context class loader is not guaranteed to be set
            if (loader == null) {
                loader = RNative.class.getClassLoader();
            }
        }

        String resourcePath = name;
        if (resourcePath.startsWith("/")) {
            resourcePath = resourcePath.substring(1);
        }
        InputStream is = loader.getResourceAsStream(resourcePath);
        if (is == null) {
            throw new IOException("Can't obtain InputStream for " + resourcePath);
        }

        File lib = null;
        FileOutputStream fos = null;
        try {
            // Suffix is required on windows, or library fails to load
            // Let Java pick the suffix, except on windows, to avoid
            // problems with Web Start.
            lib = File.createTempFile("nuiton-j2r-", IS_WINDOWS ? ".dll" : null);
            lib.deleteOnExit();
            fos = new FileOutputStream(lib);
            int count;
            byte[] buf = new byte[1024];
            while ((count = is.read(buf, 0, buf.length)) > 0) {
                fos.write(buf, 0, count);
            }
        }
        catch(IOException e) {
            throw new IOException("Failed to create temporary file for " + name + " library: " + e.getMessage());
        }
        finally {
            try { is.close(); } catch(IOException e) { }
            if (fos != null) {
                try { fos.close(); } catch(IOException e) { }
            }
        }
        return lib;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy