Java+Jboss+Hibernate rant

Warning. This is a rant. This is the result of several weeks clawing up the learning cliff on this environment, and it’s really wearing me down. You have been warned.
I’m have a Hard Time [tm] [reg us pat off] implementing stuff in this environment. The complexity level is enormous, and no one really has a good clue on how to do it properly. The level of knowledge needed to implement even a basic application is astronomical, and the number of ways it can possibly go wrong are mind boggling.
The simple thing is, this shouldn’t be that hard. I have a JBoss J2EE server. That’s an application server environment, you’re suposed to be able to deploy your applications into it, and they’re in a managed, hosted mechanism. Sounds simple, right?
Well Jboss (as well as other J2EE containers) provide various hooks and services for the applications they host. The problem is, those hooks and services are not well documented, and are so generic trying to fix a specific problem is maddening.
In this case, I’m using the persistent object engine that JBoss supports (Hibernate), and I can’t even get a a simple “Create this row in that table” working. Why? Because here’s what has to happen to run an application that creates One. Count ’em. One row in a SQL table managed by hibernate.

  1. The sessionbean needs to be created
  2. The Hibernate mappings definitions need to be written
  3. The baseline object for the row needs to be written
  4. The Hibernate configuration XML file needs to be put in place.
  5. The MySQL JDBC connection has be implemented
  6. Jboss needs to be told to provide that JDBC session as a service, and mapped into JNDI
  7. The application archive (EAR) file needs to contain all components of the application, including the deployment descriptors, the servlet definitions for client access, and all the EJB pieces, which are plentiful in their own right
  8. The database has to have the schema configured
  9. The app has to be deployed and you PRAY that that all works when it’s dropped into the appserver. Watch the logs for all the errors.

Once that’s all deployed, you try it. The servlet is the ‘easiest’ way to access an EJB, so hit the servlet. The servlet has to call the EJB, which in this case is a Stateless Sessionbean, by far the EASIEST (COUGH) type of J2EE object to work with. The bean in turn is supposed to ask Hibernate for configuation information, session details, and talk to the managed datasource connection in JBoss.
But lo! There’s a problem! This is a MANAGED environment. That means it must have transactions. JBoss has it’s own transaction manager (JTA), which has to manage all commit/rollback actions. But, since JTA is acting as the manager between Hibernate and the database, certain things can’t work. Like, oh, the basic “auto-increment the primary key” id that every database on the planet uses. Hibernate keys data based on a unique key. It comes iwht a simple ‘hilo’ mechanism that will generate those keys whenever you create a new instance of the persistent object, but THESE DONT WORK IN JBOSS. You have to MANUALLY write your own key generator for every type of object you need to instantiate.
This is INSANE. Now I have to deploy a whole new EJB just to manage the persistent object keys in Hibernate.
“Gosh Dave. That sounds silly. Why doesn’t someone write that into the system?”
Why? Because every webpage I find either says “oh, this is easy, just whip up XYZ to manage it.” or says “Use XDoclet to create this” (yet another system I’d have to learn just to generate the code to manage the objects i’m creating).
While I understand that huge flexibility in Java is a good thing, this level of abstraction and complexity really is driving me absolutely batshit. I just want to settle down and write my code, but finally, after getting Hibernate to actually CONNECT to the database and show that things are ready, I’m faced with the unhelpful error that looks like this:

12:36:50,522 INFO  [SessionFactoryObjectFactory] Bound factory to JNDI name: java:comp/env/hibernate/SessionFactory
12:36:50,522 WARN  [SessionFactoryObjectFactory] InitialContext did not implement EventContext
12:36:50,532 WARN  [JDBCExceptionReporter] SQL Error: 0, SQLState: null
12:36:50,533 ERROR [JDBCExceptionReporter] You cannot commit during a managed transaction!
12:36:50,534 ERROR [JDBCExceptionReporter] Could not save object
java.sql.SQLException: You cannot commit during a managed transaction!
at org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:499)
at org.jboss.resource.adapter.jdbc.WrappedConnection.commit(WrappedConnection.java:451)
at net.sf.hibernate.id.TableGenerator.generate(TableGenerator.java:126)

It’s enough to make you cry.
Update, 1/2 hour later – there’s a little-documented function in the Hibernate XML spec. Click through for details.


If you specify:

<generator class="native">

it will use whatever auto-increment key mechanism is available in the database server. This has just eliminated the whole transaction problem I was running into, and had me successfully run a single update.
Want to see what it looks like? Here’s JBoss Doing The Right thing and instantiating a ‘Planet’ object and saving away the info…
14:05:59,563 INFO [TomcatDeployer] undeploy, ctxPath=/game, warUrl=file:/home/dbs/jboss/jboss-4.0.1sp1/server/default/tmp/deploy/tmp43929game.ear-contents/game.war/
14:05:59,587 INFO [EJBDeployer] Undeploying: file:/home/dbs/jboss/jboss-4.0.1sp1/server/default/tmp/deploy/tmp43929game.ear-contents/game.jar
14:05:59,634 INFO [EjbModule] Undeployed Game
14:05:59,639 INFO [EARDeployer] Undeploying J2EE application, destroy step: file:/home/dbs/jboss/jboss-4.0.1sp1/server/default/deploy/game.ear
14:05:59,643 INFO [EARDeployer] Init J2EE application: file:/home/dbs/jboss/jboss-4.0.1sp1/server/default/deploy/game.ear
14:05:59,856 INFO [EjbModule] Deploying Game
14:06:00,178 INFO [EJBDeployer] Deployed: file:/home/dbs/jboss/jboss-4.0.1sp1/server/default/tmp/deploy/tmp43930game.ear-contents/game.jar
14:06:00,208 INFO [TomcatDeployer] deploy, ctxPath=/game, warUrl=file:/home/dbs/jboss/jboss-4.0.1sp1/server/default/tmp/deploy/tmp43930game.ear-contents/game.war/
14:06:00,416 INFO [EARDeployer] Started J2EE application: file:/home/dbs/jboss/jboss-4.0.1sp1/server/default/deploy/game.ear
14:07:29,680 INFO [STDOUT] ——————————————————
14:07:29,681 INFO [STDOUT] Configuring…
14:07:29,682 INFO [Configuration] configuring from resource: /hibernate.cfg.xml
14:07:29,682 INFO [Configuration] Configuration resource: /hibernate.cfg.xml
14:07:29,726 INFO [Configuration] Mapping resource: com/stonekeep/game/db/Planet.hbm.xml
14:07:29,790 INFO [Binder] Mapping class: com.stonekeep.game.db.Planet -> planets
14:07:29,792 INFO [Configuration] Configured SessionFactory: java:comp/env/hibernate/SessionFactory
14:07:29,794 INFO [STDOUT] Done…
14:07:29,794 INFO [STDOUT] Instantiating, setting, and saving…
14:07:29,795 INFO [Configuration] processing one-to-many association mappings
14:07:29,795 INFO [Configuration] processing one-to-one association property references
14:07:29,795 INFO [Configuration] processing foreign key constraints
14:07:29,796 INFO [Dialect] Using dialect: net.sf.hibernate.dialect.MySQLDialect
14:07:29,797 INFO [SettingsFactory] Maximim outer join fetch depth: 2
14:07:29,797 INFO [SettingsFactory] Use outer join fetching: true
14:07:29,798 INFO [NamingHelper] JNDI InitialContext properties:{}
14:07:29,802 INFO [DatasourceConnectionProvider] Using datasource: java:/MySqlDS
14:07:29,802 INFO [TransactionFactoryFactory] Transaction strategy: net.sf.hibernate.transaction.JTATransactionFactory
14:07:29,803 INFO [NamingHelper] JNDI InitialContext properties:{}
14:07:29,804 INFO [TransactionManagerLookupFactory] No TransactionManagerLookup configured (in JTA environment, use of process level read-write cache is not recommended)
14:07:29,805 INFO [TransactionManagerLookupFactory] No TransactionManagerLookup configured (in JTA environment, use of process level read-write cache is not recommended)
14:07:29,808 INFO [SettingsFactory] Use scrollable result sets: true
14:07:29,809 INFO [SettingsFactory] Use JDBC3 getGeneratedKeys(): false
14:07:29,809 INFO [SettingsFactory] Optimize cache for minimal puts: false
14:07:29,810 INFO [SettingsFactory] Query language substitutions: {}
14:07:29,810 INFO [SettingsFactory] cache provider: net.sf.hibernate.cache.EhCacheProvider
14:07:29,810 INFO [Configuration] instantiating and configuring caches
14:07:29,811 INFO [SessionFactoryImpl] building session factory
14:07:29,957 INFO [SessionFactoryObjectFactory] Factory name: java:comp/env/hibernate/SessionFactory
14:07:29,958 INFO [NamingHelper] JNDI InitialContext properties:{}
14:07:29,961 INFO [NamingHelper] Creating subcontext: hibernate
14:07:29,962 INFO [SessionFactoryObjectFactory] Bound factory to JNDI name: java:comp/env/hibernate/SessionFactory
14:07:29,962 WARN [SessionFactoryObjectFactory] InitialContext did not implement EventContext
14:07:29,971 INFO [STDOUT] Closing session…
14:07:29,972 INFO [STDOUT] Done!
NOW i can go to lunch.

About

A wandering geek. Toys, shiny things, pursuits and distractions.

View all posts by

7 thoughts on “Java+Jboss+Hibernate rant

  1. If you specify what? Ain’t nothin’ showing up there. 🙂
    Oopsie! All fixed now. Durned embedded XML tags.

  2. So, about 14 years ago, when I was writing stuff for MacOS in C, it took about 50 lines of code for “Hello, World”, much less anything else.
    How did we end up with cargo-cult boilerplate hell again?

  3. I was looking up “No TransactionManagerLookup configured” with Google and ended up here. See, my application suddenly stopped working. It was fine last friday, but come monday morning and the scene has changed completely. I’ve done absolutely nothing with to my configurations, but now the last thing I see on my console is:
    07:03:44,064 INFO[TransactionManagerLookupFactory] No TransactionManagerLookup configured (in JTA environment, use of process level read-write cache is not recommended)
    BRILLIANT!
    I hate this bullshit.

Comments are closed.