40package com.jogamp.common.jvm;
42import java.io.IOException;
43import java.lang.reflect.InvocationTargetException;
44import java.lang.reflect.Method;
45import java.net.URISyntaxException;
47import java.security.PrivilegedAction;
48import java.util.Arrays;
49import java.util.HashSet;
50import java.util.Iterator;
52import java.util.Locale;
54import com.jogamp.common.net.Uri;
55import com.jogamp.common.os.NativeLibrary;
56import com.jogamp.common.util.JarUtil;
57import com.jogamp.common.util.PropertyAccess;
58import com.jogamp.common.util.SecurityUtil;
59import com.jogamp.common.util.cache.TempJarCache;
61import jogamp.common.Debug;
62import jogamp.common.os.PlatformPropsImpl;
65 public static final boolean DEBUG;
66 protected static final boolean PERF;
69 Debug.initSingleton();
70 DEBUG = Debug.debug(
"JNILibLoader");
74 private static final Object perfSync =
new Object();
75 private static long perfTotal = 0;
76 private static long perfCount = 0;
87 boolean loadLibrary(String libname,
boolean ignoreError, ClassLoader cl);
98 void loadLibrary(String libname, String[] preload,
boolean preloadIgnoreError, ClassLoader cl);
101 private static class DefaultAction
implements LoaderAction {
103 public boolean loadLibrary(
final String libname,
final boolean ignoreError,
final ClassLoader cl) {
107 loadLibraryInternal(libname, cl);
110 System.err.println(
"JNILibLoaderBase: loaded "+libname);
112 }
catch (
final UnsatisfiedLinkError e) {
117 if (!ignoreError && e.getMessage().indexOf(
"already loaded") < 0) {
126 public void loadLibrary(
final String libname,
final String[] preload,
final boolean preloadIgnoreError,
final ClassLoader cl) {
129 for (
int i=0; i<preload.length; i++) {
138 private static final HashSet<String> loaded =
new HashSet<String>();
139 private static LoaderAction loaderAction =
new DefaultAction();
141 public static boolean isLoaded(
final String libName) {
142 return loaded.contains(libName);
148 System.err.println(
"JNILibLoaderBase: Loaded Native Library: "+libName);
161 loaderAction = action;
164 private static final String nativeJarTagPackage =
"jogamp.nativetag";
177 private static final boolean addNativeJarLibsImpl(
final Class<?> classFromJavaJar,
final Uri classJarUri,
179 throws IOException, SecurityException, URISyntaxException
182 final StringBuilder msg =
new StringBuilder();
183 msg.append(
"JNILibLoaderBase: addNativeJarLibsImpl(").append(PlatformPropsImpl.NEWLINE);
184 msg.append(
" classFromJavaJar = ").append(classFromJavaJar).append(PlatformPropsImpl.NEWLINE);
185 msg.append(
" classJarURI = ").append(classJarUri).append(PlatformPropsImpl.NEWLINE);
186 msg.append(
" jarBasename = ").append(jarBasename).append(PlatformPropsImpl.NEWLINE);
187 msg.append(
" os.and.arch = ").append(PlatformPropsImpl.os_and_arch).append(PlatformPropsImpl.NEWLINE);
188 msg.append(
" nativeJarBasename = ").append(nativeJarBasename).append(PlatformPropsImpl.NEWLINE);
190 System.err.println(msg.toString());
192 final long t0 =
PERF ? System.currentTimeMillis() : 0;
196 final Uri jarSubURI = classJarUri.getContainedUri();
197 if (
null == jarSubURI) {
198 throw new IllegalArgumentException(
"JarSubURI is null of: "+classJarUri);
201 final Uri jarSubUriRoot = jarSubURI.getDirectory();
204 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: initial: %s -> %s%n", jarSubURI, jarSubUriRoot);
207 final String nativeLibraryPath = String.format((Locale)
null,
"natives/%s/", PlatformPropsImpl.os_and_arch);
209 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: nativeLibraryPath: %s%n", nativeLibraryPath);
214 final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(nativeJarBasename) );
217 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: module: %s -> %s%n", nativeJarBasename, nativeJarURI);
221 ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath);
222 }
catch(
final Exception e) {
224 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
230 final ClassLoader cl = classFromJavaJar.getClassLoader();
234 final URL nativeLibraryURI = cl.getResource(nativeLibraryPath);
235 if (
null != nativeLibraryURI) {
236 final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(jarBasename) );
238 if( TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath) ) {
241 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: fat: %s -> %s%n", jarBasename, nativeJarURI);
244 }
catch(
final Exception e) {
246 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
256 final String moduleName;
258 final String packageName = classFromJavaJar.getPackage().getName();
259 final int idx = packageName.lastIndexOf(
'.');
261 moduleName = packageName.substring(idx+1);
263 moduleName = packageName;
266 final String os_and_arch_dot = PlatformPropsImpl.os_and_arch.replace(
'-',
'.');
267 final String nativeJarTagClassName = nativeJarTagPackage +
"." + moduleName +
"." + os_and_arch_dot +
".TAG";
270 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: Locating module %s, os.and.arch %s: %s%n",
271 moduleName, os_and_arch_dot, nativeJarTagClassName);
273 final Uri nativeJarTagClassJarURI = JarUtil.getJarUri(nativeJarTagClassName, cl);
275 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: %s -> %s%n", nativeJarTagClassName, nativeJarTagClassJarURI);
277 ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarTagClassJarURI, nativeLibraryPath);
278 }
catch (
final Exception e ) {
280 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl: Caught %s%n", e.getMessage());
288 final long tNow = System.currentTimeMillis() - t0;
289 final long tTotal, tCount;
290 synchronized(perfSync) {
291 tCount = perfCount+1;
292 tTotal = perfTotal + tNow;
296 final double tAvrg = tTotal / (double)tCount;
297 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl.X: %s / %s -> ok: %b; duration: now %d ms, total %d ms (count %d, avrg %.3f ms)%n",
298 jarBasename, nativeJarBasename, ok, tNow, tTotal, tCount, tAvrg);
397 public static boolean addNativeJarLibs(
final Class<?>[] classesFromJavaJars,
final String singleJarMarker) {
399 final StringBuilder msg =
new StringBuilder();
400 msg.append(
"JNILibLoaderBase: addNativeJarLibs(").append(PlatformPropsImpl.NEWLINE);
401 msg.append(
" classesFromJavaJars = ").append(Arrays.asList(classesFromJavaJars)).append(PlatformPropsImpl.NEWLINE);
402 msg.append(
" singleJarMarker = ").append(singleJarMarker).append(PlatformPropsImpl.NEWLINE);
404 System.err.println(msg.toString());
409 ok = addNativeJarLibsWithTempJarCache(classesFromJavaJars, singleJarMarker);
411 System.err.println(
"JNILibLoaderBase: addNativeJarLibs0: disabled due to uninitialized TempJarCache");
416 private static boolean addNativeJarLibsWithTempJarCache(
final Class<?>[] classesFromJavaJars,
final String singleJarMarker) {
420 boolean done =
false;
423 for (
int i = 0; i < classesFromJavaJars.length; ++i) {
424 final Class<?> c = classesFromJavaJars[i];
429 final ClassLoader cl = c.getClassLoader();
430 final Uri classJarURI = JarUtil.getJarUri(c.getName(), cl);
431 final Uri.Encoded jarName = JarUtil.getJarBasename(classJarURI);
433 if (jarName ==
null) {
437 final Uri.Encoded jarBasename = jarName.substring(0, jarName.indexOf(
".jar"));
440 System.err.printf(
"JNILibLoaderBase: jarBasename: %s%n", jarBasename);
448 if (singleJarMarker !=
null) {
449 if (jarBasename.indexOf(singleJarMarker) >= 0) {
454 final Uri.Encoded nativeJarBasename =
455 Uri.Encoded.cast( String.format((Locale)
null,
"%s-natives-%s.jar", jarBasename.get(), PlatformPropsImpl.os_and_arch) );
457 ok = JNILibLoaderBase.addNativeJarLibsImpl(c, classJarURI, jarName, nativeJarBasename);
462 System.err.printf(
"JNILibLoaderBase: addNativeJarLibs0: done: %s%n", jarBasename);
465 }
catch (
final Exception x) {
466 System.err.printf(
"JNILibLoaderBase: Caught %s: %s%n", x.getClass().getSimpleName(), x.getMessage());
473 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsWhenInitialized: count %d, ok %b%n", count, ok);
486 protected static synchronized boolean loadLibrary(
final String libname,
final boolean ignoreError,
final ClassLoader cl) {
487 if (loaderAction !=
null) {
488 return loaderAction.loadLibrary(libname, ignoreError, cl);
502 protected static synchronized void loadLibrary(
final String libname,
final String[] preload,
final boolean preloadIgnoreError,
final ClassLoader cl) {
503 if (loaderAction !=
null) {
504 loaderAction.loadLibrary(libname, preload, preloadIgnoreError, cl);
509 private static final Method customLoadLibraryMethod;
512 final String sunAppletLauncherProperty =
"sun.jnlp.applet.launcher";
513 final String sunAppletLauncherClassName =
"org.jdesktop.applet.util.JNLPAppletLauncher";
517 public Method run() {
521 Class<?> launcherClass =
null;
522 Method loadLibraryMethod =
null;
524 if (usingJNLPAppletLauncher) {
526 launcherClass = Class.forName(sunAppletLauncherClassName);
527 }
catch (
final ClassNotFoundException cnfe) {
530 System.err.println(
"JNILibLoaderBase: <"+sunAppletLauncherClassName+
"> not found, despite enabled property <"+sunAppletLauncherProperty+
">, JNLPAppletLauncher was probably used before");
531 System.setProperty(sunAppletLauncherProperty, Boolean.FALSE.toString());
532 }
catch (
final LinkageError le) {
535 if(
null != launcherClass) {
537 loadLibraryMethod = launcherClass.getDeclaredMethod(
"loadLibrary",
new Class[] { String.class });
538 }
catch (
final NoSuchMethodException ex) {
540 ex.printStackTrace();
542 launcherClass =
null;
546 if(
null==launcherClass) {
547 final String launcherClassName = PropertyAccess.getProperty(
"jnlp.launcher.class",
false);
548 if(
null!=launcherClassName) {
550 launcherClass = Class.forName(launcherClassName);
551 loadLibraryMethod = launcherClass.getDeclaredMethod(
"loadLibrary",
new Class[] { String.class });
552 }
catch (
final ClassNotFoundException ex) {
554 ex.printStackTrace();
556 }
catch (
final NoSuchMethodException ex) {
558 ex.printStackTrace();
560 launcherClass =
null;
564 return loadLibraryMethod;
566 customLoadLibraryMethod = loadLibraryMethod;
569 private static void loadLibraryInternal(
final String libraryName,
final ClassLoader cl) {
572 if (
null!=customLoadLibraryMethod && !libraryName.equals(
"jawt")) {
575 System.err.println(
"JNILibLoaderBase: customLoad("+libraryName+
") - mode 1");
578 customLoadLibraryMethod.invoke(
null,
new Object[] { libraryName });
580 }
catch (
final Exception e) {
582 if (t instanceof InvocationTargetException) {
583 t = ((InvocationTargetException) t).getTargetException();
585 if (t instanceof Error) {
588 if (t instanceof RuntimeException) {
589 throw (RuntimeException) t;
592 throw (UnsatisfiedLinkError)
new UnsatisfiedLinkError(
"can not load library "+libraryName).initCause(e);
596 final String libraryPath = NativeLibrary.findLibrary(libraryName, cl);
598 System.err.println(
"JNILibLoaderBase: loadLibraryInternal("+libraryName+
"), TempJarCache: "+libraryPath);
600 if(
null != libraryPath) {
602 System.err.println(
"JNILibLoaderBase: System.load("+libraryPath+
") - mode 2");
604 System.load(libraryPath);
608 System.err.println(
"JNILibLoaderBase: System.loadLibrary("+libraryName+
") - mode 3: SystemEnvLibraryPaths: "+NativeLibrary.getSystemEnvLibraryPaths());
611 System.loadLibrary(libraryName);
613 }
catch (
final UnsatisfiedLinkError ex1) {
615 System.err.println(
"ERROR mode 3 - "+ex1.getMessage());
617 final List<NativeLibrary.LibPath> possiblePaths = NativeLibrary.enumerateLibraryPaths(libraryName, libraryName, libraryName, cl);
619 for (
final Iterator<NativeLibrary.LibPath> iter = possiblePaths.iterator(); 0 == mode && iter.hasNext(); ) {
620 final NativeLibrary.LibPath path = iter.next();
622 System.err.println(
"JNILibLoaderBase: System.load("+path+
") - mode 4");
625 System.load(path.path);
627 }
catch (
final UnsatisfiedLinkError ex2) {
629 System.err.println(
"n/a - "+ex2.getMessage());
631 if(!iter.hasNext()) {
633 throw new UnsatisfiedLinkError(
"Couldn't load library '"+libraryName+
634 "' generically including "+NativeLibrary.getSystemEnvLibraryPaths()+
635 ", nor as "+possiblePaths);
643 System.err.println(
"JNILibLoaderBase: loadLibraryInternal("+libraryName+
"): OK - mode "+mode);
static final boolean addNativeJarLibsJoglCfg(final Class<?>[] classesFromJavaJars)
Loads and adds a JAR file's native library to the TempJarCache, calling JNILibLoaderBase#addNativeJar...
static final boolean PERF
static synchronized void loadLibrary(final String libname, final String[] preload, final boolean preloadIgnoreError, final ClassLoader cl)
Loads the library specified by libname, using the LoaderAction set by setLoadingAction(LoaderAction).
static boolean addNativeJarLibs(final Class<?>[] classesFromJavaJars, final String singleJarMarker)
Loads and adds a JAR file's native library to the TempJarCache.
static boolean isLoaded(final String libName)
static void addLoaded(final String libName)
static final boolean DEBUG
static void disableLoading()
static synchronized void setLoadingAction(final LoaderAction action)
static synchronized boolean loadLibrary(final String libname, final boolean ignoreError, final ClassLoader cl)
Loads the library specified by libname, using the LoaderAction set by setLoadingAction(LoaderAction).
static void enableLoading()
Immutable RFC3986 encoded string.
This class implements an immutable Uri as defined by RFC 2396.
Helper routines for accessing properties.
static final boolean getBooleanProperty(final String property, final boolean jnlpAlias)
static final boolean isPropertyDefined(final String property, final boolean jnlpAlias)
static< T > T doPrivileged(final PrivilegedAction< T > o)
Call wrapper for java.security.AccessController#doPrivileged(PrivilegedAction).
Static Jar file cache handler using an underlying instance of TempFileCache, see getTempFileCache().
static boolean isInitialized(final boolean forExecutables)
boolean loadLibrary(String libname, boolean ignoreError, ClassLoader cl)
Loads the library specified by libname.
void loadLibrary(String libname, String[] preload, boolean preloadIgnoreError, ClassLoader cl)
Loads the library specified by libname.