I have deployed one web-application, which contains following code.
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
Now, I de
As of Tomcat versions 9.0.13
, 8.5.35
, and 7.0.92
we have added the following options to address this issue BZ-62830:
1) Use the JniLifecycleListener to load the native library.
e.g. to load the opencv_java343
library, you can use:
<Listener className="org.apache.catalina.core.JniLifecycleListener"
libraryName="opencv_java343" />
2) Use the load() or loadLibrary() from org.apache.tomcat.jni.Library instead of System
.
e.g.
org.apache.tomcat.jni.Library.loadLibrary("opencv_java343");
Using either of those options will use the Common ClassLoader to load the native library, and therefore it will be available to all of the Web Apps.
I got stuck on this exact problem.
Adding listener in Tomcat (v8.5.58) server.xml file seems to successfully load the dll file (at least the log says so) when Tomcat starts, but when you call the the native method, it fails with java.lang.UnsatisfiedLinkError.
With or without calling "org.apache.tomcat.jni.Library.loadLibrary("TeighaJavaCore");" in my java code makes no difference, same error remain. I include tomcat-jni dependency in my project to enable the "org.apache.tomcat.jni.Library.loadLibrary("TeighaJavaCore")" call. While, I guess there is no need to call "org.apache.tomcat.jni.Library.loadLibrary("TeighaJavaCore")" in java code (at web application level) as the TeighaJavaCore.dll will be automatically loaded when Tomcat starts (because the listener above is defined for this purpose at Tomcat container level)
I also check the source code of "org.apache.tomcat.jni.Library.loadLibrary" here, it simply calls "System.loadLibrary(libname)".
https://github.com/apache/tomcat-native/blob/master/java/org/apache/tomcat/jni/Library.java
The problem is with how OpenCV handles the initialization of the native library.
Usually a class that uses a native library will have a static initializer that loads the library. This way the class and the native library will always be loaded in the same class loader. With OpenCV the application code loads the native library.
Now there's the restriction that a native library can only be loaded in one class loader. Web applications use their own class loader so if one web application has loaded a native library, another web application cannot do the same. Therefore code loading native libraries cannot be put in a webapp directory but must be put in the container's (Tomcat) shared directory. When you have a class written with the usual pattern above (loadLibrary
in static initializer of using class) it's enough to put the jar containing the class in the shared directory. With OpenCV and the loadLibrary
call in the web application code however, the native library will still be loaded in the "wrong" class loader and you will get the UnsatisfiedLinkError
.
To make the "right" class loader load the native library you could create a tiny class with a single static method doing only the loadLibrary
. Put this class in an extra jar and put this jar in the shared Tomcat directory. Then in the web applications replace the call to System.loadLibrary
with a call to your new static method. This way the class loaders for the OpenCV classes and their native library will match and the native methods can be initialized.
Edit: example as requested by a commenter
instead of
public class WebApplicationClass {
static {
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
}
}
use
public class ToolClassInSeparateJarInSharedDirectory {
public static void loadNativeLibrary() {
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
}
}
public class WebApplicationClass {
static {
ToolClassInSeparateJarInSharedDirectory.loadNativeLibrary();
}
}
As of javacpp>=1.3 you may also change the cache folder (defined by system property) in your war deployment listener:
System.setProperty("org.bytedeco.javacpp.cachedir",
Files.createTempDirectory( "javacppnew" ).toString());
Note though that native libraries are always unpacked and will be loaded several times (because considered as different libs).