Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Glassfish native library loading (.dll, .so)

I am using the recently released Glassfish v3 and while using native libraries glassfish would intermittently complain

glassfish SEVERE: java.lang.UnsatisfiedLinkError: 
Native Library already loaded in another classloader

The procedure to load native libraries in the previous glassfish release (v2.2) was to simply put the .dll files in GLASSFISH_HOME\lib. Now I dont know if there is such a magic folder in v3 and if there is do tell. I have also checked the admin screen and there are two variables I think are related to my problem: Native Library Path Prefix and Native Library Path Suffix. I have been scouring the internet to find an adequate description of what they do and how I should use them but apparently no-one likes to talk about them.

like image 481
mglmnc Avatar asked Dec 13 '09 10:12

mglmnc


2 Answers

java.lang.UnsatisfiedLinkError: Native Library already loaded in another classloader

A native lib can only be loaded once in the JVM and you'll get that error message whenever you load a new version of the calling class (the class where the System.loadLibrary(String) call resides) on a redeploy. More on this below.

The procedure to load native libraries in the previous glassfish release (v2.2) was to simply put the .dll files in GLASSFISH_HOME\lib.

Well, this is actually only the first part of the story. To load a native library, you have of course to put it on the library path and to load it from the Java code. To do so, the convention is to include a static initializer like this:

class FooWrapper {
    static {
        System.loadLibrary("foo");
    }

    native void doFoo();
    }
}

Assuming you are working with a web application, a best practice is to not place the native libraries OR their JNI interfaces under WEB-INF/lib or WEB-INF/classes to avoid problems when reloading the application, as mentioned above. In other words, the class that calls System.loadLibrary(String) should be loaded by a classloader that is not affected by reloading the web application itself.

So my question is: where did you put that code?

PS: Another option would be to check if the dll is already available before to load it but I wouldn't do that.

like image 59
Pascal Thivent Avatar answered Nov 01 '22 20:11

Pascal Thivent


First thing: a given native class can only be loaded into one class loader.

Second thing: each web app in a servlet container has its own class loader.

Third thing: you have to be very careful in coding native code to allow its classes to be garbage collected.

Result: once you load native code into a webapp, you are likely to get these errors if you try to unload and reload it.

I am, to some extent, skipping the really simple variation on this theme: simply loading two different webapps with the same native class.

Some folks prefer to load native code in the system class loader to stay out of this problem.

like image 33
bmargulies Avatar answered Nov 01 '22 20:11

bmargulies