Dean Hiller wrote on Oct 27, 2008 23:10:
So, I notice I can successfully deploy a jar with just entity beans and a persistence.xml to JBoss. I can successfully reference it from my ear as well using an ear's persistence.xml(though this results in the EJB layer loading twice in two classloaders).
If you want to make sure your shared persistence.xml is loaded only once put it in the EAR lib directory, it will then be visible to all EJB-modules and child WAR archives.
Now, I am trying to make the final step where my persistence.xml file has
where I assume JBoss will bind this to JNDI. Now, how do I have my ear lookup this JNDI EntityManagerFactory so that seam is creating and closing the EntityManagers???
Add this line in your persistence.xml so that jboss publishes a reference to the entityManagerFactory in global JNDI.
<property name="jboss.entity.manager.factory.jndi.name" value="java:/rdm-sdEntityManagerFactory" />
then you can reference the jndiName in components.xml
<persistence:managed-persistence-context name="entityManager" auto-create="true" persistence-unit-jndi-name="java:/rdm-sdEntityManagerFactory"> </persistence:managed-persistence-context>
Is there a way to do this so I can share the entitybeans and their cache between two web applications?
unless your WARs are packaged as part of the same EAR I don't think this is possible unless you use a shared EJB3 service layer that you call remotely in order to access your entity beans and leverage the shared cache.
The farthest I got with this is that it can't find the persistence context unless I have the ear's persistence.xml...yuck!!! There has to be a way to share this cache between applications otherwise, I mine as well go back to tomcat and use tomcats common/lib directory to reuse this layer.
I'm not sure I understand, what do you mean by ear's persistence.xml ? where did you package your persistence.xml exactly? In an ejb-module at the root of the EAR?
someone taught me that I could have this in the deploy directory
+-deploy +-entities.jar +-myapp.ear with persistence.xml
My persistence.xml then referred to the entities.jar from the myapp.ear which worked, BUT each ear like this causes entities.jar to load AGAIN into a new classloader which is not what I want. I did read some JBoss classloader stuff, but not sure how to tweak the settings right to get entities.jar to be in a parent classloader of both ear files.
I am going to try your way. I had entities.jar in the ear lib before but your persistence.xml code above is what I was missing I think as I could not get it to work at all. Let me try that.
My preference though is to have entities.jar in the deploy directory. I would think with the move to osgi you could do this....After all, I can do it in osgi just fine on knopflerfish platform!!!! In osgi everything is a library or a service and I can include or exclude any service from being visible from my app. JBoss needs to get to that point as it is really slick and easy to use!!!
I dont think you can load a JPA persistence unit JAR in a classloader above EAR classloaders in jboss classloader hierarchy.
My solution only works if all apps live in the same EAR. If that is not the case you need a remote EJB service layer to make your entity cache shareable.
I have tried to achieve this before. It's not nice with all the problems you get, and I also got recommended to put everything in the same ear, seems to be standard operating procedure according to what I've heard.
how about you include persistence.xml inside your entities.jar deployed directly in deploy dir ? would that work? I have never tried that but we never know...
yup, tried that. when you only have one persistence.xml and put that in entities.jar, the ear file stuff gives an error about not being able to find the persistenceUnit. Then you add a persistence.xml file to the ear(now have two, one in each archive). the 2nd one refers to entities.jar though. This results in it loading twice, so I wipe the persistence.xml from the entities.jar and it works but I can't share the classes.
NOTE: When it loads twice, default memory on jboss is not enough and jboss crashes for my entity layer which is 444 classes(many are composite keys though). The classes were generated from existing schema.
ok then afaik the largest persistence unit scoping you can have is at the EAR level which means in your case you probably need to include all partipipating apps or modules in the same EAR or use a reusable remote EJB service to wrap your entity layer.
I'm following this thread with interest as we're trying to do almost exactly the same thing. Have you made any progress?
I've tried to find more out about Guillaume's suggestion of using
a reusable remote EJB service to wrap your entity layer. Guillaume, by that do you mean on a separate physical machine, or is there some way of structuring this on the same server as the main application EARs (which is what we need to do)? Can you point me towards any information about how to achieve that?
remote EJB just means you have the call the EJB remotely not locally.
A local EJB ref is only good as long as you are in the same EAR (for classloader isolation reasons among other things).
You can certainly deploy several EARs to the same physical server instance and have them communicate between themselves using their remote interfaces.
Honestly, we gave up. I am hoping someday, they will start exposing the OSGi stuff which does a beautiful job(quite perfect) of letting you have 2 jars depend on another jar without the 2 jars being in the same classloader. In fact, it is very slick as you can actually specify the packages the apis are in and only expose that to the other 2 jars without exposing the implementation. I think JBoss is a bit behind here in making this convenient, but hopefully someday since from what I understand the neew microkernel is based on OSGi.
Honestly, OSGi can do way more complicated things in a simple fashion. I am very surprised JBoss just doesn't let us have the first jar in a parent classloader. that is one step closer to OSGi without using OSGi. There are many with this same situation where they have 10 applications and only want to redeploy one but the ear method forces them to redeploy all 10(ps. we are not going to go with the ear method...being able to deploy ONE app is a requirement for us)
Hi Gillaume, thanks for the reply.
OK, I think that remote calls add a level of complexity we can hopefully do without.
I have actually managed to achieve what I wanted, almost, by creating a Jar containing my entities and another containing shared classes/resources common to all apps deployed on this server and deploying those in the jboss-as/server/default directory.
almostbecause this works fine so long as the name of my shared jar sorts higher alphabetically than the name of my entity jar, which has classes that depend on classes in the shared jar.
If I rename the shared jar so that the entity jar loads first, I get startup errors due to depended-on classes being unavailable to the entity jar.
It may be possible to combine these two jars, but I'd prefer to avoid doing that. Is there any way I can influence the order in which JBoss loads these two jars? I'd prefer not to rely in alphabetical sorting of the names as this has a distinctly flaky feel about it!
OK, I managed to sort this one out myself. I added the name of the depended-on jar into the manifest in the dependent jar and that seems to have forced the correct loading order. Though I considered myself quite experienced in Java, I've actually never played with the
Class-Pathattribute in a jar manifest before. For those, like me, who haven't met it before, I simply created a META-INF/MANIFEST.MF file in my jar and added the following to it:
(no path needed, just the name of the jar).
So, now I have the following in my jboss-as/server/default path:
Where app1.ear, app2.ear and shared-ejb.jar all use classes from shared-classes.jar. app1.ear and app2.ear use persistence units defined in shared-ejb.jar/META-INF/persistence.xml (pointing at SQLServer and Oracle DBs FWIW) and everything seems to play happily together. app1.ear and app2.ear both define the same seam.jboss.org:loader in their META-INF/jboss-app.xml files which seems to ensure that all classes are loaded into the same space. AFAICT, only one instance of each persistence unit is being loaded (there are 3 units defined in the persistence.xml file) and we only have one set of classes so no ClassCastExceptions.
We've also put a single jboss-seam.jar into jboss-as/server/lib and that seems to have got rid of log entries complaining about multiple SeamPhaseListeners.
As I said, this all seems to be working nicely for us ATM and I thought I'd post the details so that:
- Others can benefit if they are trying to do the same thing; and
- People who know more about this than I do can suggest any pitfalls we may not have thought of/encountered.
good call Rob.
But this also means that your 2 EARs have highly coupled dependencies, it might be ok for you if the 2 apps are really just 1 app but deployable in different units. i.e. it allows you to restart 1 app while keeping the other running.
I'm curious though, how does jboss load persistence units declared in the shared-ejb.jar that is in server/default/lib dir ?
Can you do me a quick favor and run a test?
In both applications put in the following log statements
log.info("ejb3 bean class from app1="+bean.class+ " classloader="+bean.class.getClassloader());
and in app2
log.info("ejb3 bean class from app2="+bean.class+ " classloader="+bean.class.getClassloader());
This proves or disproves they are sharing the same exact class and that the class is not loaded twice. If sharing is the case, we are going to try to copy what you did and have our two ears depending on our ejb.jar. could you please run this test?