[hibernate-commits] Hibernate SVN: r19180 - in core/trunk/envers/src: main/java/org/hibernate/envers/event and 3 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Tue Apr 6 16:35:16 EDT 2010
Author: adamw
Date: 2010-04-06 16:35:15 -0400 (Tue, 06 Apr 2010)
New Revision: 19180
Added:
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java
Removed:
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSync.java
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSyncManager.java
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java
core/trunk/envers/src/main/java/org/hibernate/envers/event/AuditEventListener.java
core/trunk/envers/src/main/java/org/hibernate/envers/reader/AuditReaderImpl.java
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/ExceptionListener.java
Log:
HHH-3543: using BeforeTransactionCompletionProcess instead of a transaction synchronization. That way exceptions are not swallowed if one is thrown in the audit synchronization/process, and the tx is rolled back
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java 2010-04-06 20:34:27 UTC (rev 19179)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java 2010-04-06 20:35:15 UTC (rev 19180)
@@ -30,7 +30,7 @@
import org.hibernate.envers.entities.EntitiesConfigurations;
import org.hibernate.envers.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator;
-import org.hibernate.envers.synchronization.AuditSyncManager;
+import org.hibernate.envers.synchronization.AuditProcessManager;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.AnnotationConfiguration;
@@ -42,7 +42,7 @@
public class AuditConfiguration {
private final GlobalConfiguration globalCfg;
private final AuditEntitiesConfiguration auditEntCfg;
- private final AuditSyncManager auditSyncManager;
+ private final AuditProcessManager auditProcessManager;
private final EntitiesConfigurations entCfg;
private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final RevisionInfoNumberReader revisionInfoNumberReader;
@@ -51,8 +51,8 @@
return auditEntCfg;
}
- public AuditSyncManager getSyncManager() {
- return auditSyncManager;
+ public AuditProcessManager getSyncManager() {
+ return auditProcessManager;
}
public GlobalConfiguration getGlobalCfg() {
@@ -80,7 +80,7 @@
RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure(cfg, reflectionManager);
auditEntCfg = new AuditEntitiesConfiguration(properties, revInfoCfgResult.getRevisionInfoEntityName());
globalCfg = new GlobalConfiguration(properties);
- auditSyncManager = new AuditSyncManager(revInfoCfgResult.getRevisionInfoGenerator());
+ auditProcessManager = new AuditProcessManager(revInfoCfgResult.getRevisionInfoGenerator());
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
entCfg = new EntitiesConfigurator().configure(cfg, reflectionManager, globalCfg, auditEntCfg,
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/event/AuditEventListener.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/event/AuditEventListener.java 2010-04-06 20:34:27 UTC (rev 19179)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/event/AuditEventListener.java 2010-04-06 20:35:15 UTC (rev 19180)
@@ -31,7 +31,7 @@
import org.hibernate.envers.entities.RelationType;
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
import org.hibernate.envers.entities.mapper.id.IdMapper;
-import org.hibernate.envers.synchronization.AuditSync;
+import org.hibernate.envers.synchronization.AuditProcess;
import org.hibernate.envers.synchronization.work.*;
import org.hibernate.envers.tools.Tools;
import org.hibernate.envers.RevisionType;
@@ -68,7 +68,7 @@
private AuditConfiguration verCfg;
- private void generateBidirectionalCollectionChangeWorkUnits(AuditSync verSync, EntityPersister entityPersister,
+ private void generateBidirectionalCollectionChangeWorkUnits(AuditProcess auditProcess, EntityPersister entityPersister,
String entityName, Object[] newState, Object[] oldState,
SessionImplementor session) {
// Checking if this is enabled in configuration ...
@@ -112,7 +112,7 @@
id = (Serializable) idMapper.mapToIdFromEntity(newValue);
}
- verSync.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, verCfg, id, newValue));
+ auditProcess.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, verCfg, id, newValue));
}
if (oldValue != null) {
@@ -132,7 +132,7 @@
id = (Serializable) idMapper.mapToIdFromEntity(oldValue);
}
- verSync.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, verCfg, id, oldValue));
+ auditProcess.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, verCfg, id, oldValue));
}
}
}
@@ -143,14 +143,14 @@
String entityName = event.getPersister().getEntityName();
if (verCfg.getEntCfg().isVersioned(entityName)) {
- AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
+ AuditProcess auditProcess = verCfg.getSyncManager().get(event.getSession());
AuditWorkUnit workUnit = new AddWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
event.getId(), event.getPersister(), event.getState());
- verSync.addWorkUnit(workUnit);
+ auditProcess.addWorkUnit(workUnit);
if (workUnit.containsWork()) {
- generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
+ generateBidirectionalCollectionChangeWorkUnits(auditProcess, event.getPersister(), entityName, event.getState(),
null, event.getSession());
}
}
@@ -160,14 +160,14 @@
String entityName = event.getPersister().getEntityName();
if (verCfg.getEntCfg().isVersioned(entityName)) {
- AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
+ AuditProcess auditProcess = verCfg.getSyncManager().get(event.getSession());
AuditWorkUnit workUnit = new ModWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
event.getId(), event.getPersister(), event.getState(), event.getOldState());
- verSync.addWorkUnit(workUnit);
+ auditProcess.addWorkUnit(workUnit);
if (workUnit.containsWork()) {
- generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
+ generateBidirectionalCollectionChangeWorkUnits(auditProcess, event.getPersister(), entityName, event.getState(),
event.getOldState(), event.getSession());
}
}
@@ -177,20 +177,20 @@
String entityName = event.getPersister().getEntityName();
if (verCfg.getEntCfg().isVersioned(entityName)) {
- AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
+ AuditProcess auditProcess = verCfg.getSyncManager().get(event.getSession());
AuditWorkUnit workUnit = new DelWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
event.getId(), event.getPersister(), event.getDeletedState());
- verSync.addWorkUnit(workUnit);
+ auditProcess.addWorkUnit(workUnit);
if (workUnit.containsWork()) {
- generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, null,
+ generateBidirectionalCollectionChangeWorkUnits(auditProcess, event.getPersister(), entityName, null,
event.getDeletedState(), event.getSession());
}
}
}
- private void generateBidirectionalCollectionChangeWorkUnits(AuditSync verSync, AbstractCollectionEvent event,
+ private void generateBidirectionalCollectionChangeWorkUnits(AuditProcess auditProcess, AbstractCollectionEvent event,
PersistentCollectionChangeWorkUnit workUnit,
RelationDescription rd) {
// Checking if this is enabled in configuration ...
@@ -209,13 +209,13 @@
Object relatedObj = changeData.getChangedElement();
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity(relatedObj);
- verSync.addWorkUnit(new CollectionChangeWorkUnit(event.getSession(), relatedEntityName, verCfg,
+ auditProcess.addWorkUnit(new CollectionChangeWorkUnit(event.getSession(), relatedEntityName, verCfg,
relatedId, relatedObj));
}
}
}
- private void generateFakeBidirecationalRelationWorkUnits(AuditSync verSync, PersistentCollection newColl, Serializable oldColl,
+ private void generateFakeBidirecationalRelationWorkUnits(AuditProcess auditProcess, PersistentCollection newColl, Serializable oldColl,
String collectionEntityName, String referencingPropertyName,
AbstractCollectionEvent event,
RelationDescription rd) {
@@ -242,13 +242,13 @@
AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(event.getSession(), realRelatedEntityName, verCfg,
relatedId, relatedObj);
- verSync.addWorkUnit(new FakeBidirectionalRelationWorkUnit(event.getSession(), realRelatedEntityName, verCfg,
+ auditProcess.addWorkUnit(new FakeBidirectionalRelationWorkUnit(event.getSession(), realRelatedEntityName, verCfg,
relatedId, referencingPropertyName, event.getAffectedOwnerOrNull(), rd, revType,
changeData.getChangedElementIndex(), nestedWorkUnit));
}
// We also have to generate a collection change work unit for the owning entity.
- verSync.addWorkUnit(new CollectionChangeWorkUnit(event.getSession(), collectionEntityName, verCfg,
+ auditProcess.addWorkUnit(new CollectionChangeWorkUnit(event.getSession(), collectionEntityName, verCfg,
event.getAffectedOwnerIdOrNull(), event.getAffectedOwnerOrNull()));
}
@@ -257,7 +257,7 @@
String entityName = event.getAffectedOwnerEntityName();
if (verCfg.getEntCfg().isVersioned(entityName)) {
- AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
+ AuditProcess auditProcess = verCfg.getSyncManager().get(event.getSession());
String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
String referencingPropertyName = collectionEntry.getRole().substring(ownerEntityName.length() + 1);
@@ -266,20 +266,20 @@
// null in case of collections of non-entities.
RelationDescription rd = verCfg.getEntCfg().get(entityName).getRelationDescription(referencingPropertyName);
if (rd != null && rd.getMappedByPropertyName() != null) {
- generateFakeBidirecationalRelationWorkUnits(verSync, newColl, oldColl, entityName,
+ generateFakeBidirecationalRelationWorkUnits(auditProcess, newColl, oldColl, entityName,
referencingPropertyName, event, rd);
} else {
PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(event.getSession(),
entityName, verCfg, newColl, collectionEntry, oldColl, event.getAffectedOwnerIdOrNull(),
referencingPropertyName);
- verSync.addWorkUnit(workUnit);
+ auditProcess.addWorkUnit(workUnit);
if (workUnit.containsWork()) {
// There are some changes: a revision needs also be generated for the collection owner
- verSync.addWorkUnit(new CollectionChangeWorkUnit(event.getSession(), event.getAffectedOwnerEntityName(),
+ auditProcess.addWorkUnit(new CollectionChangeWorkUnit(event.getSession(), event.getAffectedOwnerEntityName(),
verCfg, event.getAffectedOwnerIdOrNull(), event.getAffectedOwnerOrNull()));
- generateBidirectionalCollectionChangeWorkUnits(verSync, event, workUnit, rd);
+ generateBidirectionalCollectionChangeWorkUnits(auditProcess, event, workUnit, rd);
}
}
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/reader/AuditReaderImpl.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/reader/AuditReaderImpl.java 2010-04-06 20:34:27 UTC (rev 19179)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/reader/AuditReaderImpl.java 2010-04-06 20:35:15 UTC (rev 19180)
@@ -35,8 +35,9 @@
import org.hibernate.envers.query.AuditQueryCreator;
import static org.hibernate.envers.tools.ArgumentsTools.checkNotNull;
import static org.hibernate.envers.tools.ArgumentsTools.checkPositive;
-import org.hibernate.envers.synchronization.AuditSync;
+import org.hibernate.envers.synchronization.AuditProcess;
+
import org.hibernate.NonUniqueResultException;
import org.hibernate.Query;
import org.hibernate.Session;
@@ -201,10 +202,10 @@
}
// Obtaining the current audit sync
- AuditSync auditSync = verCfg.getSyncManager().get((EventSource) session);
+ AuditProcess auditProcess = verCfg.getSyncManager().get((EventSource) session);
// And getting the current revision data
- return (T) auditSync.getCurrentRevisionData(session, persist);
+ return (T) auditProcess.getCurrentRevisionData(session, persist);
}
public AuditQueryCreator createQuery() {
Copied: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java (from rev 19150, core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSync.java)
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java (rev 0)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java 2010-04-06 20:35:15 UTC (rev 19180)
@@ -0,0 +1,156 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.envers.synchronization;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+
+import org.hibernate.action.BeforeTransactionCompletionProcess;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.envers.revisioninfo.RevisionInfoGenerator;
+import org.hibernate.envers.synchronization.work.AuditWorkUnit;
+import org.hibernate.envers.tools.Pair;
+
+import org.hibernate.FlushMode;
+import org.hibernate.Session;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class AuditProcess implements BeforeTransactionCompletionProcess {
+ private final RevisionInfoGenerator revisionInfoGenerator;
+
+ private final LinkedList<AuditWorkUnit> workUnits;
+ private final Queue<AuditWorkUnit> undoQueue;
+ private final Map<Pair<String, Object>, AuditWorkUnit> usedIds;
+
+ private Object revisionData;
+
+ public AuditProcess(RevisionInfoGenerator revisionInfoGenerator) {
+ this.revisionInfoGenerator = revisionInfoGenerator;
+
+ workUnits = new LinkedList<AuditWorkUnit>();
+ undoQueue = new LinkedList<AuditWorkUnit>();
+ usedIds = new HashMap<Pair<String, Object>, AuditWorkUnit>();
+ }
+
+ private void removeWorkUnit(AuditWorkUnit vwu) {
+ workUnits.remove(vwu);
+ if (vwu.isPerformed()) {
+ // If this work unit has already been performed, it must be deleted (undone) first.
+ undoQueue.offer(vwu);
+ }
+ }
+
+ public void addWorkUnit(AuditWorkUnit vwu) {
+ if (vwu.containsWork()) {
+ Object entityId = vwu.getEntityId();
+
+ if (entityId == null) {
+ // Just adding the work unit - it's not associated with any persistent entity.
+ workUnits.offer(vwu);
+ } else {
+ String entityName = vwu.getEntityName();
+ Pair<String, Object> usedIdsKey = Pair.make(entityName, entityId);
+
+ if (usedIds.containsKey(usedIdsKey)) {
+ AuditWorkUnit other = usedIds.get(usedIdsKey);
+
+ AuditWorkUnit result = vwu.dispatch(other);
+
+ if (result != other) {
+ removeWorkUnit(other);
+
+ if (result != null) {
+ usedIds.put(usedIdsKey, result);
+ workUnits.offer(result);
+ } // else: a null result means that no work unit should be kept
+ } // else: the result is the same as the work unit already added. No need to do anything.
+ } else {
+ usedIds.put(usedIdsKey, vwu);
+ workUnits.offer(vwu);
+ }
+ }
+ }
+ }
+
+ private void executeInSession(Session session) {
+ // Making sure the revision data is persisted.
+ getCurrentRevisionData(session, true);
+
+ AuditWorkUnit vwu;
+
+ // First undoing any performed work units
+ while ((vwu = undoQueue.poll()) != null) {
+ vwu.undo(session);
+ }
+
+ while ((vwu = workUnits.poll()) != null) {
+ vwu.perform(session, revisionData);
+ }
+ }
+
+ public Object getCurrentRevisionData(Session session, boolean persist) {
+ // Generating the revision data if not yet generated
+ if (revisionData == null) {
+ revisionData = revisionInfoGenerator.generate();
+ }
+
+ // Saving the revision data, if not yet saved and persist is true
+ if (!session.contains(revisionData) && persist) {
+ revisionInfoGenerator.saveRevisionData(session, revisionData);
+ }
+
+ return revisionData;
+ }
+
+ public void doBeforeTransactionCompletion(SessionImplementor session) {
+ if (workUnits.size() == 0 && undoQueue.size() == 0) {
+ return;
+ }
+
+ // see: http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4178431
+ if (FlushMode.isManualFlushMode(session.getFlushMode())) {
+ Session temporarySession = null;
+ try {
+ temporarySession = session.getFactory().openTemporarySession();
+
+ executeInSession(temporarySession);
+
+ temporarySession.flush();
+ } finally {
+ if (temporarySession != null) {
+ temporarySession.close();
+ }
+ }
+ } else {
+ executeInSession((Session) session);
+
+ // Explicity flushing the session, as the auto-flush may have already happened.
+ session.flush();
+ }
+ }
+}
Copied: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java (from rev 19150, core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSyncManager.java)
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java (rev 0)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java 2010-04-06 20:35:15 UTC (rev 19180)
@@ -0,0 +1,68 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.envers.synchronization;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.hibernate.action.AfterTransactionCompletionProcess;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.envers.revisioninfo.RevisionInfoGenerator;
+
+import org.hibernate.Transaction;
+import org.hibernate.event.EventSource;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class AuditProcessManager {
+ private final Map<Transaction, AuditProcess> auditProcesses;
+ private final RevisionInfoGenerator revisionInfoGenerator;
+
+ public AuditProcessManager(RevisionInfoGenerator revisionInfoGenerator) {
+ auditProcesses = new ConcurrentHashMap<Transaction, AuditProcess>();
+
+ this.revisionInfoGenerator = revisionInfoGenerator;
+ }
+
+ public AuditProcess get(EventSource session) {
+ final Transaction transaction = session.getTransaction();
+
+ AuditProcess auditProcess = auditProcesses.get(transaction);
+ if (auditProcess == null) {
+ // No worries about registering a transaction twice - a transaction is single thread
+ auditProcess = new AuditProcess(revisionInfoGenerator);
+ auditProcesses.put(transaction, auditProcess);
+
+ session.getActionQueue().registerProcess(auditProcess);
+ session.getActionQueue().registerProcess(new AfterTransactionCompletionProcess() {
+ public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
+ auditProcesses.remove(transaction);
+ }
+ });
+ }
+
+ return auditProcess;
+ }
+}
Deleted: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSync.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSync.java 2010-04-06 20:34:27 UTC (rev 19179)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSync.java 2010-04-06 20:35:15 UTC (rev 19180)
@@ -1,180 +0,0 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
- */
-package org.hibernate.envers.synchronization;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Queue;
-import javax.transaction.Synchronization;
-
-import org.hibernate.envers.revisioninfo.RevisionInfoGenerator;
-import org.hibernate.envers.synchronization.work.AuditWorkUnit;
-import org.hibernate.envers.tools.Pair;
-
-import org.hibernate.FlushMode;
-import org.hibernate.Session;
-import org.hibernate.Transaction;
-import org.hibernate.event.EventSource;
-
-/**
- * @author Adam Warski (adam at warski dot org)
- */
-public class AuditSync implements Synchronization {
- private final RevisionInfoGenerator revisionInfoGenerator;
- private final AuditSyncManager manager;
- private final EventSource session;
-
- private final Transaction transaction;
- private final LinkedList<AuditWorkUnit> workUnits;
- private final Queue<AuditWorkUnit> undoQueue;
- private final Map<Pair<String, Object>, AuditWorkUnit> usedIds;
-
- private Object revisionData;
-
- public AuditSync(AuditSyncManager manager, EventSource session, RevisionInfoGenerator revisionInfoGenerator) {
- this.manager = manager;
- this.session = session;
- this.revisionInfoGenerator = revisionInfoGenerator;
-
- transaction = session.getTransaction();
- workUnits = new LinkedList<AuditWorkUnit>();
- undoQueue = new LinkedList<AuditWorkUnit>();
- usedIds = new HashMap<Pair<String, Object>, AuditWorkUnit>();
- }
-
- private void removeWorkUnit(AuditWorkUnit vwu) {
- workUnits.remove(vwu);
- if (vwu.isPerformed()) {
- // If this work unit has already been performed, it must be deleted (undone) first.
- undoQueue.offer(vwu);
- }
- }
-
- public void addWorkUnit(AuditWorkUnit vwu) {
- if (vwu.containsWork()) {
- Object entityId = vwu.getEntityId();
-
- if (entityId == null) {
- // Just adding the work unit - it's not associated with any persistent entity.
- workUnits.offer(vwu);
- } else {
- String entityName = vwu.getEntityName();
- Pair<String, Object> usedIdsKey = Pair.make(entityName, entityId);
-
- if (usedIds.containsKey(usedIdsKey)) {
- AuditWorkUnit other = usedIds.get(usedIdsKey);
-
- AuditWorkUnit result = vwu.dispatch(other);
-
- if (result != other) {
- removeWorkUnit(other);
-
- if (result != null) {
- usedIds.put(usedIdsKey, result);
- workUnits.offer(result);
- } // else: a null result means that no work unit should be kept
- } // else: the result is the same as the work unit already added. No need to do anything.
- } else {
- usedIds.put(usedIdsKey, vwu);
- workUnits.offer(vwu);
- }
- }
- }
- }
-
- private void executeInSession(Session session) {
- // Making sure the revision data is persisted.
- getCurrentRevisionData(session, true);
-
- AuditWorkUnit vwu;
-
- // First undoing any performed work units
- while ((vwu = undoQueue.poll()) != null) {
- vwu.undo(session);
- }
-
- while ((vwu = workUnits.poll()) != null) {
- vwu.perform(session, revisionData);
- }
- }
-
- public Object getCurrentRevisionData(Session session, boolean persist) {
- // Generating the revision data if not yet generated
- if (revisionData == null) {
- revisionData = revisionInfoGenerator.generate();
- }
-
- // Saving the revision data, if not yet saved and persist is true
- if (!session.contains(revisionData) && persist) {
- revisionInfoGenerator.saveRevisionData(session, revisionData);
- }
-
- return revisionData;
- }
-
- public void beforeCompletion() {
- if (workUnits.size() == 0 && undoQueue.size() == 0) {
- return;
- }
-
- try {
- // see: http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4178431
- if (FlushMode.isManualFlushMode(session.getFlushMode()) || session.isClosed()) {
- Session temporarySession = null;
- try {
- temporarySession = session.getFactory().openTemporarySession();
-
- executeInSession(temporarySession);
-
- temporarySession.flush();
- } finally {
- if (temporarySession != null) {
- temporarySession.close();
- }
- }
- } else {
- executeInSession(session);
-
- // Explicity flushing the session, as the auto-flush may have already happened.
- session.flush();
- }
- } catch (RuntimeException e) {
- // Rolling back the transaction in case of any exceptions
- //noinspection finally
- try {
- if (session.getTransaction().isActive()) {
- session.getTransaction().rollback();
- }
- } finally {
- //noinspection ThrowFromFinallyBlock
- throw e;
- }
- }
- }
-
- public void afterCompletion(int i) {
- manager.remove(transaction);
- }
-}
Deleted: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSyncManager.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSyncManager.java 2010-04-06 20:34:27 UTC (rev 19179)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditSyncManager.java 2010-04-06 20:35:15 UTC (rev 19180)
@@ -1,65 +0,0 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
- */
-package org.hibernate.envers.synchronization;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.hibernate.envers.revisioninfo.RevisionInfoGenerator;
-
-import org.hibernate.Transaction;
-import org.hibernate.event.EventSource;
-
-/**
- * @author Adam Warski (adam at warski dot org)
- */
-public class AuditSyncManager {
- private final Map<Transaction, AuditSync> auditSyncs;
- private final RevisionInfoGenerator revisionInfoGenerator;
-
- public AuditSyncManager(RevisionInfoGenerator revisionInfoGenerator) {
- auditSyncs = new ConcurrentHashMap<Transaction, AuditSync>();
-
- this.revisionInfoGenerator = revisionInfoGenerator;
- }
-
- public AuditSync get(EventSource session) {
- Transaction transaction = session.getTransaction();
-
- AuditSync verSync = auditSyncs.get(transaction);
- if (verSync == null) {
- // No worries about registering a transaction twice - a transaction is single thread
- verSync = new AuditSync(this, session, revisionInfoGenerator);
- auditSyncs.put(transaction, verSync);
-
- transaction.registerSynchronization(verSync);
- }
-
- return verSync;
- }
-
- public void remove(Transaction transaction) {
- auditSyncs.remove(transaction);
- }
-}
Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/ExceptionListener.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/ExceptionListener.java 2010-04-06 20:34:27 UTC (rev 19179)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/ExceptionListener.java 2010-04-06 20:35:15 UTC (rev 19180)
@@ -40,7 +40,7 @@
cfg.addAnnotatedClass(ExceptionListenerRevEntity.class);
}
- @Test
+ @Test(expectedExceptions = RuntimeException.class)
public void testTransactionRollback() throws InterruptedException {
// Trying to persist an entity - however the listener should throw an exception, so the entity
// shouldn't be persisted
@@ -49,9 +49,12 @@
StrTestEntity te = new StrTestEntity("x");
em.persist(te);
em.getTransaction().commit();
+ }
+ @Test(dependsOnMethods = "testTransactionRollback")
+ public void testDataNotPersisted() {
// Checking if the entity became persisted
- em = getEntityManager();
+ EntityManager em = getEntityManager();
em.getTransaction().begin();
Long count = (Long) em.createQuery("select count(s) from StrTestEntity s where s.str = 'x'").getSingleResult();
assert count == 0l;
More information about the hibernate-commits
mailing list