Running CFGroovy on in a Hibernate-Aware Environment

In my last post I mentioned the issue with using CFGroovy's Hibernate when Hibernate is already loaded by the app server, such as the case with JBoss 4.2+ and a certain unreleased CFML runtime (cough … Centaur … cough).  The gist of it is that Hibernate appears to create some static references to itself that circumvent the RootLoader that CFGroovy uses to isolate it's Hibernate environment.  These static references get used because they already exist, so the classloader doesn't bother to load the classes from the RootLoader.  As such Class comparisons fail within Hibernate's class hierarchy, because Class equality is both on the Class name and the ClassLoader used to load it.

Fortunately, this problem is mostly a "getting started" issue.  I can't think of many places where you'd want to use CFGroovy's Hibernate and some other Hibernate environment in the same webapp (a partial port or an app being the one I can think of).  As such, it's very unlikely you actually need multiple copies of Hibernate in your webapp classpath.  And that means that you can get CFGroovy's Hibernate support to work simply by removing some unneeded JAR files.

For the unreleased CFML runtime that bundles Hibernate, simply removing /WEB-INF/cfusion/lib/hibernate3.jar will allow CFGroovy's Hibernate support to work.  This means you can't use that runtime's Hibernate-backed features, but if you're using CFGroovy's Hibernate support, you probably don't need it.

For JBoss, Patrick Santora did some digging and had this to say:

Removed a few jars from within the jboss node I have cfgroovy running in "{node}\lib":
  antlr.jar
  hibernate3.jar
  hibernate-annotations.jar
  hibernate-entitymanager.jar

Removed a few jars from within the cfgroovy hibernate_lib node:
  cglib-nodep-2.1_3.jar
  commons-collections.jar
  commons-httpclient.jar
  commons-logging.jar
  dom4j-1.6.1.jar
  ejb3-persistence.jar

Start the jboss node and done.

The removed jboss jar's were in the cfgroovy folder and vice versa so I
just needed to do a comparison. Removing those conflicts fixed the
problem.

I am running on jboss 4.3.2 and Railo 3 war (community edition license)

I don't have a JBoss environment to confirm this on, but he said he's now up and running.

13 responses to “Running CFGroovy on in a Hibernate-Aware Environment”

  1. Sami Hoda

    Keep it up Barney! We're following CF/Groovy integration intently.

  2. Patrick Santora

    For those who may have issues getting this going feel free to ping me and I will assist however I can.

    Keep it up Barney, this is some slick stuff!!

  3. denny

    By removing the hibernate jars from the {node}\lib folder, you're actually removing them from the server's classpath, not just a web applicaiton, right?

    I use JBoss clustering, which uses hibernate for some stuff, so I don't think removing the hibernate jars on the jboss side will work for me.

    I'm sure there is some way to set the context classloader, or something similar (perhaps there is another way to load a resource which will bypass the classloading error?), to get around the cfgroovy-hibernate classloading issue, but so far, I haven't found the answer.

    Glad to see you're keeping folks posted about this, Barney! If I stumble upon something "pretty" that works I'll holler.

  4. denny

    Hmm… I'm pretty sure that the clustering and cache stuff is like a level above WAR and EAR deployment… I'm pretty sure JBoss itself is doing things with hibernate, before it ever tries to fire up WARs and such (at least if you're using clustering and cache whatnots).

    And, other apps can include hibernate and work, so I think that the main problem is how the classloading/dynamic stuff is resolving things, or some such.

    Changing to a child first classloading deal for the EAR I have railo in doesn't do anything different for cfgroovy, but cfgroovy isn't being deployed the way a WAR or EAR would be, so… eh.

    'course, there's always the route of compiling the model sources first, and including them while loading hibernate; which probably wouldn't be too bad, as that's sorta what happens anyways… eh*2.

    It might have taken me 8 years or so to figure out how to include commons-logging without messing up other applications, but I did it. This seems similar, but not as inherently broken, so hopefully in like 4 or so, perhaps 6 to be safe… :-)

  5. Henry Ho

    Does that mean I cannot use CF9's hibernate features together with cfgroovy + hibernate in the future?

  6. Henry Ho

    seamless scriptlets? oh, I thought it is already implemented… What does it do? :)

    Hmm… I just don't want my app to be broken when upgraded to CF9. Hope things will work out better later.

  7. denny

    Using a URL classloader that's not in the server scope generally leads to threads that cannot be garbage collected… dunno if that's part of what's going on, but it's a possibility, maybe.

    I think the problem with Hibernate is that it uses the thread local context or whatever, and you're swapping the thread contexts around with the classloading, so the context that loads Hibernate isn't the same one using it (or something like that perhaps).

    I'm pretty sure I've gotten hibernate to load in a classloader (had to be real careful that it didn't go "outside", like for dom4j (to read config.xml — I think I used properties instead)), so IIRC, it's doable, at least.

    Had any luck using pre-compiled entities?

  8. denny

    I was thinking the pre-compiled entities would only be pre-compiled for the groovyLoader, not for the application as a whole, so you could re-compile and re-load on the fly.

    I had some relative success doing that for Hibernate alone, in a classloader, so as to get the "on the fly" loveliness. I was doing a lot with the entity-based hibernate objects (hashmaps), to get a lot of dynamicalness out of it, too. Haven't decided which is better… hibernate is basically a whole framework-ish-deal, when you get really into it– but then your model is hibernate-based, which might kinda suck sometimes…

    I was thinking the groovyLoader, being designed for crazy classloading, might not have such a rough time with garbage collection and whatnot. Eh.

    Been experimenting here and there (mostly checking out GORM-without-Grails stuff lately, as it sounds nifty), but I haven't really messed with a spring-based java model… after all the stuff I've seen lately tho, spring is at least as cool as ColdSpring ;-), might not be a bad thing to look into…

    If the server isn't running out of memory while you're doing all your groovy stuff, then it looks like garbage collection *is* better when using a groovy classloader…. are you sure the reason it's running out of memory after a while isn't the URLClassLoader you're using to put groovy itself into play?

    I've been doing a lot of load testing lately, guess I can slap some experiments together to see what happens.