OpenCV as JBoss-as global module - java

Problem presentation
I try to install OpenCV as global module of a JBoss-as instance. The versions are:
JBoss-as: 7.1.1 Final
OpenCV: 2.4.5 (compiled with Java support)
I started from a fresh installation of Ubuntu Server 12.04 64 bits with only JBoss-as and OpenCV installed.
Preamble
The OpenCV java wrapper use JNI calls. Thus two things are required:
opencv-245.jar
libopencv_java245.so
And available in /usr/share/OpenCV/java/ (regarding to installation)
I also point some observations:
The installation of JBoss is correct (applications can be deployed and are working)
The compilation and installation of OpenCV with java support is correct (Java class using OpenCV are working)
A basic web application using OpenCV and deployed, with maven, on JBoss-as works (the opencv-245.jar is listed as dependency in pom.xml, and thus packaged into the war)
Problem description
As soon as I define OpenCV as JBoss global module (setting <scope>provided</scope> in pom.xml) this exception is raised:
java.lang.UnsatisfiedLinkError: org.opencv.core.Mat.n_Mat()J
org.opencv.core.Mat.n_Mat(Native Method)
org.opencv.core.Mat.<init>(Mat.java:441)
WS.printMessage(WS.java:15)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:616)
org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:155)
org.jboss.resteasy.core.ResourceMethod.invokeOnTarget(ResourceMethod.java:257)
org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:222)
org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:211)
org.jboss.resteasy.core.SynchronousDispatcher.getResponse(SynchronousDispatcher.java:525)
org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:502)
org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:119)
org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:208)
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55)
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:50)
javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
It appears that the OpenCV jar library is found because the exception is raised from it. Also it does not complains about some library not found like (taken from first link at the end):
java.lang.UnsatisfiedLinkError: no xxxx in java.library.path
thus I guess the libopencv_java245.so is not the problem. The precise configuration is described below.
Configurations
I defined the org.opencv module in modules/org/opencv/main/module.xml:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.opencv">
<resources>
<resource-root path="opencv-245.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>
Then I put in the same folder opencv-245.jar and also libopencv_java245.so in lib/linux-x86_64/ subfolder (as explained in Native Library)
To define this module as global I modified in standalone/configuration/standalone.xml:
<subsystem xmlns="urn:jboss:domain:ee:1.0">
<global-modules>
<module name="org.opencv" slot="main"/>
</global-modules>
</subsystem>
Finally to use the global module I set in src/main/webapp/WEB-INF/jboss-deployment-structure.xml:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.opencv" />
</dependencies>
</deployment>
</jboss-deployment-structure>
I also reminds that I have put <scope>provided</scope> in my maven pom.xml.
Also, putting:
System.loadLibrary("opencv_java245");
or not in the code doesn't change anything.
Extra observations
I also noticed that with an ear application, composed of one war and one jar, even the procedure described in point 3 in "Preamble" does not work and give the same exception as above. Maybe this information can help.
Someone have some pointers or solutions?
Related questions
Path setting for DLL's in JBOSS 7.1.1
JBoss 7 is trying to load modules libraries from JBoss bin

I finally solve the problem and write here the answer to help other people.
The problem wasn't in the path of the libopencv_java245.so, but in the JBoss Classloaders.
For the case decribed in Preamble point 3 (which worked), the ClassLoader that load the war file is the same that load opencv-245.jar (which is embedded into the war), and the call to System.loadLibrary("opencv_java245") in my code has effect on this same ClassLoader, because it has loaded the Class containing this method call. All has effect on the same ClassLoader and everything work.
Now the reason why it is not working with an ear follow up from the fact that an ear has its own ClassLoader, and then each subdeployment as another one. The first ClassLoader deploy the ear, which contains the opencv-245.jar dependecy, then another ClassLoader deploy the war contained into the ear. Because the call System.loadLibrary("opencv_java245") is in the war, the effect of this command has effect on the ClassLoader of the war, but the opencv-245.jar is loaded into the ear ClassLoader. Thus when trying to call native library, java can't find the link because they are on different ClassLoader.
Finally the point of interest here is for a JBoss module. When describing a module as configured in my initial question, this is a high level JBoss ClassLoader which load the opencv-245.jar. The ClassLoader will also automatically know where to search for native libraries: in $MODULE_PATH/lib/linux-x86_64/. But the problem is to load the library. The call to System.loadLibrary("opencv_java245") must be done in the same ClassLoader that have charged opencv-245.jar. Thus it is not possible to load library like this in your code:
static {
System.loadLibrary("opencv_java245");
}
because it will has effect on the ClassLoader that have load your Class, not on the JBoss one. The solution is to modify the opencv-245.jar and add into it a org.opencv.core.Loader class for instance, which have only one method:
package org.opencv.core
class Loader
{
public static void loadLibrary(String name)
{
System.loadLibrary(name);
}
}
Then in your class you can put:
static {
Loader.loadLibrary("opencv_java245");
}
And the System.loadLibrary call being placed in opencv-245.jar will have effect one the same ClassLoader that load the opencv-245.jar. Then native call are correctly linked because both library, the jar and the so, were loaded in the same ClassLoader.

If you are using OpenCV (org.openpnp package) 3.4.2+ instead of:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
you can use:
OpenCV.loadLocally();
I'm using jboss wildfly, and had problem when doing more than one deploy. Native classes were already loaded, but this fixed the problem.

Add the libopencv_java245.so file to the same directory you created for your OpenCV module. then add it as a resource so it will be added to the classpath and be available at runtime.
So your module.xml will look like this now:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.opencv">
<resources>
<resource-root path="opencv-245.jar"/>
<resource-root path="."/>
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>

Related

Jboss logging to slf4j/log4j2 with Keycloak

I have a Keycloak EAR module, deployed on Keycloak 11.0. In my EAR module I want to use log4j2 logging library with slf4j. I successfully accomplished this by adding the following dependencies in the pom directly: log4j-slf4j-impl, log4j-api & log4j-core.
Wildfly logging dependencies are excluded by setting add-logging-api-dependencies to false. log4j2.xml is specified outside the packaged EAR and is referenced with log4j.configurationFile system property.
Now the problem. I also want Keycloak to use log4j2 but I cannot get this to work. Keycloak is using Jboss Logging wrapper which always picks up JbossLogManager no matter which logging provider I set - I always get either ClassNotFoundException or NoClassDefFoundError.
I realize there is a classpath problem but I am out of ideas at this point. I tried creating log4j-slf4j-impl, log4j-api & log4j-core Wildfly modules with the following command but I still get the same error.
./jboss-cli.sh --command="module add --name=org.apache.logging.log4j.log4j-api --resources=/Users/jernej/log4j-api-2.13.3.jar"
If I understand correctly, log4j2 should be in the classpath on Wildfly startup (when searching for LoggerProvider) and Jboss Logging findProvider method should return Log4j2LoggerProvider if modules are correctly added? How can I accomplished this?
Suppose I want to use log4j2 appender, located in separate library. If I add this library as a Wildfly module this log4j2 appender can then be used by other deployments as well - e.g. keycloak-server.war?
Adding a library as a module may not necessary makes it available to your application. Have you defined the dependency to that module in the jboss-deployment-structure.xml in the META-INF folder of your ear file? Something like this:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:deployment-structure:1.3 http://www.jboss.org/schema/jbossas/jboss-deployment-structure-1_3.xsd">
<deployment>
<dependencies>
<module name="org.apache.logging.log4j.log4j-api" export="true"/>
</dependencies>
</deployment>
</jboss-deployment-structure>

Can a JBoss module depend on a jar

I have made a jboss module to provide some base code. I want to log out some data when this module is deployed to jboss. I can achieve this by creating a simple class, like so:
#Singleton
#Startup
public MyClass {
#PostConstruct
public void init() {
System.out.println("I am in here");
}
}
The above initi method works, and is initiated correctly. Note, the module above is a jar.
However, when I extract the above code into its own project, and add the compiled jar as a dependency to the same module, the code is never executed. Conversely, if I add it to war deployable, it works as expected. i.e Maven dependency
<dependency>
<groupId>com.myModuleCommon</groupId>
<artifactId>moduleCommon</artifactId>
<version>1.0.0</version>
</dependency>
I have looked at the documentation here and examined this stackoverflow question tho I am unsure if that is the reason I cannot have a jar module depend on another jar.
My question then is, why does my extracted code not get invoked during startup (i.e The class above) when used as a dependency for a module, but works both as an internal class or as an dependency in a war deployable?
i.e In my sample war file, I can see the extracted dependency under WEB-INF/lib. However, in my jar module, there is nothing in the Manifest file that denotes that this dependency is being used. Maybe this is part of the problem, where there might be some alternate way to specify a dependency in a module.
Based on the documentation in the question, I believe that the correct answer is that module dependencies need to be explicitly added in the MANIFEST or jboss-deplyment-structure.xml file. Here is an article that shows how this can be done
i.e Using maven:
<configuration>
<archive>
<manifestEntries>
<Dependencies>com.something.dependency</Dependencies>
</manifestEntries>
</archive>
</configuration>
i.e Using jboss xml file
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="com.something.dependency" />
</dependencies>
</deployment>
</jboss-deployment-structure>

WAR extension strategy in Wildfly

In a WildFly-project, I have a big WAR-File (about 100 MB) which contains the whole application in JAR-Files (EJBs, GUI, Web Services etc)
In this WAR, there are some Functions which implement a custom Function interface (there are also other classes like AbstractFunction and so on). Now I would like to extend the application with user-provided functions (they should be on the class path which can then be accessed by the application.
The problem is that I can't deploy the functions before the main WAR because Function, AbstractFunction etc. are the the WAR which is not yet deployed.
Adding a WildFly module with the functions fails for the same reason.
One possibility would be to restructure the WAR file so that Function, AbstractionFunction are in an own jar which is deployed separately. Unfortunately, this would be a major refactoring which is not possible at the time being.
So is the only (simple) possibility to put the user-defined functions in a JAR into the WAR-file?
You can deploy user code as independent jar/war with EJB. EJB implements Function. Main module can lookup and find them through JNDI. Also you have to make common classes like Function and DTO available for user modules and for main war. The simplest way is share classes from main war. You can add META-INF/jboss-deployment-structure.xml to client modules:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<dependencies>
<module name="deployment.main.war"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
PS
I have similar project with structure:
core.war contains Plugin interface
set of plugin*.jar (dependent from core.war)
In my core.war I have code like:
Plugin srv = (Plugin) new InitialContext().lookup(jndi);
And my plugin looks like:
#Stateless
public class UserPlugin implements Plugin
JNDI looks like java:global/user-plugin/UserPlugin

Error inheriting a module in a mavenized GWT project

After adding this dependency in my pom.xml:
<dependency>
<groupId>com.eaio.uuid</groupId>
<artifactId>uuid</artifactId>
<version>3.2</version>
</dependency>
I get an error by jetty on the module load event:
no source code available for com.eaio.uuid; did you forget to inherit the module? unable to find com.client.myproject..`
What am I missing?
If you're using any of the classes in that artifact in your GWT compiled code, then the source code needs to be available, either packaged in the jar or as a source jar (remember that's another dependency).
You'll have to look for a .gwt.xml file in the jar, as this will be the name you need to inherit in your own GWT descriptor, eg. if the file is called com/eaio/UUID.gwt.xml you should
...
<inherits name="com.eaio.UUID" />
...
If one isn't available, just create your own with a simple <source path="..." /> and stick in the right package in your own project (still provided the source is actually available!)
Cheers,

WildFly AS 8.0 Error: org.hibernate.integrator.spi.Integrator: Provider org.hibernate.envers.event.EnversIntegrator not a subtype

I come from a heavy .NET/IIS background and although I have worked with Java in the past, I am fairly new to large Java web applications so please bear with me. Due to my limited background, I will walk through the steps I took from the very start trying to get this app to deploy (in case my "fix" for another issue could have broken something else).
I am having trouble deploying a Spring/Hibernate application to the WildFly application server. The application itself definitely works because it is a sample project in an open-source eCommerce framework (Broadleaf Commerce). I have also successfully got it to run on Jetty locally.
The application uses three JNDI data sources which I have configured in WildFly/JBoss; I have confirmed that the application sees them because I tried running it prior to configuring the DS's and it gave a clear error, which it no longer did after I configured them.
Afterwards, the application would throw three different errors (one per each PU) saying that it was unable to start the persistence units due to a class loading exception. This error I was able to fix by adding a jboss-deployment-structure.xml file into WEB-INF with the following contents (based on what I understand, this file is needed because this app has all of the Hibernate JARs within its WAR file already, and thus the below file tells JBoss not to supply its own Hibernate implementation):
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<exclusions>
<module name="org.hibernate"/>
<module name="org.javassist"/>
<module name="org.apache.log4j" />
</exclusions>
<dependencies>
<module name="org.jboss.ironjacamar.jdbcadapters" slot="main"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
After adding the above file, I now get this set of three (one per each PU) errors:
23:15:16,791 INFO [org.jboss.as.controller] (DeploymentScanner-threads - 2) JBAS014774: Service status report
JBAS014777: Services which failed to start: service jboss.persistenceunit."admin.war#blPU".__FIRST_PHASE__: org.jboss.msc.service.StartException in service jboss.persistenceunit."admin.war#blPU".__FIRST_PHASE__: java.util.ServiceConfigurationError: org.hibernate.integrator.spi.Integrator: Provider org.hibernate.envers.event.EnversIntegrator not a subtype
service jboss.persistenceunit."admin.war#blSecurePU".__FIRST_PHASE__: org.jboss.msc.service.StartException in service jboss.persistenceunit."admin.war#blSecurePU".__FIRST_PHASE__: java.util.ServiceConfigurationError: org.hibernate.integrator.spi.Integrator: Provider org.hibernate.envers.event.EnversIntegrator not a subtype
service jboss.persistenceunit."admin.war#blCMSStorage".__FIRST_PHASE__: org.jboss.msc.service.StartException in service jboss.persistenceunit."admin.war#blCMSStorage".__FIRST_PHASE__: java.util.ServiceConfigurationError: org.hibernate.integrator.spi.Integrator: Provider org.hibernate.envers.event.EnversIntegrator not a subtype
There is a file called hibernate-envers-4.1.11.Final.jar inside the WAR archive. Also remember that this is the same WAR (except the jboss-deployment-structure.xml file) which ran successfully on Jetty.
I tried poking around but simply have no idea where to look... I tried changing the DS's in WildFly to use a JDBC4-based driver as well as a JDBC41 (probably has nothing to do with it) with no luck. I know it is probably something very simple and is related to configuration (of either WildFly or the application itself), but I am not sure where to poke around.
My completely out of the blue take on it is that WildFly is still somehow trying to load an older version of Hibernate, which the classes in the bundled 4.1.11 Envers JAR are trying to override but cannot (or vice versa).
If it is of any use - the app is trying to connect to a PostgreSQL 9.3 database and the DS's defined in WildFly work as far as clicking "Test Connection" goes.
If there is any other info I can provide which would be helpful, please let me know.
Any insights or hints would be very much appreciated.
The Wildfly server has a Hibernate 4.3 version. To use Hibernate 4.1 you have to exclude the default Hibernate and package the correct one.
Class Loading in WildFly
Example:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclusions>
<module name="org.hibernate" />
<module name="org.hibernate.envers" />
<module name="org.hibernate.validator" />
<module name="org.hibernate.commons-annotations" />
</exclusions>
</deployment>
</jboss-deployment-structure>
I never figured out the cause of the issue (but I am figuring it was a conflict with the JARs supplied by JBoss).
Just in case anyone is having the same issue - I ended up using Tomcat where everything worked without a hitch. I understand this isn't exactly a solution but it will work in the interim. This also possibly reinforces my initial suspicion of the JARs provided by JBoss conflicting with the bundled Hibernate JARs in the project.

Categories