Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
CDO/Hibernate Store/Auditing
Contents
Since November 2012 the CDO Hibernate Store supports auditing in the 4.2 release stream. The auditing support is based on the auditing support provided by Teneo with the notable difference that auditing and revisions are completely integrated with the CDO client side object history api.
Architecture
The CDO Hibernate Store uses the Teneo mapping engine to generate an auditing model and database schema. The auditing database schema creates audit tables for each domain type and follows the same structure as the domain model. The main differences are:
- Teneo adds audit meta data to each table (commit timestamp, validity period of an audit entry etc.)
- EReferences are not persisted as foreign keys but as strings
- Enumerates are always persisted as strings
Other than that you will see the same columns and fields in the auditing database schema.
Enabling and configuring auditing - controlling the database schema
You enable auditing by setting the following option in the server config xml file:
<property name="supportingAudits" value="true"/>
In addition all the Teneo specific options apply, see here for more information.
You can control the auditing database schema by annotating the model in the same way as for standard Teneo, with one difference: auditing annotations are defined using the teneo.jpa.auditing source on the EAnnotation on the domain model. See here for more information.
Retrieving Object History - Revisions
The CDO api provides several ways of working with historical data/audit entries.
Setting a timestamp on the view/transaction
The easiest way to access to historical data is to open a view using a specific time stamp. The resources and objects retrieved through the resource (and all referenced objects) will all represent that state on that timestamp.
// open a view for a specific timestamp CDOView audit = session.openView(commitTime3); // get a resource in the state of that timestamp CDOResource auditResource = audit.getResource("/res1"); // get a revision on that timestamp Company auditCompany = (Company)auditResource.getContents().get(0); // test something assertEquals("Eclipse", auditCompany.getName());
CDOObjectHistory and CDOCommitHistory
The CDOObjectHistory and CDOCommitHistory can be retrieved from the CDOView. They both give access to the commit history until the timestamp of the view.
The special thing with both objects is that they load their information asynchronously, so you need a small loop to test when the data has arrived. This is illustrated in the code below.
// load the CDOObjectHistory private synchronized CDOObjectHistory getCDOObjectHistory(CDOView audit, Object object) { CDOObjectHistory cdoObjectHistory = audit.getHistory((CDOObject)object); cdoObjectHistory.triggerLoad(); long startTime = System.currentTimeMillis(); while (cdoObjectHistory.isLoading()) { ConcurrencyUtil.sleep(10); // waited too long if (System.currentTimeMillis() - startTime > 5000) { throw new IllegalStateException("commit info could not be loaded"); } } return cdoObjectHistory; }
When you the CDOObjectHistory you get all the commits in which the object participated. For each commit you can get to all the changed, new and deleted objects.
for (CDOCommitInfo cdoCommitInfo : cdoCommitHistory.getElements()) { final List<CDOIDAndVersion> newObjects = cdoCommitInfo.getNewObjects(); final List<CDORevisionKey> changedObjects = cdoCommitInfo.getChangedObjects(); final List<CDOIDAndVersion> detachedObjects = cdoCommitInfo.getDetachedObjects(); ... }
The CDOCommitHistory is almost the same, it provides access to all commits until the timestamp of the view.
CDOUtil.getRevisionByVersion - Comparing revisions
Another way of getting to the versions of an object is to use the CDOUtil.getRevisionByVersion method. It allows you to easily iterate over the revisions of a specific object using the version number.
// use the auditCompany from above final CDOObject cdoObject = CDOUtil.getCDOObject(auditCompany); int thisVersion = cdoObject.cdoRevision().getVersion(); assertEquals(3, thisVersion); final InternalCDORevision revision3 = (InternalCDORevision)CDOUtil.getRevisionByVersion(cdoObject, 3); final InternalCDORevision revision2 = (InternalCDORevision)CDOUtil.getRevisionByVersion(cdoObject, 2); final InternalCDORevision revision1 = (InternalCDORevision)CDOUtil.getRevisionByVersion(cdoObject, 1); // note get the eclass from the revision to use the correct eclass instance assertEquals("ESC", revision1.getValue(revision1.getEClass().getEStructuralFeature("name"))); assertEquals("Sympedia", revision2.getValue(revision1.getEClass().getEStructuralFeature("name"))); assertEquals("Eclipse", revision3.getValue(revision1.getEClass().getEStructuralFeature("name")));
You can also compare the revisions to get the details of the differences between different revisions:
CDORevisionDelta revisionDelta = revision3.compare(revision2); for (CDOFeatureDelta featureDelta : revisionDelta.getFeatureDeltas()) { System.err.println(featureDelta.getFeature().getName() + " changed through changeType " + featureDelta.getType()); }
Note that the CDOFeatureDelta has many subclasses, checking the exact instance class and casting to it (based on the type) allows access to the change details (for example new and old value).
Limitations
- HQL queries are not executed on the audit tables but always on the domain tables, this means that HQL queries will not execute in the timestamp set on the view but always on the latest version of an object.
- Auditing entries can not be exported/imported, i.e. always the latest version of an object is exported and imported.