Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Taal2014-06-15 05:45:51 -0400
committerMartin Taal2014-06-15 05:45:51 -0400
commitb66440af06b2bda1a40a309436e9495741312a20 (patch)
treebb415c02682e88d3ba88bcf47287e749fe205266
parent130bdd7c88f37809ff8baa6efa9078ffaadec050 (diff)
downloadorg.eclipse.emf.teneo-b66440af06b2bda1a40a309436e9495741312a20.tar.gz
org.eclipse.emf.teneo-b66440af06b2bda1a40a309436e9495741312a20.tar.xz
org.eclipse.emf.teneo-b66440af06b2bda1a40a309436e9495741312a20.zip
[436367] [Auditing] initial record not available after first
-rw-r--r--[-rwxr-xr-x]core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java10
-rw-r--r--[-rwxr-xr-x]hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/auditing/AuditProcessHandler.java98
2 files changed, 108 insertions, 0 deletions
diff --git a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java
index d7279b8bc..c63196af1 100755..100644
--- a/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java
+++ b/core/org.eclipse.emf.teneo/src/org/eclipse/emf/teneo/PersistenceOptions.java
@@ -11,6 +11,7 @@
* Martin Taal - Initial API and implementation
* Jason Henriksen - Mapping File Path
* Jason Henriksen - XSDDate and XSDDateTime constants
+ * Erdal Karaca - [bug 436367]: check for initial audit entry
* </copyright>
*
* $Id: PersistenceOptions.java,v 1.71 2011/10/29 06:12:48 mtaal Exp $
@@ -73,6 +74,13 @@ public class PersistenceOptions implements ExtensionPoint {
+ "auditing.jointable.postfix";
public static final String AUDITING_PERSISTENCE_XML = MAPPING_PREFIX + "auditing.persistence_xml";
+ /**
+ * Whether to check and create the initial audit entry if it is not available when the first
+ * change is done to an entity.
+ */
+ public static final String AUDITING_CHECK_INITIAL_AUDIT_ENTRY = MAPPING_PREFIX
+ + "auditing.checkInitialAuditEntry";
+
// START: ++++++++++++++++++++++ SQL Naming related Options
// ++++++++++++++++++++++++++++++++++++
@@ -576,6 +584,8 @@ public class PersistenceOptions implements ExtensionPoint {
props.setProperty(EXTRA_ANNOTATIONS_OVERRIDES_DEFAULT, "false");
props.setProperty(AUTO_ADAPT_MANUAL_SET_SQL_NAMES, "true");
+ props.setProperty(AUDITING_CHECK_INITIAL_AUDIT_ENTRY, "false");
+
return props;
}
diff --git a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/auditing/AuditProcessHandler.java b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/auditing/AuditProcessHandler.java
index 5e90e81be..3a7f0e4e3 100755..100644
--- a/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/auditing/AuditProcessHandler.java
+++ b/hibernate/org.eclipse.emf.teneo.hibernate/src/org/eclipse/emf/teneo/hibernate/auditing/AuditProcessHandler.java
@@ -9,6 +9,7 @@
*
* Contributors:
* Martin Taal
+ * Erdal Karaca - [bug 436367]: check for initial audit entry
* </copyright>
*
* $Id: AnyEObjectType.java,v 1.7 2010/11/12 09:33:33 mtaal Exp $
@@ -57,6 +58,7 @@ import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
+import org.hibernate.tuple.entity.EntityTuplizer;
/**
* The main auditing logic used at runtime to create and persist auditing entries.
@@ -100,6 +102,12 @@ public class AuditProcessHandler implements AfterTransactionCompletionProcess,
private ThreadLocal<Boolean> inAuditWorkInSession = new ThreadLocal<Boolean>();
private AuditHandler auditHandler = null;
+ /**
+ * Flag to check if an initial audit entry exists before creating the first audit entry
+ * onPostUpdate.
+ */
+ private boolean checkInitialAuditEntry = false;
+
private void addToAuditWorkQueue(EventSource session, TeneoAuditKind auditKind, Object entity) {
if (!auditHandler.isAudited(entity)) {
return;
@@ -183,7 +191,48 @@ public class AuditProcessHandler implements AfterTransactionCompletionProcess,
@Override
public void onPostUpdate(PostUpdateEvent event) {
+ AuditWork initialRecord = null;
+
+ if (checkInitialAuditEntry) {
+ final Object object = event.getEntity();
+ final EClass eClass = auditHandler.getEClass(object);
+ final EClass auditEntryEClass = auditHandler.getAuditingModelElement(eClass);
+ final String auditEntryEntityName = HbUtil.getEntityName(auditEntryEClass);
+ String objectId = auditHandler.entityToIdString(event.getSession(), event.getEntity());
+
+ final Query infoQuery = event.getSession().createQuery(
+ "select count(teneo_object_id) from " + auditEntryEntityName
+ + " e where teneo_object_id=:objectId and teneo_end="
+ + AuditProcessHandler.DEFAULT_END_TIMESTAMP);
+ infoQuery.setMaxResults(1);
+ infoQuery.setString("objectId", objectId);
+
+ Number next = (Number) infoQuery.iterate().next();
+
+ if (next != null && next.intValue() == 0) {
+ EntityTuplizer entityTuplizer = event.getPersister().getEntityTuplizer();
+ Object oldStateObject = entityTuplizer.instantiate();
+ Object[] oldState = event.getOldState();
+ entityTuplizer.setPropertyValues(oldStateObject, oldState);
+ entityTuplizer.setIdentifier(oldStateObject, entityTuplizer.getIdentifier(object));
+
+ // add the initial record (AuditWork) and remember to link to the UPDATE AuditWork
+ {
+ addToAuditWorkQueue(event.getSession(), TeneoAuditKind.ADD, oldStateObject);
+ List<AuditWork> auditWorks = workQueue.get(event.getSession().getTransaction());
+ initialRecord = auditWorks.get(auditWorks.size() - 1);
+ }
+ }
+ }
+
addToAuditWorkQueue(event.getSession(), TeneoAuditKind.UPDATE, event.getEntity());
+
+ if (initialRecord != null) {
+ List<AuditWork> auditWorks = workQueue.get(event.getSession().getTransaction());
+ // assume the last AuditWork is the newly added audit entry
+ AuditWork updateRecord = auditWorks.get(auditWorks.size() - 1);
+ updateRecord.setInitialRecord(initialRecord);
+ }
}
@Override
@@ -367,6 +416,23 @@ public class AuditProcessHandler implements AfterTransactionCompletionProcess,
// save later to not flush in the loop
toSaveEntries.add(auditEntry);
setCommitInfoInReferencedObjects(auditEntry, toSaveEntries);
+
+ // if this audit entry has a derived initial audit record, then we have to adjust its
+ // timestamps to be lower than this commit time stamp
+ if (auditWork.getInitialRecord() != null) {
+ AuditWork initialRecord = auditWork.getInitialRecord();
+
+ // first to be saved entry is the commit info, so skip it by adding +1 to the index
+ int indexOf = auditWorks.indexOf(initialRecord) + 1;
+ TeneoAuditEntry initialAuditEntry = (TeneoAuditEntry) toSaveEntries.get(indexOf);
+
+ // it is sufficient to subtract at least one millisecond difference to the initial audit
+ // entry timestamps
+ long initialRecordTimestamp = auditEntry.getTeneo_start() - 1;
+ initialAuditEntry.setTeneo_start(initialRecordTimestamp);
+ initialAuditEntry.setTeneo_end(initialRecordTimestamp);
+ auditEntry.setTeneo_previous_start(initialRecordTimestamp);
+ }
}
// do flush here to ensure that the update is done before
// the save, this to prevent unique constraint failures
@@ -481,6 +547,11 @@ public class AuditProcessHandler implements AfterTransactionCompletionProcess,
PersistenceOptions.AUDITING_PRUNE_COMMIT_INTERVAL));
this.auditHandler = dataStore.getAuditHandler();
+
+ boolean checkInitialAuditEntry = Boolean.parseBoolean(""
+ + dataStore.getDataStoreProperties().get(
+ PersistenceOptions.AUDITING_CHECK_INITIAL_AUDIT_ENTRY));
+ setCheckInitialAuditEntry(checkInitialAuditEntry);
}
private synchronized void pruneEntries(SessionImplementor session) {
@@ -551,10 +622,24 @@ public class AuditProcessHandler implements AfterTransactionCompletionProcess,
private TeneoAuditKind auditKind;
private long version;
+ /**
+ * The initial record is created if in the first onPostUpdate Teneo detects that there is no
+ * initial audit entry available.
+ */
+ private AuditWork initialRecord;
+
public Object getEntity() {
return entity;
}
+ public void setInitialRecord(AuditWork initialRecord) {
+ this.initialRecord = initialRecord;
+ }
+
+ public AuditWork getInitialRecord() {
+ return initialRecord;
+ }
+
public void setEntity(Object entity) {
this.entity = entity;
}
@@ -596,4 +681,17 @@ public class AuditProcessHandler implements AfterTransactionCompletionProcess,
public AuditHandler getAuditHandler() {
return auditHandler;
}
+
+ /**
+ * Whether to check and create the initial audit entry if it is not available when the first
+ * change is done to an entity.
+ *
+ * @param checkInitialAuditEntry
+ * <code>true</code> to check and create the initial audit entry of an object if it does
+ * not exist, <code>false</code> else
+ * @see PersistenceOptions#AUDITING_CHECK_INITIAL_AUDIT_ENTRY
+ */
+ public void setCheckInitialAuditEntry(boolean checkInitialAuditEntry) {
+ this.checkInitialAuditEntry = checkInitialAuditEntry;
+ }
} \ No newline at end of file

Back to the top