Ovi Faur
Ovi Faur

Reputation: 528

Shared JNI library (.so) in Tomcat - UnsatisfiedLinkError

I have a JNI library (.so) shared between two web applications deployed in Tomcat7. I am loading the library using the System.loadLibrary only once in the first web application that is being deployed and then in the second I'm checking if it already was loaded to not load anymore (I tried loading it in both and I got UnsatisfiedLinkError - library was loaded by another classloader). I can make any call to the native library in the first application, but in the second one I get UnsatisfiedLinkError with the method name that I am trying to call.

I am running out of ideas of what I can do. Any ideas? I tried most of the solutions on SO. Thank you.

EDIT Yes, I tried adding the library in the tomcat lib folder and loading it from there. Initially it was in the bin folder and the same issue occurs.

Upvotes: 3

Views: 3359

Answers (4)

isapir
isapir

Reputation: 23463

Tomcat has a built-in solution for this issue as of versions 9.0.13, 8.5.35, and 7.0.92:

1) Use the JniLifecycleListener to load the native library.

2) Use the loadLibrary() or load() from org.apache.tomcat.jni.Library instead of System.

See more details and examples in my answer at java.lang.UnsatisfiedLinkError: Native Library XXX.so already loaded in another classloader

Upvotes: 0

kuhajeyan
kuhajeyan

Reputation: 11017

Yes, this will happen when you try to load the library that has already loaded my another web application. Tomcat, uses separate class loaders for each of the web application, and it wont allow you load a same native library more than once to JVM via another class loader

Move any share jar files if any that consumes JNI from you sharedlib.so. Add the system path to sharedlib ,

export LD_LIBRARY_PATH=/path/to/whereyourlinklibrary

Write a simple class like this which enables you to load your shared library when tomcat starts. Just compile this class and drop it in tomcat lib folder

package msm;
public class DLLBootstrapper {

     static {
      System.loadLibrary("sharedlib");
     }

     public static void main(String args[]) {
      System.out.println("Loaded");
     }

    }

you can now load this class from any of your web application ( probably in startup listener)

Class.forName("msm.DLLBootstrapper");

Good to go!

Upvotes: 2

Michael-O
Michael-O

Reputation: 18430

You need to load any native code from within the server classloader and not the webapp classloader. I recommend to write a Listener which loads the binary image of the shared object into the VM. This will happens only once. Please see the AprLifecycleListener on how to properly do that. It included a JNI compnent which likely represents you case exactly.

The shared object has to reside in ${catalina.home}/lib and LD_LIBRARY_PATH hat to point to it.

Upvotes: 0

Ankit Tripathi
Ankit Tripathi

Reputation: 405

Have you tried putting shared JNI library just inside the lib directory of server.It should be shared by all the web applications deployed.

Upvotes: 0

Related Questions