UnsatisfiedLinkError with OpenCV in Tomcat - java

First of all, I have a basic example of OpenCV running in a main method.
However, if I use OpenCV in a Spring Web Controller, an error is thrown.
I am getting an UnsatisfiedLinkError when running the following code inside a Tomcat Server, within STS (Spring Tool Suite), and have boiled the problem down to the following code:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
CascadeClassifier cascadeClassifier = new CascadeClassifier();
The run configurations of both the server and the "main" application contain the VM Arguments pointing to the OpenCV DLLs:
-Djava.library.path="C:\opencv\build\java\x64;C:\opencv\build\x64\vc10\bin"
For reference, I have also included the pertinent bits of the stacktrace below:
org.springframework.web.util.NestedServletException: Handler processing failed;
nested exception is
java.lang.UnsatisfiedLinkError: org.opencv.objdetect.CascadeClassifier.CascadeClassifier_0()J
...
Caused by: java.lang.UnsatisfiedLinkError:
org.opencv.objdetect.CascadeClassifier.CascadeClassifier_0()J
at org.opencv.objdetect.CascadeClassifier.CascadeClassifier_0(Native Method)
at org.opencv.objdetect.CascadeClassifier.<init>(CascadeClassifier.java:38)
at com.immersion.test.controllers.SimpleController.createClassifier(SimpleController.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
Note: I have read in several StackOverflow threads that the main cause of the UnsatisfiedLinkError is the missing System.loadLibrary(Core.NATIVE_LIBRARY_NAME) call. This is clearly not the case here, since it is being called just above where the exception is thrown.

Same thing here.
I try what Dylan said, but did not work here.
But I added "C:\opencv\build\java\x64;C:\opencv\build\x64\vc10\bin" on my PATH variable. On my sys variables.
ps: I'm using windows.

It turns out that the default run configuration to start a Tomcat server within STS/Eclipse is essentially just a launcher for Tomcat.
This means that any VM Args that are added to the Tomcat 'run configuration' will not be transferred to the actual Tomcat instance.
On looking in tcruntime-instance.bat within the Tomcat directory (this is what ends up creating the tomcat java instance), we can see that simply by adding our intended VM Args to the JAVA_OPTS environment variable, the dlls will be available to Tomcat.
TL;DR:
So.. Simply add the the locations of the OpenCV binaries to your JAVA_OPTS environment variable:
-Djava.library.path="C:\opencv\build\java\x64;C:\opencv\build\x64\vc10\bin"
For more information on setting JAVA_OPTS for Tomcat, see this SO question.

Related

jna Native.LoadLibrary does not manage to load library on server (working in local)

I use JNA to load a c++ library (.so) in a java project. I package my library inside the jar, and load it from the jar when instantiating the java class that uses it. I do all this like so:
mvn install compiles the c++ code and packages the outcome dynamic library inside the jar.
I call in a static context when instantiating the LibraryWrapperClass the following
System.load( temp.getAbsolutePath() );
where temp is a temporary file containing the library which was found in the jar. This code is based on the work found here adamheinrich
- I call Native.loadLibrary(LIBRARYPATH) to wrap the library into a java class.
private interface Wrapper extends Library {
Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
Pointer Constructor();
...
}
I run tests and validate that the library was found and up and running.
I use a java web project that depends on this project. It uses tomcat and runs fine in local.
My issue is that when I deploy on the server, the LibraryWrapperClass cannot instantiate. Error on server is:
java.lang.NoClassDefFoundError: Could not initialize class pacakgeName.LibraryWrapperClass
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:375)
at org.hibernate.annotations.common.util.StandardClassLoaderDelegateImpl.classForName(StandardClassLoaderDelegateImpl.java:57)
at org.hibernate.boot.internal.MetadataBuilderImpl$MetadataBuildingOptionsImpl$4.classForName(MetadataBuilderImpl.java:758)
at org.hibernate.annotations.common.reflection.java.JavaReflectionManager.classForName(JavaReflectionManager.java:144)
at...
This error seems that the library is found, since there is not the UnsatisfiedLinkError exception thrown. But something else is failing. Do someone know what could happen? How could I debug?
I recall that everything works perfectly in local.
How could I debug?
1. with strace
strace will give you what files Tomcat is trying to open : strace -f -e trace=file -o log.txt bin/startup.sh
After this, look for packageName in log.txt, or other files not found with :
egrep ' open.*No such file' log.txt
2. with JConsole
Enable JMX, launch a JConsole, go to VM summary tab, and check/compare very carefully VM arguments/classpath/library path/boot class path
3. dependency listing with ldd
If a dependency issue is likely to be the problem, the ldd sharedLibraryFile.so command lists all the dependencies and allows to track which one might be missing.

Java webapp produces StackOverflow exception on Linux

I have a Java-web application running on Tomcat 9. It works fine on a Windowns machine. But after deploying this app on a Debian Linux server I've encountered java.lang.StackOverflow exceptions on some particular pages. Here is the beginning of the stacktrace log:
27-Dec-2017 08:54:43.746 SEVERE [https-jsse-nio-9443-exec-3]
org.apache.catalina.core.ApplicationDispatcher.invoke Servlet.service() for
servlet [jsp] threw exception
java.lang.StackOverflowError
at java.io.UnixFileSystem.canonicalize0(Native Method)
at java.io.UnixFileSystem.canonicalize(UnixFileSystem.java:172)
at java.io.File.getCanonicalPath(File.java:618)
at org.apache.catalina.webresources.AbstractFileResourceSet.file(AbstractFileResourceSet.java:90)
Please, see full stacktrace here:
https://pastebin.com/0AmFDY8F
As far as I understand, the exception occurs while compiling the JSP page source by Jasper and it's somehow related to the resolving of Linux paths / directories. Could anybody please help me to figure out what the exact problem is? I didn't create any symbolic links, if the problem can be related to this.
According to your stack trace, the problem is caused by not being able to find a specific path as resolved by your Spring framework:
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
...
Caused by: java.io.IOException: JSPException including path '/struct/context/tutorials.jsp'.
The Spring framework is likely using the canonical paths to resolve the file, and it fails perhaps because there is some quirk in the framework related to the type of Unix system you are deploying to.
Please reference this in the Spring documentation:
https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html#deployment-install-supported-operating-systems
The default script supports most Linux distributions and is tested on CentOS and Ubuntu. Other platforms, such as OS X and FreeBSD, will require the use of a custom embeddedLaunchScript.
Notice that Debian was not listed. Hopefully this puts you on the right path.
If I'm chasing a red herring here, I'm sorry - but you haven't given us much to go on.
Finally I've found what caused the StackOverflow exception. I have a recursive JSP tag call to render nested options for a <select> tag. After removing the recursion, the exception disappeared. Sure, it's just a workaround, so I'm still wondering why it works fine on Windows and doesn't on Linux.

Run java applet offline: Exception in thread "main" java.lang.NoClassDefFoundError

I just downloaded some java applets from this site: http://www.surendranath.org/Apps.html to run them offline on my laptop. Take for example this one: http://www.surendranath.org/Applets/Oscillations/Lissajous/Lissajous.html
By inspecting the source code I downloaded the file: wget http://www.surendranath.org/Applets/Oscillations/Lissajous/LissajousApplet.class
Then I tried it to run it on my ubuntu box via gappletviewer-4.8 -code LissayousApplet.class
However I got the following error message:
Exception in thfully qualifiedread "main" java.lang.NoClassDefFoundError: loaded class LissajousApplet was in fact named Applets.Oscillations.Lissajous.LissajousApplet
at java.lang.VMClassLoader.defineClass(libgcj.so.14)
at java.lang.ClassLoader.defineClass(libgcj.so.14)
at java.security.SecureClassLoader.defineClass(libgcj.so.14)
at java.net.URLClassLoader.findClass(libgcj.so.14)
at java.lang.ClassLoader.loadClass(libgcj.so.14)
at java.lang.ClassLoader.loadClass(libgcj.so.14)
at java.lang.ClassLoader.loadClass(libgcj.so.14)
at gnu.classpath.tools.appletviewer.Main.createApplet(libgcj-tools.so.14)
at gnu.classpath.tools.appletviewer.StandaloneAppletWindow.<init>(libgcj-tools.so.14)
at gnu.classpath.tools.appletviewer.StandaloneAppletViewer.createWindows(libgcj-tools.so.14)
at gnu.classpath.tools.appletviewer.StandaloneAppletViewer.<init>(libgcj-tools.so.14)
at gnu.classpath.tools.appletviewer.Main.main(libgcj-tools.so.14)
So what is the correct way to run this applet offline? Running it online within my browser and the icetea plugin works. However I need a way to run it offline.
Edit
Trying the fully qualified class-name results in:
gappletviewer-4.8 -code Applets.Oscillations.Lissajous.LissajousApplet.class -codebase codebase="../../../"
WARNING: CURRENTLY GAPPLETVIEWER RUNS WITH NOSECURITY MANAGER.
THIS MEANS THAT APPLETS YOU LOAD CAN DO ANYTHING A JAVA APPLICATION
THAT YOU DOWNLOAD AND RUN CAN DO. BE *VERY* CAREFUL WHICH APPLETS YOU RUN.
DO NOT USE GAPPLETVIEWER ON YOUR SYSTEM IF YOUR SYSTEM STORES IMPORTANTDATA.
THIS DATA CAN BE DESTROYED OR STOLEN IF YOU LOAD A MALICIOUS APPLET.
[press 'c' or 'C' to continue or anything else to quit]
c
java.lang.ClassNotFoundException: Applets.Oscillations.Lissajous.LissajousApplet not found in gnu.classpath.tools.appletviewer.AppletClassLoader{urls=[file:/home/null,file:/home/], parent=gnu.gcj.runtime.SystemClassLoader{urls=[file:./], parent=gnu.gcj.runtime.ExtensionClassLoader{urls=[], parent=null}}}
at java.net.URLClassLoader.findClass(libgcj.so.14)
at gnu.classpath.tools.appletviewer.AppletClassLoader.findClass(libgcj-tools.so.14)
at java.lang.ClassLoader.loadClass(libgcj.so.14)
at java.lang.ClassLoader.loadClass(libgcj.so.14)
at gnu.classpath.tools.appletviewer.Main.createApplet(libgcj-tools.so.14)
at gnu.classpath.tools.appletviewer.StandaloneAppletWindow.<init>(libgcj-tools.so.14)
at gnu.classpath.tools.appletviewer.StandaloneAppletViewer.createWindows(libgcj-tools.so.14)
at gnu.classpath.tools.appletviewer.StandaloneAppletViewer.<init>(libgcj-tools.so.14)
at gnu.classpath.tools.appletviewer.Main.main(libgcj-tools.so.14)
Try using the fully qualified classname
gappletviewer-4.8 -code Applets.Oscillations.Lissajous.LissajousApplet.class -codebase codebase="http://www.surendranath.org/"
Read: gappletviewer Man page

UnsatisfiedLinkError and NoClassDefFoundError : Running Java Mapscript on Ubuntu 11.10

We have coded and run a dynamic web application using MAPSERVER(Version 6.0.1) on windows platform using Java Technology. Now, there is need of deploying it on Ubuntu 11.10. We have installed Apache Tomcat 6.0, Mapserver 6.0.1, Apache 2.0, and FWTools-2.0.1(As this package contain all required tools for mapserver if I am not wrong, so I didn't feel any other tools to be installed). We have deployed the war file(and put application without) in Apache Tomcat 's Webapps folder. I even got the index page which dont have code related with mapscript api. But while fetching the other servlet with mapscript we are getting following error...
java.lang.UnsatisfiedLinkError: no mapscript in java.library.path
java.lang.ClassLoader.loadLibrary(ClassLoader.java:1681)
java.lang.Runtime.loadLibrary0(Runtime.java:840)
java.lang.System.loadLibrary(System.java:1047)
edu.umn.gis.mapscript.mapscriptJNI.<clinit>(mapscriptJNI.java:23)
edu.umn.gis.mapscript.mapObj.<init>(mapObj.java:283)
Again while refreshing the browser page where the above error was displayed, I got a change,
java.lang.NoClassDefFoundError: Could not initialize class
edu.umn.gis.mapscript.mapscriptJNI
edu.umn.gis.mapscript.mapObj.<init>(mapObj.java:283)
I searched on net about the above problem. But finally blank. Please, provide idea about the above problem.
I'm not going to explain why you're getting the UnsatisfiedLinkError, but instead I'll explain why you are getting the NoClassDefFoundError when you reload the page.
A NoClassDefFoundError with a message Could not initialize class ... is thrown by the JVM when it attempts to initialize a class that it has already tried and failed to initialize.
The first of your two stacktraces contains the line
edu.umn.gis.mapscript.mapscriptJNI.<clinit>(mapscriptJNI.java:23)
The method name <clinit> denotes the static initializer, of the class mapscriptJNI. So, at the point that the UnsatisfiedLinkError was thrown, the JVM was trying to initialize this class. Looking at the error message, it seems that this static initializer tried to load the native code library mapscript but failed.
This UnsatisfiedLinkError causes the mapscriptJNI class to fail to initialize successfully. The JVM keeps a record of all classes that fail to initialize, and if you attempt to initialize one of those classes again, you'll get a NoClassDefFoundError with a message saying that it could not initialize that class.
When you refresh the page, you end up causing the JVM to attempt to initialize the class mapscriptJNI a second time. Of course, this class failed to initialize the previous time. Your second stacktrace contains exactly the error I've described.
In short, the UnsatisfiedLinkError is the real error here. Fix that and the other one will go away.
I would check the following 2 items:
Is the mapscript.jar file on Tomcat or at least your webapp's classpath? (NoClassDefFoundError is your big clue here)
Is the libmapscript.so on either your LD_LIBRARY_PATH or -Djava.library.path? (UnsatisfiedLinkError since the shared object cannot be found)
Try having a look at this post, near the Running Java Mapscript (on Linux) section.
Hope that helps!

RMI with multiple JAR inclusion

I am coding a RMI program with 3 JAR:
RMIServer, contains server-side classes
RMIClient contains client-side classes
RMIResource contains server & client shared content (interfaces, custom exceptions)
To make separate JAR files, I created 3 projects in NetBeans, then I declared the shared Jar in the "Libraries/Build" section of the other 2 projects.
Everything just build-up fine, no error.
But when I try to launch the server through the command-line, which was simple before I had the idea to put the shared files in a distinct JAR, this is suddenly pain in the a**...
Here are a few examples of commands I tried:
Keeping the ClassPath pointing to the server resources, but using dual CodeBase
java -cp ~/NetBeansProjects/RMIServer/dist/RMIServer.jar -Djava.rmi.server.codebase="file:/home/myuser/netbeansprojects/rmiserver/dist/rmiserver.jar file:/home/myuser/netbeansprojects/rmiserver/dist/lib/rmiresource.jar" rmiserver.Shop
Result:
Network exception: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: rmiresource.BookingManager
...
Using dual ClassPath but keeping the CodeBase pointing to the server resources
java -cp "~/NetBeansProjects/RMIServer/dist/RMIServer.jar;~/NetBeansProjects/RMIServer/dist/lib/RMIResource.jar" -Djava.rmi.server.codebase=file:/home/myuser/netbeansprojects/rmiserver/dist/rmiserver.jar rmiserver.Shop
Result:
Exception in thread "main" java.lang.NoClassDefFoundError: rmiserver/Shop
Caused by: java.lang.ClassNotFoundException: rmiserver.Shop
...
Using dual ClassPath & dual CodeBase
java -cp "~/NetBeansProjects/RMIServer/dist/RMIServer.jar;~/NetBeansProjects/RMIServer/dist/lib/RMIResource.jar" -Djava.rmi.server.codebase="file:/home/myuser/netbeansprojects/rmiserver/dist/rmiserver.jar file:/home/myuser/netbeansprojects/rmiserver/dist/lib/rmiresource.jar" rmiserver.Shop
Result:
Exception in thread "main" java.lang.NoClassDefFoundError: rmiserver/Shop
Caused by: java.lang.ClassNotFoundException: rmiserver.Shop
...
EDIT:
I am working on the local computer, simulating distant connections. Thus I use 'file' protocol and not 'http'.
Am I missing something? Thanks for any help you would provide
I tested out again my 1st solution since it was the most promising:
java -cp ~/NetBeansProjects/RMIServer/dist/RMIServer.jar -Djava.rmi.server.codebase="file:/home/myuser/netbeansprojects/rmiserver/dist/rmiserver.jar file:/home/myuser/netbeansprojects/rmiserver/dist/lib/rmiresource.jar" rmiserver.Shop
It still failed.
Then I tested out on Windows:
Setup the rmiregistry with an empty classpath (and cd to the java/bin directory)
set CLASSPATH=""; export CLASSPATH
start rmiregistry
Launch the server with an equal command as before (moduo the Win env changes)
java -cp c:/NetBeansProjects/RMIServer/dist/RMIServer.jar -Djava.rmi.server.codebase="file:/c:/netbeansprojects/rmiserver/dist/rmiserver.jar file:/c:/netbeansprojects/rmiserver/dist/lib/rmiresource.jar" rmiserver.Shop
And... It worked!
I cleaned-up/rebuilt the solution both on Linux & Windows and it is still not working on Linux and working on Windows... I use the same Netbeans version on both!
Can someone explain that to me? I am using the JDK 6 on Linux & JDK 7 on Windows: would that have an impact?
A file: codebase can't work out of the local machine. You need to use HTTP. You could possibly use a file: URL pointing to a shared directory, such that the URL makes sense at a client, but this won't work outside the LAN.
Unless you are using the codebase feature, the RMI Registry needs access to the shared classes via its classpath: rmiregistry -J-Dclasspath=... It's simpler to use LocateRegistry.createRegistry(), then it's in the same JVM as your remote objects and uses the same classpath of course.

Categories