Difference between revisions of "Opentaps Hibernate Integration"
(→View Entities) |
(→Encryption) |
||
Line 139: | Line 139: | ||
=== Encryption === | === Encryption === | ||
+ | |||
+ | The ofbiz delegator allows you to set a field to be encrypted in the database with the <tt>encrypt="true"</tt> attribute in the <tt>field</tt> tag of an entity definition. The opentaps hibernate will support the same encryption/decryption algorithm, so that encrypted values can be stored with the delegator and decrypted when it's retrieved with hibernate or vice versa. This is done by: | ||
+ | # When an object is being stored, the <tt>EcaCommEvent.beforeSave</tt> Method will come for the object to an ofbiz GenericValue and then use the ofbiz delegator to encrypt it. | ||
+ | # When an object is retrieved from the database, the <tt>Session.load</tt> will call the <tt>HibernateUtil.decryptField</tt> to decrypt it. | ||
=== Transaction Management === | === Transaction Management === |
Revision as of 17:47, 16 April 2009
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 org.opentaps.foundation.entity.hibernate.Session, 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"); newTestEntity.setCreatedStamp(UtilDateTime.nowTimestamp()); session.save(newTestEntity); tx.commit(); session.flush(); // ... 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
session.close();
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 tx.commit();
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="org.opentaps.foundation.entity.hibernate.OpentapsIdentifierGenerator") @GeneratedValue(generator="Party_GEN") @Id @Column(name="PARTY_ID") private String partyId;
So that a partyId field is automatically set for you.
You can also ask the Session to generate a particular sequence ID for you:
String testEntityItemSeqId = session.getNextSeqId("TestEntityItemSeqId");
This can be helpful when you have complex keys with several fields, and you want the secondary key fields to be auto sequenced as well.
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"/> </container>
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"/> </delegator>
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 org.opentaps.foundation.entity.hibernate.Session, 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.
Encryption
The ofbiz delegator allows you to set a field to be encrypted in the database with the encrypt="true" attribute in the field tag of an entity definition. The opentaps hibernate will support the same encryption/decryption algorithm, so that encrypted values can be stored with the delegator and decrypted when it's retrieved with hibernate or vice versa. This is done by:
- When an object is being stored, the EcaCommEvent.beforeSave Method will come for the object to an ofbiz GenericValue and then use the ofbiz delegator to encrypt it.
- When an object is retrieved from the database, the Session.load will call the HibernateUtil.decryptField to decrypt it.
Transaction Management
Unit Tests
Unit tests for hibernate are found in org.opentaps.tests.entity.hibernate.HibernateTests in the opentaps-tests component.