Opentaps Hibernate Integration

From Opentaps Wiki
Revision as of 10:23, 2 April 2009 by Spark (talk | contribs) (Auto Generating ID Values)
Jump to navigationJump to search

Beginning with opentaps version 1.4, Hibernate will be available as a persistence tool alongside with the original ofbiz entity engine. Hibernate is a more object oriented persistence framework and better suited for the new Domain Driven Architecture, while the ofbiz entity engine will continue to be supported for legacy features from both ofbiz and opentaps. In this document, we will review how the hibernate integration in opentaps works.

Working with Hibernate in opentaps

Generating Hibernate Configuration Files

After changing or defining new entities in your entitymodel.xml files, you need to generate new Java classes for your entities with

$ ant make-base-entities

This command updates the Java classes defined in org.opentaps.domain.base.entities, including their hibernate annotations, and the hibernate.cfg.xml for integrating with hibernate. (If you use a repository management system, you must commit both and you Java classes and the updated hibernate.cfg.xml files.)

Accessing Entities with Hibernate

To use hibernate to access your entities, you will need an, which is an extension of the org.hibernate.Session class. You can obtain it from the Infrastructure class like this:

       session = infrastructure.getSession();

Then, you can work with it as if it were a Hibernate Session:

       Transaction tx = session.beginTransaction();
       TestEntity newTestEntity = new TestEntity();
       newTestEntity.setTestStringField("testInsertTestEntity string field");
       // ...
       TestEntity loadEntity = (TestEntity) session.load(TestEntity.class, newTestEntity.getTestId());
       // ...
       String hql = "from TestEntity eo where eo.testId='" + testEntityId2 + "'";
       Query query = session.createQuery(hql);
       List<TestEntity> list = query.list()

You do not need to close your JDBC connection manually with the opentaps Session, however. When you call


It will do it for you automatically.

Traversing Related Entities

opentaps will automatically create the relationship annotations, such as @OneToMany, @ManyToMany, and @Join, for your Java classes.

To get related entities, use the hibernate query language (HQL):

   String hql = "from TestEntityItem eo where eo.testEntity.testId='" + testEntity.getTestId() + "'"
              + " and eo.testEntityItemSeqId in (" + testEntityItemSeqIds + ")";
   Query query = session.createQuery(hql);
   List<TestEntityItem> list = query.list();

Or use the getter methods in the base entities:

   List<TestEntityItem> list = testEntity.getTestEntityItems();

Note that hibernate will automatically load related entities for you, so the getRelated methods from Repository which were designed for the ofbiz entity engine are no longer needed when you work with hibernate.

Working with View Entities

Once a view entity has been defined in entitymodel.xml, you can access it as any other Java object from hibernate, for example:

       Query query = session.createQuery("from TestEntityAndItem eo where eo.testId='" 
                   + testEntityId + "' order by eo.testEntityItemSeqId");
       List<TestEntityAndItem> list = query.list();

The opentaps Session, which extends the hibernate Session, will automatically create the SQL for accessing the view entity.

Using Transactions

You should use the transaction manager configured in the ofbiz entity engine through the UserTransaction class. In the entity engine, the transaction manager is configured as:

 <transaction-factory class="org.ofbiz.geronimo.GeronimoTransactionFactory"/>

This is obtained from the ofbiz TransactionFactory by our Session and used the same way as a hibernate transaction:

     UserTransaction tx = session.beginUserTransaction();
     // do something useful

Auto Generating ID Values

ofbiz keeps track of auto generated sequence IDs in an entity called SequenceValueItem To make sure that the auto generated sequence IDs from hibernate and the ofbiz entity engine work well together, we have created an OpentapsIdentifierGenerator which also uses the same SequenceValueItem to obtain the next sequential ID. This ID generator is wired to the base entity POJO Java objects with hibernate annotations, like this:

 @org.hibernate.annotations.GenericGenerator(name="Party_GEN",  strategy="")
 private String partyId;

So that a partyId field is automatically set for you.

Support for OFBIZ EECA's

ofbiz EECA's are supported with custom event listeners which are registered with hibernate when Infrastructure.getSessionFactory(String delegatorName) is called, usually during the initial startup. These event listeners will run ofbiz services defined in eeca.xml's when hibernate is used to update the same entities.

Under the Hood: How It Works

Base Class Annotations

In opentaps version 1.4, the entity model XML from the ofbiz entity engine is still used as the base definition for all entities. The opentaps POJO generator is used to create base Java objects automatically from these entity definitions. This POJO generator will also create the annotations which hibernate can then use to map those base objects to the database persistence layer. The definitions of the annotations can be found in BaseEntity.ftl file used by the POJO generator.

How Hibernate Configuration Files are Generated

The POJO Generator will use hot-deploy/opentaps-common/templates/HibernateCfg.ftl to generate a base hibernate configuration file in hot-deploy/opentaps-common/config/hibernate.cfg.xml When opentaps is started, the following new container in framework/base/config/ofbiz-containers.xml

    <container name="hibernate-container" class="org.opentaps.common.container.HibernateContainer">
        <property name="delegator-name" value="default"/>

will generate all the hibernate configuration XML files in the hot-deploy/opentaps/config/ directory for each data source in your entity engine XML file. For example, it will generate a localmysql.cfg.xml, a localpostgres.cfg.xml

How We Get the Hibernate Session

The opentaps Infrastructure Class maintains a Map of delegatorName and hibernate SessionFactory objects. Each SessionFactory is created for its corresponding delegatorName the first time it is requested from the Infrastructure.getSessionFactory(delegatorName) method. This SessionFactory is created from ofbiz entity engine configurations:

  • The HibernateContainer in ofbiz-containers.xml has a property called delegator-name
  • From this delegator, we get the data source defined in entityengine.xml for the default group helper name. This is set to org.ofbiz by default in the Infrastructure class and is the group attribute of the entitygroup.xml definitions in ofbiz:
 <entity-group group="org.ofbiz" entity="AcctgTagEnumType"/>

In entityengine.xml, you map a data source to each group:

   <delegator name="default" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" distributed-cache-clear-enabled="false">
       <group-map group-name="org.ofbiz" datasource-name="localmysql"/>

So, we are basically following the entity engine from the delegator to the data source via the group.

  • Once we have the data source, we can create the SessionFactory from the hibernate.cfg.xml for that data source. For example, if your data source is "localmysql", we will create the SessionFactory from the localmysql.cfg.xml created by the HibernateContainer

The HibernateContainer, which loads on startup, will cause a SessionFactory to be loaded for the delegator in the delegator-name attribute. Once this SessionFactory is loaded, it will be available for future use. Additional session factories can be obtained later by calling the getSessionFactory directly.

When the Infrastructure.getSession() method is called, it will use the delegator already in the Infrastructure object to open a JDBC connection first, and then use that JDBC connection and the SessionFactory for the delegator to return a Session.

The Infrastructure.getSession() will return an, which extends the hibernate Session with the following differences:

  • when the session is closed, the JDBC connection is also automatically closed
  • when a Query is created, this Session will check if the query is on an entity engine view entity and construct the Query from native SQL first

View Entities

View entities are supported with @NamedNativeQuery annotations in the base entity Java classes, which are automatically generated by the opentaps POJO Generator.

Unit Tests

Unit tests for hibernate are found in org.opentaps.tests.entity.hibernate.HibernateTests in the opentaps-tests component.