WAR extension strategy in Wildfly - java

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

Related

Glassfish java.lang.NoClassDefFoundError when using webapp as dependency

I'm trying to extend webapp functionality without redeploying webapp archive. App runs under Glassfish 3.
Basically, what I did is the following:
webapp.war contains some part.jar which is a part of webapplication. It contains some class SomeClass. Webapp allows some custom configuration where descendant of SomeClass may be loaded dynamically using Class.forName.
I derived ExtensionClass from SomeClass (ExtensionClass extends SomeClass), compiled it using part.jar and got some extension.jar.
I tried to put extension.jar into domain/lib and domain/lib/ext. But then app when loading ExtensionClass says java.lang.NoClassDefFoundError: SomeClass (note that it says about parent class). It seems that classloader which loads library cannot find the base class, which is contained in the webapp.
Goal: I'd like to extend app using dependencies from it but without rebuilding.
Question: what can be done in this case?
Edit
If I just put my extension.jar into applications/mywebapp/WEB-INF/libs it obviously works, as if I'd put it into webapp.war itself. But it is very dirty, I want to solve it without doing this dirtiness and without touching webapp.war.

Jackson 2 annotations ignored in EJB Jar with JBoss (6.2.0 GA)

I am migrating a web app from Websphere 7 (JEE5) to JBoss EAP 6.2.0 (JEE6). It currently works fine in Glassfish 3 & WAS.
The web interface consumes/produces JSON - so am using Jackson2 with Spring 3 MVC MappingJackson2HttpMessageConverter to handling (de)serialisation in a simple controller class.
In JBoss I see Jackson2 annotations #JsonProperty etc are being ignored in the ejb module - (they are applied to JPA entities only), but are being applied in the web module. So responses come back with different field names for some objects in JBoss which trips up our user interface.
I've tried every permuation of jboss-deployment-structure.xml to no avail (see below). I'm aware that JBoss ships with Jackson 1.x as an internal module. However, this doesn't seem to be the problem, otherwise the web module annotations would be ignored as well ? E.g.: Jackson annotations ignored after deployment to JBOSS
The app is structured as 3 maven modules - war, ejb (jar) & the ear container.
I'm going to refactor the code to remove the annotations from the JPA entities, but really it would be good to find a coherent solution, as there are several other apps to migrate.
JBoss descriptor I've tried below, makes no difference.
<jboss-deployment-structure>
<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
<deployment>
<exclusions>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
</exclusions>
</deployment>
<sub-deployment name="my-war.war">
<exclusions>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
</exclusions>
</sub-deployment>
<sub-deployment name="my-ejbs.jar">
<exclusions>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
</exclusions>
</sub-deployment>
</jboss-deployment-structure>
Initial Workaround (reverted now)
Whilst it does not address what the original problem was caused by, I have solved this by adding a Jackson Mixin within the web module to rename/suppress the fields concerned. I've tested this and it works fine.
The point about all this, is that by using a Jackson Mixin, the scope of the customisation of the serialisation has been confined to the web module, and thereby avoided possible class loading issues due to ejb-jar sub-deployment. No jboss-deployment-structure.xml is being used.
Add a Mixin
public interface MyMixin {
#JsonIgnore
String getUnwantedField();
#JsonProperty(value = "newName")
String getOldName();
}
Then in the startup of my web controller I wire in the Mixin to the Jackson ObjectMapper which is autowired into the controller and defined in my dispatcher servlet xml config.
#Autowired
private ObjectMapper objectMapper;
#PostConstruct
void configObjectMapper() {
objectMapper.addMixInAnnotations(MyEjbJar.class, MyMixin.class);
}
Dispatcher servlet:
.
.
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"/>
I have tracked this down (via IDE debugger & adding logging) to different classloaders being used for the war module and ejb jar module. This is expected default behaviour with JBoss AS 7 according to the docs. The war uses the war ModuleLoader, and the ejb jar uses the ear ModuleLoader.
What happens is the Class for the annotation differs depending on which class loader loads the annotation. Also see: similar issue on SO
By "differs" I mean they are the same annotation, sourced from the same jar & version, but they are not deemed equivalent according to the contract for equals, their hashcodes differ, therefore the JacksonAnnotationIntrospector does not locate annotations even though they show as held against the JPA POJO class.
Workaround
I have worked around this by making the ear ModuleLoader be a common loader for jackson 2. I did this by making the com.fasterxml.jackson.core databind dependency provided scope in the war & ejb jar, and marking it as a normal compile scope dependency in the ear POM.
This kind of approach is sort of endorsed here JBoss AS classloading although it uses the jboss-deployment-structure or MANIFEST.MF to achieve pretty much the same thing.

OpenCV as JBoss-as global module

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>

Deploying 2 war files with common classes in JBoss

I have two war file app1.war and app2.war deployed in a single JBoss instance. Package names for java classes for both war files starts with com.myapp
To add further, there are some Classes that are common between the two apps while there are some that have same fully qualified class names but are different (Source Code has changed).
I want to know, if this could pose threat of any kind to the deployment scenario?
You could get class loading problems if your applications are not isolated, i.e. have their own class loading repository and class loaders. If you configure JBoss to isolate the applications from each other you should be fine (I don't know what is the default for your version but 4.2.3 that we use does not isolate apps by default).
To clarify that a bit:
If you have two classes with different implementations but the same FQCN you could get the wrong class from the class loader for the application that is loaded second. Even if the implementation was the same you could get class cast exceptions or other strange behavior if one app gets the class from the other app.
I had a similar situation with multiple apps.Look at my solution here
Best way is to isolate class loading for your application archives.
For JBoss 5.1.0 GA following worked for me.
Create jboss-classloading.xml file in WEB-INF folder.
Added following lines to this file
Here,
export-all="NON_EMPTY" => Makes sure the classes loaded for this app is not exported
import-all="true" => Imports and uses all of the class definition available.
parent-first="false" => If more than one class with same name is found, one defined under the application will be used first.
FYI. This also helped me embedding the log configuration of log4j in the application war file. Will need to place log4j.xml in WEB-INF/classes and have a log4j.jar in WEB-INF/lib folder.
There will be one class loader instance for each application or standalone module. In other words, classes in app1.war will be loaded in different class loader than the classes in app2.war. This is the default behavior of any Java EE server; So it really doesn't matter about having classes with the same package/names and/or different content. This is the default behavior of any Java EE server.
Having said that, if you tweak the class loader policy of the server or try to load classes (reflect) using anything other than Thread.currentThread().getContextClassLoader(), you could be asking for trouble.

How to extend/customize a WAR with another project

We have the following scenario with our project:
A core web application packaged as a
war file (call it Core project).
The need to "customize" or "extend" the core app
per customer (call it Customer project). This mostly includes
new bean definitions (we're using
Spring), ie. replacing service
implementations in the core.war with
customer-specific implementations.
We want to develop the Core and Customer projects independently
When the Customer project is developed, we need to be able to run/debug it in Eclipse (on Tomcat) with the Core project as a dependency
When the Customer project is built, the resulting war file "includes" the core and customer projects. So this .war is the customer-specific version of the application
I'm looking for suggestions as to the best way to do this in terms of tooling and project configuration.
We're using Ant currently, but would like to avoid getting buried in more ant. Has anyone done this with Maven?
I've seen a lot of posts on how to build a web application that depends on a java application, but nothing on a web application depending on another web app.
Thanks!
Sounds like Maven WAR overlay does what you want.
In Eclipse there is a "native" WTP way to do this. It mainly using linked folders and a little hack in .settings/org.eclipse.wst.common.component file. You can read the article about it at http://www.informit.com/articles/article.aspx?p=759232&seqNum=3 the chapter called "Dividing a Web Module into Multiple Projects". The problem with this is that the linked folder must be relative to some path variable can be defined in Window/Preferences/General/Workspace/Linked Resources tab. Otherwise the linked folder definition (can be found in .project file in project root) will contain workstation specific path. The path variable practicly should be the workspace root. This solution works great with WTP, deploy and everything else works like it should.
The second solution is to use ant for it. Forget it. You will deeply regret it.
The third solution is to use maven for it. You can forget the comfort of WTP publishing if you dont do some tricks. Use war overlays like others suggested. Be sure to install both m2eclipse, m2eclipse extras. There is an extension plugin released recently, that can help you. Described at this blog. I did not try it, but looks ok. Anyway Maven have nothing to do with linked folders, so I think even the first solution and this maven overlay can live together if necessary.
As for headless builds you can use HeadlessEclipse for the first solution. It is dead (by me) now, but still works :). If you use the maven overlay + eclipse stuff, headless builds are covered by maven.
This is little bit more involved but at a high-level we do it as below. We have the core platform ui divided to multiple war modules based on the features (login-ui,catalog-mgmt-ui etc). Each of these core modules are customizable by the customer facing team.
We merge all of these modules during build time into 1 single war module. The merge rules are based on maven's assembly plugin.
You usually start from the Java source code. WARs don't include the Java source code, just the compiled classes under WEB-INF/classes or JARs under WEB-INF/libs.
What I would do is use Maven and start a brand new empty webapp project with it: http://maven.apache.org/guides/mini/guide-webapp.html
After you have the new empty project structure, copy the Java source code to it (src/main/java) and fill out the dependencies list in pom.xml.
Once you've done all this you can use mvn clean package to create a standard WAR file that you can deploy to Tomcat.
You might want to look into designing your core app with pluggable features based on interfaces.
For example say your core app has some concept of a User object and needs to provide support for common user based tasks. Create a UserStore interface;
public interface UserStore
{
public User validateUser(String username, String password) throws InvalidUserException;
public User getUser(String username);
public void addUser(User user);
public void deleteUser(User user);
public void updateUser(User user);
public List<User> listUsers();
}
You can then code your core app (logon logic, registration logic etc) against this interface. You might want to provide a default implementation of this interface in your core app, such as a DatabaseUserStore which would effectively be a DAO.
You then define the UserStore as a Spring bean and inject it where needed;
<bean id="userStore" class="com.mycorp.auth.DatabaseUserStore">
<constructor-arg ref="usersDataSource"/>
</bean>
This allows you to customise or extend the core app depending on specific customer's needs. If a customer wants to integrate the core app with their Active Directory server you write a LDAPUserStore class that implements your UserStore interface using LDAP. Configure it as a Spring bean and package the custom class as a dependant jar.
What you are left with is a core app which everyone uses, and a set of customer specific extensions that you can provide and sell seperately; heck, you can even have the customer write their own extensions.

Categories