Hot questions for Using GlassFish in jna

Question:

I'm having issues deploying a servlet. The servlet uses JNA to load some DLLs, which are placed inside the classpath com.myproject..etc. (e.g. "my_dll.dll"):

public static final MyDllInterface INSTANCE = (MyDllInterface) Native.loadLibrary("./com/myproject/main/jna/dll/my_dll", MyDllInterface.class);

This works fine as long as I test these JNA Interfaces locally with test classes. As soon as I deploy them to glassfish (via Netbeans) I get errors like this:

java.lang.UnsatisfiedLinkError: Unable to load library './com/myproject/main/jna/dll/my_dll': The specified module could not be found.

I am suspecting it has something to do with how glassfish handles classpaths or maybe how loading inside *.war packed application works.

Things I've tried using:

  • relative class paths (../dll_file)
  • absolute class paths (com/etc and /com/etc)
  • absolute system paths (C:/Users/etc)

Can anyone help?

(I'm using Netbeans 8.2, Glassfish 4.1.1 (comes with Netbeans) on Windows. DLLs were compiled on Windows C++ and work with my testing code)


Answer:

I guess the problem is related to java.library.path and that you are packaging the DLL files inside your webapp. This is not recommended.

About the variable java.library.path:

When a Java application loads a native library using the System.loadLibrary() method, the java.library.path is scanned for the specified library. If the JVM is not able to detect the requested library, it throws an UnsatisfiedLinkError. Finally, the usage of native libraries makes a Java program more platform dependent, as it requires the existence of specific native libraries.

So on Glassfish this variable is normally set to the JVM folders and the glassfish/lib directories.

One solution may be, to put the DLL files into the folder glassfish/lib and remove the paths from your loadLibrary() calls.

If this doesn't work or is not portable enough for you, you can try to set the java.library.path to the path of your exploded WAR directory (ths is the directory where the content of your WAR file is extracted when it is deployed on Glassfish).

You can change the variable for your Glassfish domain via the Glassfish Admin UI, with the asadmin utility or directly in your domain.xml.

Here is an example: -Djava.library.path=c:\somewhere\where\the\DLLs\are\located

The path to your exploded web application should look similar to this: glassfish\domains\domain1\applications\YOUR_WEBAPPLICATION\WEB-INF\classes\whereTheDLLsAre\. Have a look at this folder to make sure, the DLL files are there.

Then your setting should look similar to this:

-Djava.library.path=c:\SOMETHIN\glassfish4\glassfish\domains\domain1\applications\YOUR_WEBAPPLICATION\WEB-INF\classes\whereTheDLLsAre\

See also:

  • Could I pack native DLLs into WAR?
  • Trying to use DLL from Java (JNA). Unable to load library exception

Question:

I have serious problem and I have tried all possible ideas, I did read also answers on stackoverflow on similar issue whaich were of no use to me.

What actually happens is I am deploying application on glassfish 3.1.2.2. I am using 2 jars: jna.jar and platform.jar (I tried different versions, last I tried was actually: jna-3.3.0.jar and jna-3.0.0-platform.jar) what I am trying to is to read Windows registry keys. I am also calling other methods from jna.jar (interesting I don't have to include jna.jar in my lib directory inside my ".ear" file, what indicates - it must be allready present somewhere on glassfish. When I searched for it on glassfish directories - I couldn't find it.). Anyways - when I call methods of jna.jar - it is working just fine, when I call methods of platform.jar, first of all I have to deploy that platform.jar in lib directory of my .ear file, secondly - it never works - because I get: ...

java.lang.IllegalAccessError: tried to access method com.sun.jna.Pointer.(J)V from class com.sun.jna.platform.win32.WinReg$HKEY

I have tried anything I could have think of: rebuilding my workspace, renaming jars, including both of them in lib folder of .ear file, including one of them, not including at all, including those jars in glassfish3\glassfish\domains\target\lib\ext, including one or the other in glassfish3\glassfish\domains\target\lib\ext, trying different versions of those 2 jars, nothing worked. I tried using jni4j.jar instead of jna.jar and platform.jar, still didn't help.

Here is actual code, using jna.jar and platform.jar:

    if (Advapi32Util.registryKeyExists(WinReg.HKEY_LOCAL_MACHINE, "SOFTWARE\\CitySyncSafety")) {
        path = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, "SOFTWARE\\CitySyncSafety", "Path") + File.separator + "DetectEngine";
        logger.warning("POJO path is: " + path);
    } else {
        path = "";
        logger.warning("Else POJO path is: " + path);
    }
    String libPath = System.getProperty("java.library.path");
    if (path != null && !path.equalsIgnoreCase("") && !libPath.contains(path)) {
        logger.warning("Library paths are: " + libPath);
        System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + path);
    }
    if (path != null) {
        //System.loadLibrary(path + File.separator + "cutilityProj1.dll");
    }

It causes that illegal access exception spoken of. When I try to use jni4j.jar with the following code, I do not get any exception, because I do not get anything at all:

    try {
        Reg reg = new Reg("HKEY_LOCAL_MACHINE\\SOFTWARE");
        Reg.Key cp = reg.get("HKEY_LOCAL_MACHINE\\SOFTWARE");
        Reg.Key sound = cp.getChild("CitySyncSafety");
        String p = sound.get("Path");
        path = p  + File.separator + "DetectEngine";;
    } catch (IOException e) {
        if (path == null) {
            path = "";
        }
    }

It just hangs forever on the first line. Please note I have ensured that appropriate key and directories do exist, so we can exclude this issue. I will appreciate any help, as I spent already 2 days on this single issue.


Answer:

Here is solution :). I can't tell if all the steps are necessary (I mean, I could but I can't be bothered now, while at work). All it takes is to combine jna.jar and platform.jar into 1 jar and place it in glassfish3\glassfish\domains\target\lib and in glassfish3\glassfish\domains\target\lib\ext (actually I bet it is enough to place it in glassfish3\glassfish\domains\target\lib, but I didn't test it).

Well, at least now it works!

Please vote it up, if it helps you.