[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