JBoss-Hibernate Integration (Hibernate 2)

    - Steve Ebersole, JBoss Inc




    As of version 3.2.6{FOOTNOTE RED #1 1}, JBoss comes with built-in support for utilizing Hibernate within application code. This support

    is provided by 3 high-level components:

    1. Hibernate MBean - provides deployment, lifecycle, and management support around a Hibernate SessionFactory;

    2. HAR Deployer - defines a Hibernate ARchive as a new deployable unit within JBoss AS;

    3. Session Management - provides transparent management of Hibernate sessions.




    Please note that versions integrating Hibernate2 into JBossAS are deprecated, in favor of those

    inetgrating Hibernate3.  See JBossHibernate3 for details on that integration.


    Hibernate MBean

    The Hibernate MBean is responsible for constructing a Hibernate SessionFactory and exposing it through JNDI. It also provides

    JMX management capabilities around the deployed SessionFactory such that its configuration can be modified at runtime.





    It exposes a number of configuration properties which affect its runtime behaviour. The more important of these include:

    • DatasourceName - the JNDI name of the datasource Hibernate should use;

    • Dialect - the RDBMS dialect;

    • SessionFactoryName - the JNDI name where the constructed SessionFactory should be bound;

    • CacheProviderClass - the Hibernate CacheProvider class to use for its second-level cache.

    Check out the javadocs for org.jboss.hibernate.jmx.Hibernate for a complete list of the available configuration properties.





    Notice that there is no option to specify the mapping documents to load. That is because the Hibernate MBean is meant to work

    in conjuction with the HAR Deployer component and gets this information from there.





    As an example of configuring the MBean, here is the configuration used in the unit tests:

    <mbean code="org.jboss.hibernate.jmx.Hibernate" name="jboss.har:service=Hibernate">
    <attribute name="DatasourceName">java:/DefaultDS</attribute>
    <attribute name="~SessionFactoryName">java:/hibernate/~SessionFactory</attribute>
    <attribute name="Dialect">net.sf.hibernate.dialect.HSQLDialect</attribute>
    <attribute name="CacheProviderClass">net.sf.hibernate.cache.HashtableCacheProvider</attribute>
    <attribute name="Hbm2ddlAuto">create-drop</attribute>

    <attribute name="ShowSqlEnabled">true</attribute> should be used to show the sql output, instead of the former






    HAR Deployer

    A Hibernate ARchive (or HAR) includes all the resources needed to deploy one or more Hibernate MBean instances. The archive must end

    in a .har extension and contain a meta-inf/hibernate-service.xml which defines the Hibernate MBean(s) to deploy as well all the domain

    classes and their mappings. The mappings can occur anywhere in the archive; the classes should maintain package structure. When a HAR

    is processed by the HAR Deployer, a Hibernate MBean instance is created based on the HAR's meta-inf/hibernate-service.xml and the

    contents of the har (the mappings are processed using Hibernate's Configuration.addJar() method).





    A HAR can be deployed stand-alone or as part of an EAR. If included in an EAR, the EAR's meta-inf/jboss-app.xml must define the har

    as a module as such:


    Note the new <har/> module type used to denote the HAR subdeployment.




    Session Management

    All applications using Hibernate need to deal with the questions relating to the lifecycle of the Sessions they

    obtain from the SessionFactory.  When should the session be opened; how should components throughout the application

    obtain the "current" session; how should flushing and closing of the session be handled?





    The most common usage pattern for Hibernate in J2EE applications running within an application server is to use the

    app server DataSource and TransactionManager capabilities.  Typically a session is opened at the beginning of a

    "request" and closed at the end of that "request", and in between the session is bound to the "current context" to be

    accessible to application components.





    The central piece of the Hibernate Session management component in JBoss is the org.jboss.hibernate.session.HibernateContext

    class.  HibernateContext exposes a static method named getSession() taking a String parameter which represents the jndi name

    of a SessionFactory.  If there is already a session bound to the "current context" for the given session factory name, then

    that session is returned; otherwise, a new session is generated, bound to the "current context", and then returned.





    So what constitutes the "current context" for a managed session?  The transaction!  This component uses the org.jboss.tm.TransactionLocal

    class to associate a session with the current JTA transaction.  The life of the session is then bound to that of the transaction.  When

    the session is bound, a Synchronization is registered with that transaction such that when the transaction is about to end the Hibernate

    session can be flushed and closed.





    There are two other pieces of functionality available through the HibernateContext class: the ability to handle "unmanaged sessions" and

    ability for applications to manage the binding/unbinding of the Hibernate session themselves.





    An unmanaged session is a session that is controlled by the HibernateContext, meaning it is not automatically flushed and closed.  The session

    is created on the same underlying jdbc connection and thus participates in the same JTA transaction.  This is mostly useful for Hibernate

    Interceptor implementations.  The methods supporting this functionality are getUnmanagedSession() and releaseUnmanagedSession().  Check out

    the javadocs for more info.





    HibernateContext also exposes the methods bind(), unbind(), and prepareSession() to allow applications to manage the lifecycle of the Hibernate

    session themselves.  Say you have special requirements for obtaining a Hibernate session such as passing in your own JDBC connection or opening

    a session with a session-level Interceptor (the MBean does support SessionFactory-level Interceptors).  Then you can write the code which

    generates a session and use these HibernateContext methods to expose this session to your application components; the idea being that no code

    changes are needed in your components because they are still just using the HibernateContext.getSession() method.  bind() and unbind() are

    pretty self-explanatory; prepareSession() is used to perform the transaction Synchronization registration.  Again, see the javadocs for more info.





    The one caveat to note here is that due to the use of the TransactionLocal, the JTA transaction must be started prior to the session being

    bound to the HibernateContext.




    Why the need to pass the JNDI name to the HibernateContext.getSession() method? The HibernateContext class supports multiple simultaneously

    deployed SessionFactories. You need to specify from which of those deployed SessionFactories you want the current session.




    Bundling other versions of Hibernate2

    -- TODO; should be as simple as bundling the version you want to use within the HAR and utilizing a loader-repository, but this needs

    to be tested.




    Hibernate2 vs. Hibernate3

    See the switching doc regarding switching versions of

    Hibernate used in the integration.




    {FOOTNOTE RED #1 1} The session management code underwent a drastic change from its initial versions and this wiki page has been updated to reflect those

    changes.  However, the old page has been saved off at JBossHibernate-old