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-1: module: %s -> %s%n", nativeJarBasename, nativeJarURI);
221 ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath);
223 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-1: OK "+ok+
": %s -> %s%n", nativeJarURI, nativeLibraryPath);
225 }
catch(
final Exception e) {
227 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-1: Caught %s%n", e.getMessage());
233 final ClassLoader cl = classFromJavaJar.getClassLoader();
237 final URL nativeLibraryURI = cl.getResource(nativeLibraryPath);
238 if (
null != nativeLibraryURI) {
239 final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(jarBasename) );
241 ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath);
243 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-2: OK "+ok+
", fat: %s -> %s%n", nativeJarURI, nativeLibraryPath);
245 }
catch(
final Exception e) {
247 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-2: Caught %s%n", e.getMessage());
252 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-2: CL couldn't locate %s in %s%n", nativeLibraryPath, jarBasename);
259 final String moduleName;
261 final String packageName = classFromJavaJar.getPackage().getName();
262 final int idx = packageName.lastIndexOf(
'.');
264 moduleName = packageName.substring(idx+1);
266 moduleName = packageName;
269 final String os_and_arch_dot = PlatformPropsImpl.os_and_arch.replace(
'-',
'.');
270 final String nativeJarTagClassName = nativeJarTagPackage +
"." + moduleName +
"." + os_and_arch_dot +
".TAG";
273 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-3: ClassLoader/TAG: Locating module %s, os.and.arch %s: %s%n",
274 moduleName, os_and_arch_dot, nativeJarTagClassName);
276 final Uri nativeJarTagClassJarURI = JarUtil.getJarUri(nativeJarTagClassName, cl);
278 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-3: ClassLoader/TAG: %s -> %s%n", nativeJarTagClassName, nativeJarTagClassJarURI);
280 ok = TempJarCache.addNativeLibs(classFromJavaJar, nativeJarTagClassJarURI, nativeLibraryPath);
282 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-3: OK "+ok+
": %s -> %s%n", nativeJarTagClassJarURI, nativeLibraryPath);
284 }
catch (
final Exception e ) {
286 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl-3: Caught %s%n", e.getMessage());
294 final long tNow = System.currentTimeMillis() - t0;
295 final long tTotal, tCount;
296 synchronized(perfSync) {
297 tCount = perfCount+1;
298 tTotal = perfTotal + tNow;
302 final double tAvrg = tTotal / (double)tCount;
303 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsImpl.X: %s / %s -> ok: %b; duration: now %d ms, total %d ms (count %d, avrg %.3f ms)%n",
304 jarBasename, nativeJarBasename, ok, tNow, tTotal, tCount, tAvrg);
403 public static boolean addNativeJarLibs(
final Class<?>[] classesFromJavaJars,
final String singleJarMarker) {
405 final StringBuilder msg =
new StringBuilder();
406 msg.append(
"JNILibLoaderBase: addNativeJarLibs(").append(PlatformPropsImpl.NEWLINE);
407 msg.append(
" classesFromJavaJars = ").append(Arrays.asList(classesFromJavaJars)).append(PlatformPropsImpl.NEWLINE);
408 msg.append(
" singleJarMarker = ").append(singleJarMarker).append(PlatformPropsImpl.NEWLINE);
410 System.err.println(msg.toString());
415 ok = addNativeJarLibsWithTempJarCache(classesFromJavaJars, singleJarMarker);
417 System.err.println(
"JNILibLoaderBase: addNativeJarLibs0: disabled due to uninitialized TempJarCache");
422 private static boolean addNativeJarLibsWithTempJarCache(
final Class<?>[] classesFromJavaJars,
final String singleJarMarker) {
426 boolean done =
false;
429 for (
int i = 0; i < classesFromJavaJars.length; ++i) {
430 final Class<?> c = classesFromJavaJars[i];
435 final ClassLoader cl = c.getClassLoader();
436 final Uri classJarURI = JarUtil.getJarUri(c.getName(), cl);
437 final Uri.Encoded jarName = JarUtil.getJarBasename(classJarURI);
439 if (jarName ==
null) {
443 final Uri.Encoded jarBasename = jarName.substring(0, jarName.indexOf(
".jar"));
446 System.err.printf(
"JNILibLoaderBase: jarBasename: %s%n", jarBasename);
454 if (singleJarMarker !=
null) {
455 if (jarBasename.indexOf(singleJarMarker) >= 0) {
460 final Uri.Encoded nativeJarBasename =
461 Uri.Encoded.cast( String.format((Locale)
null,
"%s-natives-%s.jar", jarBasename.get(), PlatformPropsImpl.os_and_arch) );
463 ok = JNILibLoaderBase.addNativeJarLibsImpl(c, classJarURI, jarName, nativeJarBasename);
468 System.err.printf(
"JNILibLoaderBase: addNativeJarLibs0: done: %s%n", jarBasename);
471 }
catch (
final Exception x) {
472 System.err.printf(
"JNILibLoaderBase: Caught %s: %s%n", x.getClass().getSimpleName(), x.getMessage());
479 System.err.printf(
"JNILibLoaderBase: addNativeJarLibsWhenInitialized: count %d, ok %b%n", count, ok);
492 protected static synchronized boolean loadLibrary(
final String libname,
final boolean ignoreError,
final ClassLoader cl) {
493 if (loaderAction !=
null) {
494 return loaderAction.loadLibrary(libname, ignoreError, cl);
508 protected static synchronized void loadLibrary(
final String libname,
final String[] preload,
final boolean preloadIgnoreError,
final ClassLoader cl) {
509 if (loaderAction !=
null) {
510 loaderAction.loadLibrary(libname, preload, preloadIgnoreError, cl);
515 private static final Method customLoadLibraryMethod;
518 final String sunAppletLauncherProperty =
"sun.jnlp.applet.launcher";
519 final String sunAppletLauncherClassName =
"org.jdesktop.applet.util.JNLPAppletLauncher";
523 public Method run() {
527 Class<?> launcherClass =
null;
528 Method loadLibraryMethod =
null;
530 if (usingJNLPAppletLauncher) {
532 launcherClass = Class.forName(sunAppletLauncherClassName);
533 }
catch (
final ClassNotFoundException cnfe) {
536 System.err.println(
"JNILibLoaderBase: <"+sunAppletLauncherClassName+
"> not found, despite enabled property <"+sunAppletLauncherProperty+
">, JNLPAppletLauncher was probably used before");
537 System.setProperty(sunAppletLauncherProperty, Boolean.FALSE.toString());
538 }
catch (
final LinkageError le) {
541 if(
null != launcherClass) {
543 loadLibraryMethod = launcherClass.getDeclaredMethod(
"loadLibrary",
new Class[] { String.class });
544 }
catch (
final NoSuchMethodException ex) {
546 ex.printStackTrace();
548 launcherClass =
null;
552 if(
null==launcherClass) {
553 final String launcherClassName = PropertyAccess.getProperty(
"jnlp.launcher.class",
false);
554 if(
null!=launcherClassName) {
556 launcherClass = Class.forName(launcherClassName);
557 loadLibraryMethod = launcherClass.getDeclaredMethod(
"loadLibrary",
new Class[] { String.class });
558 }
catch (
final ClassNotFoundException ex) {
560 ex.printStackTrace();
562 }
catch (
final NoSuchMethodException ex) {
564 ex.printStackTrace();
566 launcherClass =
null;
570 return loadLibraryMethod;
572 customLoadLibraryMethod = loadLibraryMethod;
575 private static void loadLibraryInternal(
final String libraryName,
final ClassLoader cl) {
578 if (
null!=customLoadLibraryMethod && !libraryName.equals(
"jawt")) {
581 System.err.println(
"JNILibLoaderBase: customLoad("+libraryName+
") - mode 1");
584 customLoadLibraryMethod.invoke(
null,
new Object[] { libraryName });
586 }
catch (
final Exception e) {
588 if (t instanceof InvocationTargetException) {
589 t = ((InvocationTargetException) t).getTargetException();
591 if (t instanceof Error) {
594 if (t instanceof RuntimeException) {
595 throw (RuntimeException) t;
598 throw (UnsatisfiedLinkError)
new UnsatisfiedLinkError(
"can not load library "+libraryName).initCause(e);
602 final String libraryPath = NativeLibrary.findLibrary(libraryName, cl);
604 System.err.println(
"JNILibLoaderBase: loadLibraryInternal("+libraryName+
"), TempJarCache: "+libraryPath);
606 if(
null != libraryPath) {
608 System.err.println(
"JNILibLoaderBase: System.load("+libraryPath+
") - mode 2");
610 System.load(libraryPath);
614 System.err.println(
"JNILibLoaderBase: System.loadLibrary("+libraryName+
") - mode 3: SystemEnvLibraryPaths: "+NativeLibrary.getSystemEnvLibraryPaths());
617 System.loadLibrary(libraryName);
619 }
catch (
final UnsatisfiedLinkError ex1) {
621 System.err.println(
"ERROR mode 3 - "+ex1.getMessage());
623 final List<NativeLibrary.LibPath> possiblePaths = NativeLibrary.enumerateLibraryPaths(libraryName, libraryName, libraryName, cl);
625 for (
final Iterator<NativeLibrary.LibPath> iter = possiblePaths.iterator(); 0 == mode && iter.hasNext(); ) {
626 final NativeLibrary.LibPath path = iter.next();
628 System.err.println(
"JNILibLoaderBase: System.load("+path+
") - mode 4");
631 System.load(path.path);
633 }
catch (
final UnsatisfiedLinkError ex2) {
635 System.err.println(
"n/a - "+ex2.getMessage());
637 if(!iter.hasNext()) {
639 throw new UnsatisfiedLinkError(
"Couldn't load library '"+libraryName+
640 "' generically including "+NativeLibrary.getSystemEnvLibraryPaths()+
641 ", nor as "+possiblePaths);
649 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.