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

org.scijava.nativelib.NativeLoader Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
/*
 * #%L
 * Native library loader for extracting and loading native libraries from Java.
 * %%
 * Copyright (C) 2010 - 2015 Board of Regents of the University of
 * Wisconsin-Madison and Glencoe Software, Inc.
 * %%
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * #L%
 */

// This code is derived from Richard van der Hoff's mx-native-loader project:
// http://opensource.mxtelecom.com/maven/repo/com/wapmx/native/mx-native-loader/1.7/
// See NOTICE.txt for details.

// Copyright 2006 MX Telecom Ltd

package org.scijava.nativelib;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * Provides a means of loading JNI libraries which are stored within a jar.
 * 

* The library is first extracted to a temporary file, and then loaded with * System.load(). *

* The extractor implementation can be replaced, but the default implementation * expects to find the library in natives/, with its OS-dependent name. It * extracts the library underneath a temporary directory, whose name is given by * the System property "java.library.tmpdir", defaulting to "tmplib". *

* This is complicated by Java's library and version management - specifically * "The same JNI native library cannot be loaded into more than one class loader" * . In practice this appears to mean * "A JNI library on a given absolute path cannot be loaded by more than one classloader" * . Native libraries that are loaded by the OS dynamic linker as dependencies * of JNI libraries are not subject to this restriction. *

* Native libraries that are loaded as dependencies must be extracted using the * library identifier a.k.a. soname (which usually includes a major version * number) instead of what was linked against (this can be found using ldd on * linux or using otool on OS X). Because they are loaded by the OS dynamic * linker and not by explicit invocation within Java, this extractor needs to be * aware of them to extract them by alternate means. This is accomplished by * listing the base filename in a META-INF/lib/AUTOEXTRACT.LIST classpath * resource. This is useful for shipping libraries which are used by code which * is not itself aware of the NativeLoader system. The application must call * {@link #extractRegistered()} at some suitably early point in its * initialization (before loading any JNI libraries which might require these * dependencies), and ensure that JVM is launched with the LD_LIBRARY_PATH * environment variable (or other OS-dependent equivalent) set to include the * "tmplib" directory (or other directory as overridden by "java.library.tmpdir" * as above). * * @author Richard van der Hoff ([email protected]) */ public class NativeLoader { private static JniExtractor jniExtractor = null; static { try { /* * We provide two implementations of JniExtractor * * The first will work with transitively, dynamically linked libraries with shared global variables * (e.g. dynamically linked c++) but can only be used by one ClassLoader in the JVM. * * The second can be used by multiple ClassLoaders in the JVM but will only work if global variables * are not shared between transitively, dynamically linked libraries. * * For convenience we assume that if the NativeLoader is loaded by the system ClassLoader then it should be * use the first form, and that if it is loaded by a different ClassLoader then it should use the second. */ if (NativeLoader.class.getClassLoader() == ClassLoader .getSystemClassLoader()) { jniExtractor = new DefaultJniExtractor(null); } else { jniExtractor = new WebappJniExtractor("Classloader"); } } catch (final IOException e) { throw new ExceptionInInitializerError(e); } } /** * Extract the given library from a jar, and load it. *

* The default jni extractor expects libraries to be in natives/<platform>/ * with their platform-dependent name (e.g. natives/osx_64/libnative.dylib). *

* If natives/ does not exists or does not contain the directory structure, * <platform>/<lib_binary> will be searched in the root, * META-INF/lib/ and searchPaths. * * @param libname platform-independent library name (as would be passed to * System.loadLibrary) * @param searchPaths a list of additional paths relative to the jar's root * to search for the specified native library in case it does not * exist in natives/, root or META-INF/lib/ * @throws IOException if there is a problem extracting the jni library * @throws SecurityException if a security manager exists and its * checkLink method doesn't allow loading of the * specified dynamic library */ public static void loadLibrary(final String libname, final String... searchPaths) throws IOException { try { // try to load library from classpath System.loadLibrary(libname); return; } catch (UnsatisfiedLinkError e) { List libPaths = searchPaths == null ? new LinkedList() : new LinkedList(Arrays.asList(searchPaths)); libPaths.add(0, NativeLibraryUtil.DEFAULT_SEARCH_PATH); // for backward compatibility libPaths.add(1, ""); libPaths.add(2, "META-INF" + NativeLibraryUtil.DELIM + "lib"); // NB: Although the documented behavior of this method is to load // native library from META-INF/lib/, what it actually does is // to load from the root dir. See: https://github.com/scijava/ // native-lib-loader/blob/6c303443cf81bf913b1732d42c74544f61aef5d1/ // src/main/java/org/scijava/nativelib/NativeLoader.java#L126 // search in each path in {natives/, /, META-INF/lib/, ...} for (String libPath : libPaths) { File extracted = jniExtractor.extractJni( NativeLibraryUtil.getPlatformLibraryPath(libPath), libname); if (extracted != null) { System.load(extracted.getAbsolutePath()); return; } } } throw new IOException("Couldn't load library library " + libname); } /** * Extract all libraries registered for auto-extraction by way of * META-INF/lib/AUTOEXTRACT.LIST resources. The application must call * {@link #extractRegistered()} at some suitably early point in its * initialization if it is using libraries packaged in this way. * * @throws IOException if there is a problem extracting the libraries */ public static void extractRegistered() throws IOException { jniExtractor.extractRegistered(); } /** * @return the JniExtractor implementation object. */ public static JniExtractor getJniExtractor() { return jniExtractor; } /** * @param jniExtractor JniExtractor implementation to use instead of the * default. */ public static void setJniExtractor(final JniExtractor jniExtractor) { NativeLoader.jniExtractor = jniExtractor; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy