I have recently been given the task of getting the Pentaho BIServer to deploy within JBoss5 AS. Classloading has aparently been completely reworked in v5 vs v4 and prior. The new way to customize classloading behavior is to write up a jboss-classloading.xml file and drop it in various spots within your application to be deployed. After many hours of being frustrated reading blog and forum posts and not finding a single source of information on exactly what the jboss-classloading.xml is and does and where to put it, I figured I’d try to save someone else (and myself later after I forget this) the same pain I’ve experienced. Below I answer some of the questions I had on my journey.
Where do I place a jboss-classloading.xml file?
To control classloading behavior of an..
- ..EAR, place it in the META-INF of the ear, e.g. myapp.ear/META-INF/jboss-classloading.xml
- ..WAR, place it in the WEB-INF of the war, e.g. myapp.war/WEB-INF/jboss-classloading.xml
- ..JAR, place it in the META-INF of the jar, e.g. mylib.jar/META-INF/jboss-classloading.xml (I’ve not personally tried this but you can find info on this in JBoss forums)
What are all the attributes and what do they mean?
- name – typically the name of war or ear, e.g. “myapp.war”
- import-all – (“true”/”false”) – true means make all classes exported from other applications visible to this application
- export-all – value “NON_EMPTY” – all classes are exposed to other applications
- domain – a classloading domain, can be an arbitrary name but typically you will want to name it the name of your application, e.g. “myapp.ear” or “myapp.war”. If a domain by that name already exists, your app will join that classloading domain.
- parent-domain – default is “DefaultDomain” which is shared with all other applications that don’t specify a domain. If you prefer to delegate to an explicit parent domain when a class is not found in yours, then specify an existing domain here, as in delegating to an EAR’s domain, e.g. “myapp.ear”
- top-level-classloader – used to enable embedded apps, such as a war within an EAR, to participate in a top-level domain (see JBCL-125)
- parent-first (“true”/”false”) – if false, the app is in non-j2ee compliance mode, where the app’s domain is searched first for a class before searching the parent domain. The default for top-level deployed WARs is “false”, however, I have found that the default behavior for WARs within EARs is “true”
How do I deploy a WAR within an EAR in which the WAR can see all jars in the EAR, but the EAR’s classes trump JBoss’s?
The original problem I had was the Pentaho BIServer application uses a more recent version of commons-collections.jar, more recent than the one in JBoss’s own library. When deploying the Pentaho WAR outside of an EAR, I did not have a problem since as of JBoss5, WARs are deployed with a classloading scheme that looks up classes within the WAR first, before delegating to the parent domain. However, when I deployed the Pentaho EAR I saw the opposite, as if JBoss’s copy of commons-collections.jar was found first, not the EAR’s classes first. I needed to override this behavior such that EAR classes are preferred over JBoss’s. The situation I started with was a pentaho.war within a pentaho.ear and no jboss-classloading.xml files present. As I mentioned earlier, once I deployed this, JBoss libs were preferred over mine. So I had to go to work authoring some custom classloading. Here’s what I wound up with:
Contents of jboss-classloading.xml in pentaho.ear/META_INF:
<classloading xmlns="urn:jboss:classloading:1.0" domain="pentaho.ear" export-all="NON_EMPTY" import-all="true" parent-first="false"> </classloading>
The important parts here: (1) we are specifing that the pentaho.ear application participate in it’s own domain “pentaho.ear”. This is so in the embedded war, we can declare this domain as it’s parent. (2) by setting parent-first to false, we are essentially declaring that EARs classes be preferred over JBoss’s (in the DefaultDomain presumably).
One funny side-effect to mention here is that I was actually able to deploy an EAR in which javax.servlet.HttpServlet was not found during deployment. Amazing that this is even possible, but it happened. The jboss-classloading.xml file that made this happen included only a parent-first=”false” attribute, nothing else. I haven’t eliminated the attrs one-by-one to find out which is responsible for this; I suspect perhaps import-all.
Contents of jboss-classloading.xml in pentaho.ear/pentaho.war/WEB-INF:
<classloading xmlns="urn:jboss:classloading:1.0" domain="pentaho.war" parent-domain="pentaho.ear" export-all="NON_EMPTY" import-all="true"> </classloading>
The most important bit here is the pentaho.war is in it’s own domain “pentaho.war”, but delegates to the EAR’s CL domain, “pentaho.ear”. This enables the WAR to see classes within jars deployed at the EAR level. The pentaho.war in the case of an EAR deployment has no libs in WEB-INF/lib, so it must rely on the EAR for jars.
Result? Once I dropped these files in, the app “just worked”. My app found my commons-collections.jar and not JBoss’s.
FYI, the most helpful article on the subject I found during this effort was http://java.dzone.com/articles/jboss-microcontainer-classloading
/phyto
Hi phyto,
your first blog entry is already on advanced (and mind boggling) stuff. Can’t wait for the follow up 🙂
Cheers
Slawo
Thanks Slawo, I’ll try to not disappoint 🙂
Hi , I’m trying to deploy an app in which the packaging is EAR and SAR (Scheduler)
SAR is not in the EAR. Could you please help me in how to configure the jboss-classloading.xml files? I have defined one in ear/META-INF and the other in SAR folder/META-INF (SAR folder has META-INF folder and it’s app specific jar). Sar is not deployed – complains that classes from EAR are not found.
A year late on this one, but I’m wondering if you ever got to the bottom of this issue Shravani? I have a SAR, and would like that SAR to be able to access the classpath of the overall profile (e.g. the deploy folder, the conf folder etc). I also have a requirement for the solution to be generic, and not refer to the profile name, because I want the SAR to be something that can be dropped into JBOSS_HOME/server//deploy and perform a generic utility duty.
Any help, much appreciated.
Hey, nice post!
I hope you come to our forums next time,
for such issues, so it’s not so painful. 😉
I tend to answer mostly everything that drops into our MC forum.
(or did I miss your post? — the notification has been broken lately :-()
Could you somehow push this post to our wiki,
or at least link it somehow?
Cheers, Ales
Thanks Ales! I’ll be sure to do that next time 😉 .. and I have added this post to the JBoss MicroKernel FAQ
Another tip I’ve found, to debug classloading problems, turn on trace logging in server/default/conf/jboss-log4j.xml:
Hey man! You saved my day! Thanks a lot for your help!
Huges,
Adauto from Brazil! 🙂
No problem, I’m glad it was useful 🙂
Thanks for this post, it helped me a lot! Some follow-on questions if you have time please:
1. In the WAR file’s jboss-classloading.xml file, why can’t you simply tell the WAR file to be in the same CL domain as the EAR file?
2. How can you stop the EAR file from loading *any* classes from JBoss’ lib folders?
FYI, for those using JBoss 6, logging is now configured by
server/[xxx]/deploy/jboss-logging.xml
.@Andrew – regarding your first point, I don’t recall if i tried that approach, it’s definitely worth a try. To your second point, if you see my paragraph starting “One funny side-effect…”, you’ll notice that I did in fact see behavior in which JBoss’s libraries seemed to be completely ignored. Perhaps that will do what you want (import-all=”false”). Thanks for the update on the logging configuration for JBoss6
Cheers!
Hi Phyto,
I followed your suggestion setup jboss-classloading.xml in war and ear, when I deployed my app to JBoss 5, the conflicts with Hibernate jar contained in JBoss is gone, however, there was still issues with myfaces jars.
After some researches, I added the below context-param in the web.xml file to eliminate myfaces conflicts.
org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL
true
Now I deploy my app again, I get ClassCastException for javax.servlet.* e.g. javax.servlet.Filter and javax.servlet.Servlet. So it looks like it still have conflicts with servlet-api.jar in common/lib in JBoss. Also tried to set import-all = false. but it didn’t make any difference. Can you please advise? (I used the same approach for war on its own and I reach the same issue). Thanks in advance.
There is my class loading files for ear which contains war:
in the ear/META-INF:
in the war/WEB-INF:
The below is my class loading file for war on its own: (tried with or without top-level-classloader attribute)
There is my class loading files for ear which contains war:
in the ear/META-INF:
<classloading xmlns=”urn:jboss:classloading:1.0″
domain=”my-app.ear”
export-all=”NON_EMPTY”
import-all=”true”
parent-first=”false”>
</classloading>
in the war/WEB-INF:
<classloading xmlns=”urn:jboss:classloading:1.0″
domain=”my-web.war”
parent-domain=”my-app.ear”
export-all=”NON_EMPTY”
import-all=”true”
parent-first=”false”>
</classloading>
The below is my class loading file for war on its own: (tried with or without top-level-classloader attribute)
<classloading xmlns=”urn:jboss:classloading:1.0″
domain=”my-web.war”
parent-domain=”DefaultDomain”
export-all=”NON_EMPTY”
import-all=”true”
parent-first=”false”
top-level-classloader=”true”>
</classloading>
Hi,
Recently we have migrated from JBOSS 4.0.3SP1 to 5.1.0GA, after this migration we are facing tricky
classloading issue, whereas the same was working fine in the earlier JBOSS version (4.0.3SP1).
This application exposes SOAP services (using AXIS 1.2.1) to the third party applications.
Below is how my application structure looks like:
sampleapplication.ear
|
– myEjb.jar
– others.jar
– myProvisioningImpl.jar – this jar contains one class file (MyTestClass.class) which is used in myWebApp.war also.
– META-INF
|
– application.xml
– jboss-app.xml
– myWebApp.war
|
– provisioning
|
– deploy.wsdd
– undeploy.wsdd
– WEB-INF
|
– jboss-classloading.xml
– web.xml
– context.xml
– lib
|
– axis.jar
– saaj.jar
– wsdl4j.jar
– jaxrpc.jar
– myFiles.jar – this jar also contains MyTestClass.class.
The issue is MyTestClass.class file is very much required in both the jar files i.e.
one part of EAR and other part of WAR file, now when I invoke a method from WAR to EAR by passing in
the MyTestClass as an argument to the method, I am getting
java.lang.LinkageError: loader constraint violation: when resolving method.
The reason for the LinkageError being classloaders having the same the class file MyTestClass.class.
How do I get around the issue, i.e. retaining the files as it is in corresponding jars and
tweaking the classloading if possible.
Any help is greatly appreciated.
Attaching logs for reference:
In working system, JBOSS 4.0.3SP1 :-
server.log.4:2011-04-09 21:43:12,056 TRACE [org.jboss.mx.loading.RepositoryClassLoader] getResourceLocally(org.jboss.mx.loading.UnifiedClassLoader3@1200435{ url=file:/export/home/jboss/server/insight/deploy/sampleapplication.ear/ ,addedOrder=180}), name=com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class, resURL:jar:file:/export/home/jboss/server/insight/tmp/deploy/tmp231834378526396546myProvisioningImpl.jar/com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class
server.log.4:2011-04-09 21:43:12,057 TRACE [org.jboss.mx.loading.RepositoryClassLoader] getResourceLocally(org.jboss.mx.loading.UnifiedClassLoader3@17a36e1{ url=null ,addedOrder=0}), name=com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class, resURL:null
server.log.4:2011-04-09 21:43:12,085 TRACE [org.jboss.mx.loading.RepositoryClassLoader] loadClassLocally, org.jboss.mx.loading.UnifiedClassLoader3@1200435{ url=file:/export/home/jboss/server/insight/deploy/sampleapplication.ear/ ,addedOrder=180} name=com.networks.ems.lawfulintercept.webservice.model.MyTestClass class=class com.networks.ems.lawfulintercept.webservice.model.MyTestClass cl=org.jboss.mx.loading.UnifiedClassLoader3@1200435{ url=file:/export/home/jboss/server/insight/deploy/sampleapplication.ear/ ,addedOrder=180}
server.log.4:2011-04-09 21:43:12,086 TRACE [org.jboss.mx.loading.RepositoryClassLoader] loadClass org.jboss.mx.loading.UnifiedClassLoader3@1200435{ url=file:/export/home/jboss/server/insight/deploy/sampleapplication.ear/ ,addedOrder=180} name=com.networks.ems.lawfulintercept.webservice.model.MyTestClass class=class com.networks.ems.lawfulintercept.webservice.model.MyTestClass cl=org.jboss.mx.loading.UnifiedClassLoader3@1200435{ url=file:/export/home/jboss/server/insight/deploy/sampleapplication.ear/ ,addedOrder=180}
Logs from non working system, JBOSS 5.1.0GA:-
server_74.24.log(640919): 13:18:49,663 TRACE (http-0.0.0.0-80-3) [org.jboss.logging.Logger] ClassLoaderDomain@3b1e8b{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/myWebApp.war/} findLoader com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class classLoader=BaseClassLoader@152441a{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/myWebApp.war/} allExports=false findInParent=false
server_74.24.log(640921): 13:18:49,666 TRACE (http-0.0.0.0-80-3) [org.jboss.logging.Logger] ClassLoaderDomain@3b1e8b{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/myWebApp.war/} trying to load com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class from all exports of package com.networks.ems.lawfulintercept.webservice.model [VFSClassLoaderPolicy@1f530ab{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/myWebApp.war/}]
server_74.24.log(640923): 13:18:49,668 TRACE (http-0.0.0.0-80-3) [org.jboss.logging.Logger] BaseClassLoader@152441a{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/myWebApp.war/} get resource locally com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class
server_74.24.log(640925): 13:18:49,671 TRACE (http-0.0.0.0-80-3) [org.jboss.logging.Logger] BaseClassLoader@152441a{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/myWebApp.war/} got resource locally com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class
server_74.24.log(839888): 13:26:51,784 TRACE (http-0.0.0.0-80-5) [org.jboss.logging.Logger] ClassLoaderDomain@12b71a3{com.networks.ems:loader=liTargetProvisioning} findLoader com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class classLoader=BaseClassLoader@131b732{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/} allExports=false findInParent=true
server_74.24.log(839890): 13:26:51,788 TRACE (http-0.0.0.0-80-5) [org.jboss.logging.Logger] ClassLoaderDomain@12b71a3{com.networks.ems:loader=liTargetProvisioning} trying to load com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class from all exports of package com.networks.ems.lawfulintercept.webservice.model [VFSClassLoaderPolicy@f250f3{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/}]
server_74.24.log(839892): 13:26:51,791 TRACE (http-0.0.0.0-80-5) [org.jboss.logging.Logger] BaseClassLoader@131b732{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/} get resource locally com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class
server_74.24.log(839893): 13:26:51,794 TRACE (http-0.0.0.0-80-5) [org.jboss.logging.Logger] BaseClassLoader@131b732{vfsfile:/export/home/jboss/server/insight/deploy/sampleapplication.ear/} got resource locally com/networks/ems/lawfulintercept/webservice/model/MyTestClass.class
Thanks
Senthil Jayakumar
Hi JingleBell,
Did you resolve this issue? I’m having the same trouble with Jboss 6.
Hi Dipi,
No I dont have it fully resolved. what I have posted here, should correct, cos I have get some of my projects working with this config. but I suspect this isolation is only working if the conflicts jars are located in common/lib folder, if the conflicts jar in the your server instance deploy or deployers folder, this config will not be able to isolate them. Researched online, it seems to have to use what JBoss provides to us. But I am still trying to find if there is alternative for this area. BTW, I am working on JBoss 5.1.0. I think JBoss 6, there is jboss-domain.xml you can use, maybe you can try look into that.
nice post.thanks!
Hi phyto,
i am having a ear where i have a jar(ejb) and war files within it. i am able to deploy the ear when some of the lib are removed from the ear/lib. when i try to use the classloader in my ear i am getting some issue with SAXParser. Below is the classloader files. Can u let me know what am i doing wrong here?
ear/META_INF/jboss-classloading.xml
ear/myweb/WEB-INF/jboss-classloading.xml
Thanks in advance,
Cheers, Naveen.
This is definitely a nice post, thank for your efforts.
Very well-written post. Had helped me a lot.
Pingback: Having fun with Jboss classloader – or how I figured out how to get my application to work in Jboss 5 | Huima
Thanks for the help, this blog was very instrumental in me figuring something out.
Pingback: JBoss Class loading revisited | Miscellaneous musings in beta
Works!
Thank you very much.
Hi,
I am not sure if this is too late to ask. But I am using Jboss 5.1. I am trying to deploy my war file using above configuration that is defined in blog. However, it looks like it is not working. I am still getting errors reated to XercesImpl.jar etc etc. I am keeping the above configuration file in WEB-INF/.
Please let me know if I am doing anything wrong here.
Regards,
Abhinav Singhal
Nice very informative.
This post was exactly what I needed! Thanks!
Pingback: Sonar 2.3 + Jboss 5.1 | Blog de BBVA GlobalNet
Nice post. I was checking continuously this weblog and I am impressed!
Very useful information specifically the last phase :
) I deal with such information a lot. I used to be looking for this certain information for a long time.
Thank you and good luck.
Spot on with this write-up, I actually think
this web site needs a great deal more attention. I’ll probably be back again to see more, thanks for the advice!