native libraries configuration under tomcat - java

I am trying to get the JMagick library working under Tomcat to do some image
translation following an upload.
Magic comes as a semi-stub library.jar archive and a native library
libJMagick.so . I have used
System. LoadLibrary ("JMagick");,
but I get errors in the catalina.out complaining about being unable to find
the library (details at the end of this message). the key clause being:
Caused by: java.lang.RuntimeException: Can't load MagickLoader (class not found) at magick.Magick.(Magick.java:25)
So where should I put the libraries, currently they are in WEB-INF/lib so that tomcat can use them

If your shared object is not installed througha package manager, put into setenv.sh LD_LIBRARY_PATH=$CATALINA_BASE/lib:$LD_LIBRARY_PATH and copy the so to that lib directory.

Related

OpenCV 4.3.0 java.lang.UnsatisfiedLinkError in Eclipse

I'm trying to do some template matching with the Java binding of OpenCV 4.3.0 in Eclipse, but attempting to load the template image always results in this error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: org.opencv.imgcodecs.Imgcodecs.imread_0(Ljava/lang/String;I)J
The line of code where this exception is thrown is this:
flowerTemplate = Imgcodecs.imread("/templates/flowerpot_white.png", Imgcodecs.IMREAD_COLOR);
I have tried a number of solutions suggested on similar questions on StackOverflow and elsewhere on the internet, including:
Pointing at the native library folder with the "Native library location" variable in the user library definition in Eclipse.
Adding the native library folder location to my PATH variable.
Adding the native library .dll location to my PATH variable.
Setting up the Eclipse run configuration to add the native library folder & .dll locations to the PATH and CLASSPATH variables.
Loading the library with the appropriate Java code, in each of the three ways I saw it suggested, in three different places which all run before the code that throws the exception.
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.load(<path_to_the_dll>);
File opencvLibrary = new File(System.mapLibraryName(Core.NATIVE_LIBRARY_NAME));
System.load(opencvLibrary.getAbsolutePath());
Placing the .dll in question into my source folder and every subfolder. I am running it from within Eclipse, so this is also the program's working directory.
UnsatisfiedLinkError is a runtime exception that happens when running your Java program. So placing your file in the source folder will not work.
You need it to be available in a place that your program can find it.
See this article for example:
https://www.javaworld.com/article/2077520/java-tip-23--write-native-methods.html
In it they place the library in Linux's library path. In windows you'd similarly place it in the current directory (where you're running from) or in some shared location.
This article explains Window's dll search order: https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
You shouldn't need to explicitly call System.loadLibrary() yourself. That's the library's responsibility.
Your problem is that OpenCV is improperly installed on your machine or inaccessible from Eclipse.
For instructions on how to make in work in Eclipse see:
Add .dll to java.library.path in Eclipse/PyDev Jython project
After removing every load method and then adding them back one-by-one, I determined that the issue was most likely caused by Eclipse loading the native library folder twice.

Issues loading .so file with JNA in Spring Boot on Linux

I have an application written in Java with Spring Boot. This application needs to load .so files that are bundled with the project, I am using JNA to accomplish this. However, the JNA loader doesn't seem to be able to pick up the .so files and the application fails to start.
I've tried running the application from within IntelliJ and by running the packaged .jar with "java -jar". The .so files are kept in src/main/resources/linux-x86-64 for now. I've tried keeping them in a different directory, e.g src/main/resources/libs/linux-x86-64 and set the property "jna.library.path", but JNA still fails to find the files.
This is the debug log for JNA:
Trying (via loadLibrary) jnidispatch
Looking in classpath from sun.misc.Launcher$AppClassLoader#18b4aac2 for /com/sun/jna/linux-x86-64/libjnidispatch.so
Found library resource at jar:file:/home/dalivi/.m2/repository/net/java/dev/jna/jna/4.5.0/jna-4.5.0.jar!/com/sun/jna/linux-x86-64/libjnidispatch.so
Trying /tmp/jna--1339148563/jna4246531844315283838.tmp
Found jnidispatch at /tmp/jna--1339148563/jna4246531844315283838.tmp
Looking for library 'GTransTF'
Adding paths from jna.library.path: null
Trying libGTransTF.so
Adding system paths: [/usr/lib/x86_64-linux-gnu, /lib/x86_64-linux-gnu, /lib64, /usr/lib, /lib, /lib/i386-linux-gnu, /usr/lib/i386-linux-gnu, /usr/lib/x86_64-linux-gnu/libfakeroot]
Trying libGTransTF.so
Looking for version variants
Looking in classpath from sun.misc.Launcher$AppClassLoader#18b4aac2 for GTransTF
Found library resource at file:/home/dalivi/Workspace/java/geotransboot/target/classes/linux-x86-64/libGTransTF.so
Looking in /home/dalivi/Workspace/java/geotransboot/target/classes/linux-x86-64/libGTransTF.so
2019-04-25 12:43:38.032 ERROR 25897 --- [o-auto-1-exec-1] s.l.g.c.TransformationRestController : Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError: libCoreGTrans.so: cannot open shared object file: No such file or directory
I does seem to find one of the files in the directory: libGTransTF.so, but then immediately fails when trying to find the file libCoreGTrans.so which is present in the same directory as the previous file.
I should mention, on Windows, this works just fine. JNA finds the corresponding dll files in the directory specified with "jna.library.path".
The windows behaviour is to search for dependent libraries in the directory that the .dll comes from, so when jna loads the library into memory the dependent library is loaded from there as well.
If you fire up a terminal window and cd to the directory that the .so exists in and run the command:
ldd ./libGTransTF.so
and it indicates that it's unable to find the library libCoreGTrans.so then you can see that the search order won't find this location.
The run-time link-loader (ld.so) uses a set of decisions as to where to find libraries. The default behaviour doesn't include the directory that the library was found.
You can add an option to the library when building to search in specific locations to find libraries. When you're building the library, you can say to search in the directory that the .so comes from at run time by adding the line:
-Wl,-rpath,'$ORIGIN'
to the link line. It needs to populate with the constant value $ORIGIN or else this doesn't work, so this can be a bit tricky to get right in a makefile. This is a value that gets resolved at run-time.
This is all very fine and well if you're building the library yourself, but if you're getting libraries from somewhere else, or you've already built them and don't want to rebuild them, you can use a tool such as patchelf to edit the search path for an .so to add it's origin location:
patchelf --set-rpath '$ORIGIN' libGTransTF.so
Then when you run:
ldd ./libGTransTF.so
it should be able to successfully find the libCoreGTrans.so library.

When does a shared library have to be on the Java classpath?

I'm trying to work with a third-party SDK on RHEL. Running this vendor's sample code (using their own provided run.sh) throws what I'll call Error 1: java.lang.UnsatisfiedLinkError: Unable to load library 'redacted': Native library (linux-x86-64/libredacted.so) not found in resource path. I add the library location to the class path, and that error disappears.
It is replaced with Error 2: Java.lang.UnsatisfiedLinkError: libodbc.so: cannot open shared object file: No such file or directory, where I obviously am missing a dependency. I install the appropriate MySQL package (which puts the .so in /lib64) and it's happy.
Now both .so files are in /lib64, which is on the Java library path, so I would assume it should find them the same. Even pointing LD_LIBRARY_PATH to the library (which the vendor had done in their script) doesn't resolve Error 1.
Why is the first library required to be on the class path when Java uses java.library.path to find shared objects?
It's worth noting that the vendor's script didn't run correctly out of the box, which makes me wonder if it's an issue with my particular RHEL installation.

Indri library java.lang.UnsatisfiedLinkError..change to java.lang.NoClassDefFoundError only on the server

I have this web application where I use the indri.jar in it. I am using eclipse.
I have put it in the lib folder and did "add to build path" option.
Also in "Build Path -> Configure -> Order and Export", everything is checked.
Also in "Properties -> Deployment assembly", all the jar files are added. Then I export the project to .war and put it on the server.
I checked the lib folder of the deployed project and the jar file is there.
Also my machine and server are both 64 bit, since for this library there are two versions for 32 and 64 bit, and it wont work if you use them instead of each other.
It is also important to say that we are a team working on this project using git repository, and when the other side pull the code all the libraries and everything is attached and they have no problem running the code. (They have installed indri, and I did install it on the server)
Still when I open the page in the browser it gives me "error in ajax call" and when I trace the error it gives me:
description The server encountered an internal error () that prevented it from fulfilling this request.
exception
javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.UnsatisfiedLinkError: no indri_jni in java.library.pathorg.etc.
root cause
org.glassfish.jersey.server.ContainerException: java.lang.UnsatisfiedLinkError: no indri_jni in java.library.pathorg.glassfish.etc
root cause
java.lang.UnsatisfiedLinkError: no indri_jni in java.library.pathjava.lang.ClassLoader.loadLibrary(ClassLoader.java:1886)java.lang.Runtime.loadLibrary0.etc.
I searched a lot and then I ran this line on the server:
java -Djava.library.path=/path/to/jnilib/directory MainClass
Then the error changed to this:
exception
javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: Could not initialize class lemurproject.indri.indriJNIorg.glassfish
root cause
org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: Could not initialize class lemurproject.indri.indriJNIorg.glassfish.jersey.servlet
java.lang.NoClassDefFoundError: Could not initialize class lemurproject.indri.indriJNIlemurproject.indri.QueryEnvironment.<init>(QueryEnvironment.java:39)LogicLayer.IndriIndex.processQuery(I...
Note:
Indri is working on command line on the server, so the problem is not with indri but is with deploying.
When I deploy the code by commenting the lines related to Indri, it works, that shows I am exporting to .war correctly.
There is an important file in indri installation which is libinrdi_jni.so, which has the role of linking java to c language which is the language the library has been written to. It is located in the indri installation foler: ./install/lib/libindri_jni.so.
My code couldn't find this file. So I had to put it somewhere in the server that it will definitely look into and then it did find it and everything worked.
To make sure that you will have this file you need to install indri in this way:
./configure --enable-java --with-javahome=address/to//jdk1.7.0 --prefix=/address/to/indri-5.7/install
make all install
make sure to download the jdk1.7 and extract it yourself instead of using any install package. This way the libindri_jni.so will be installed.
Then to make sure that your java program will work, you need to run IndexUI.jar, and RetUI.jar, provided in the indri folder. If it works, then your program will work too, but if it is not working, then try running this command:
export LD_LIBRARY_PATH=/address/to/indri-5.7/install/lib
then run the jar file again, if the problem has been resolved, the libindri_jni.so file is the problem and you can solve it by locate it in a place that program can definitely find it.

Using Tess4J on Tomcat

When I use the Tess4J library I get an error:
java.lang.NoClassDefFoundError: Could not initialize class net.sourceforge.tess4j.TessAPI
at runtime.
But I don't get the meaning of this error, nor I am able to resolve it.
My problem is that 2 native dlls have to be loaded by Tess4J but this is out of my hands. I've added the location of the dlls to the build path for each jar.
I noticed, that when I first trigger Tess4J with my client, I get an error:
java.lang.UnsatisfiedLinkError: Unable to load library 'libtesseract302'
but every consecutive call results in the NoClassDefFoundErrorexception.
In my case switching from 64-bit Java to 32-bit Java solved the java.lang.UnsatisfiedLinkError: Unable to load library 'libtesseract302' problem (Tesseract is a 32-bit app). Don't forget to put libtesseract302.dll, liblept168.dll and tessdata in jdk/bin folder.

Categories