[hibernate-commits] Hibernate SVN: r19888 - in core/trunk/envers/src: main/java/org/hibernate/envers/configuration and 10 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Fri Jul 2 02:32:14 EDT 2010


Author: adamw
Date: 2010-07-02 02:32:13 -0400 (Fri, 02 Jul 2010)
New Revision: 19888

Added:
   core/trunk/envers/src/main/java/org/hibernate/envers/strategy/
   core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java
   core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java
   core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java
Modified:
   core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java
   core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java
   core/trunk/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
   core/trunk/envers/src/main/java/org/hibernate/envers/query/impl/AbstractAuditQuery.java
   core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/AbstractAuditWorkUnit.java
   core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java
   core/trunk/envers/src/main/java/org/hibernate/envers/tools/query/QueryBuilder.java
   core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java
   core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/customtype/CompositeTestUserType.java
   core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/sametable/BasicSametable.java
   core/trunk/envers/src/test/java/org/hibernate/envers/test/performance/AbstractPerformanceTest.java
   core/trunk/envers/src/test/resources/hibernate.test.cfg.xml
   core/trunk/envers/src/test/resources/testng.xml
Log:
HHH-3764:
- adding an end-revision column to the audit entities if the appropraite strategy is used

HHH-3765:
- filling in the end-revision column on audited entities changes

- applying patch by Stephanie Pau - thanks!

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-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -27,10 +27,12 @@
 import java.util.Properties;
 import java.util.WeakHashMap;
 
+import org.hibernate.MappingException;
 import org.hibernate.envers.entities.EntitiesConfigurations;
 import org.hibernate.envers.revisioninfo.RevisionInfoNumberReader;
 import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator;
 import org.hibernate.envers.synchronization.AuditProcessManager;
+import org.hibernate.envers.strategy.AuditStrategy;
 
 import org.hibernate.cfg.Configuration;
 import org.hibernate.cfg.AnnotationConfiguration;
@@ -38,11 +40,13 @@
 
 /**
  * @author Adam Warski (adam at warski dot org)
+ * @author Stephanie Pau at Markit Group Plc
  */
 public class AuditConfiguration {
     private final GlobalConfiguration globalCfg;
     private final AuditEntitiesConfiguration auditEntCfg;
     private final AuditProcessManager auditProcessManager;
+    private final AuditStrategy auditStrategy;
     private final EntitiesConfigurations entCfg;
     private final RevisionInfoQueryCreator revisionInfoQueryCreator;
     private final RevisionInfoNumberReader revisionInfoNumberReader;
@@ -71,7 +75,11 @@
         return revisionInfoNumberReader;
     }
 
-    @SuppressWarnings({"unchecked"})
+    public AuditStrategy getAuditStrategy() {
+        return auditStrategy;
+    }
+
+    @SuppressWarnings({ "unchecked" })
     public AuditConfiguration(Configuration cfg) {
         Properties properties = cfg.getProperties();
 
@@ -81,6 +89,14 @@
         auditEntCfg = new AuditEntitiesConfiguration(properties, revInfoCfgResult.getRevisionInfoEntityName());
         globalCfg = new GlobalConfiguration(properties);
         auditProcessManager = new AuditProcessManager(revInfoCfgResult.getRevisionInfoGenerator());
+
+        try {
+            Class auditStrategyClass = Thread.currentThread().getContextClassLoader().loadClass(auditEntCfg.getAuditStrategyName());
+            auditStrategy = (AuditStrategy) auditStrategyClass.newInstance();
+        } catch (Exception e) {
+           throw new MappingException(String.format("Unable to create AuditStrategy[%s] instance." , auditEntCfg.getAuditStrategyName()));
+        }
+        
         revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
         revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
         entCfg = new EntitiesConfigurator().configure(cfg, reflectionManager, globalCfg, auditEntCfg,

Modified: core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -25,18 +25,28 @@
 
 import static org.hibernate.envers.tools.Tools.getProperty;
 
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
 
+import org.hibernate.MappingException;
+import org.hibernate.envers.strategy.DefaultAuditStrategy;
+import org.hibernate.envers.strategy.ValidTimeAuditStrategy;
+
 /**
  * Configuration of versions entities - names of fields, entities and tables created to store versioning information.
  * @author Adam Warski (adam at warski dot org)
+ * @author Stephanie Pau at Markit Group Plc
  */
 public class AuditEntitiesConfiguration {
     private final String auditTablePrefix;
     private final String auditTableSuffix;
 
+    private final String auditStrategyName;
     private final String originalIdPropName;
 
     private final String revisionFieldName;
@@ -50,6 +60,8 @@
 
     private final Map<String, String> customAuditTablesNames;
 
+    private final String revisionEndFieldName;
+
     public AuditEntitiesConfiguration(Properties properties, String revisionInfoEntityName) {
         this.revisionInfoEntityName = revisionInfoEntityName;
 
@@ -62,6 +74,11 @@
                 "org.hibernate.envers.auditTableSuffix",
                 "_AUD");
 
+        auditStrategyName = getProperty(properties,
+                "org.hibernate.envers.audit_strategy",
+                "org.hibernate.envers.audit_strategy",
+                DefaultAuditStrategy.class.getName());
+
         originalIdPropName = "originalId";
 
         revisionFieldName = getProperty(properties,
@@ -75,6 +92,11 @@
                 "REVTYPE");
         revisionTypePropType = "byte";
 
+        revisionEndFieldName = getProperty(properties,
+                "org.hibernate.envers.audit_strategy_valid_time_end_name",
+                "org.hibernate.envers.audit_strategy_valid_time_end_name",
+                "REVEND");
+
         customAuditTablesNames = new HashMap<String, String>();
 
         revisionNumberPath = originalIdPropName + "." + revisionFieldName + ".id";
@@ -133,4 +155,12 @@
 
         return customHistoryTableName;
     }
+
+    public String getAuditStrategyName() {
+        return auditStrategyName;
+    }
+
+    public String getRevisionEndFieldName() {
+        return revisionEndFieldName;
+    }
 }

Modified: core/trunk/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -38,6 +38,7 @@
 import org.hibernate.envers.entities.mapper.ExtendedPropertyMapper;
 import org.hibernate.envers.entities.mapper.MultiPropertyMapper;
 import org.hibernate.envers.entities.mapper.SubclassPropertyMapper;
+import org.hibernate.envers.strategy.ValidTimeAuditStrategy;
 import org.hibernate.envers.tools.StringTools;
 import org.hibernate.envers.tools.Triple;
 import org.hibernate.envers.RelationTargetAuditMode;
@@ -53,6 +54,7 @@
  * @author Adam Warski (adam at warski dot org)
  * @author Sebastian Komander
  * @author Tomasz Bech
+ * @author Stephanie Pau at Markit Group Plc
  */
 public final class AuditMetadataGenerator {
     private static final Logger log = LoggerFactory.getLogger(AuditMetadataGenerator.class);
@@ -124,8 +126,23 @@
         Element revTypeProperty = MetadataTools.addProperty(any_mapping, verEntCfg.getRevisionTypePropName(),
                 verEntCfg.getRevisionTypePropType(), true, false);
         revTypeProperty.addAttribute("type", "org.hibernate.envers.entities.RevisionTypeType");
+
+        // Adding the end revision, if appropriate
+        addEndRevision(any_mapping);
     }
 
+    private void addEndRevision(Element any_mapping) {
+        // Add the end-revision field, if the appropriate strategy is used.
+        if (ValidTimeAuditStrategy.class.getName().equals(verEntCfg.getAuditStrategyName())) {
+            Element end_rev_mapping = (Element) revisionInfoRelationMapping.clone();
+            end_rev_mapping.setName("many-to-one");
+            end_rev_mapping.addAttribute("name", verEntCfg.getRevisionEndFieldName());
+            MetadataTools.addOrModifyColumn(end_rev_mapping, verEntCfg.getRevisionEndFieldName());
+
+            any_mapping.add(end_rev_mapping);
+        }
+    }
+
     @SuppressWarnings({"unchecked"})
     void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
                   EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,

Modified: core/trunk/envers/src/main/java/org/hibernate/envers/query/impl/AbstractAuditQuery.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/query/impl/AbstractAuditQuery.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/query/impl/AbstractAuditQuery.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -24,9 +24,7 @@
 package org.hibernate.envers.query.impl;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import javax.persistence.NoResultException;
 import javax.persistence.NonUniqueResultException;
 
@@ -80,16 +78,8 @@
     }
 
     protected List buildAndExecuteQuery() {
-        StringBuilder querySb = new StringBuilder();
-        Map<String, Object> queryParamValues = new HashMap<String, Object>();
+        Query query = qb.toQuery(versionsReader.getSession());
 
-        qb.build(querySb, queryParamValues);
-
-        Query query = versionsReader.getSession().createQuery(querySb.toString());
-        for (Map.Entry<String, Object> paramValue : queryParamValues.entrySet()) {
-            query.setParameter(paramValue.getKey(), paramValue.getValue());
-        }
-
         setQueryProperties(query);
 
         return query.list();

Added: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java	                        (rev 0)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -0,0 +1,39 @@
+package org.hibernate.envers.strategy;
+
+import org.hibernate.Session;
+import org.hibernate.envers.configuration.AuditConfiguration;
+import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
+
+import java.io.Serializable;
+
+/**
+ * Behaviours of different audit strategy for populating audit data.
+ * 
+ * @author Stephanie Pau
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface AuditStrategy {
+    /**
+     * Perform the persistence of audited data for regular entities.
+     * 
+     * @param session Session, which can be used to persist the data.
+     * @param entityName Name of the entity, in which the audited change happens
+     * @param auditCfg Audit configuration
+     * @param id Id of the entity.
+     * @param data Audit data to persist
+     * @param revision Current revision data
+     */
+    void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
+                 Object revision);
+
+    /**
+     * Perform the persistence of audited data for collection ("middle") entities.
+     *
+     * @param session Session, which can be used to persist the data.
+     * @param auditCfg Audit configuration
+     * @param persistentCollectionChangeData Collection change data to be persisted.
+     * @param revision Current revision data
+     */
+    void performCollectionChange(Session session, AuditConfiguration auditCfg,
+                                 PersistentCollectionChangeData persistentCollectionChangeData, Object revision);
+}


Property changes on: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java	                        (rev 0)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -0,0 +1,25 @@
+package org.hibernate.envers.strategy;
+
+import org.hibernate.Session;
+import org.hibernate.envers.configuration.AuditConfiguration;
+import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
+
+import java.io.Serializable;
+
+/**
+ * Default strategy is to simply persist the audit data.
+ *
+ * @author Adam Warski
+ * @author Stephanie Pau
+ */
+public class DefaultAuditStrategy implements AuditStrategy {
+    public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
+                        Object revision) {
+        session.save(auditCfg.getAuditEntCfg().getAuditEntityName(entityName), data);
+    }
+
+    public void performCollectionChange(Session session, AuditConfiguration auditCfg,
+                                        PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
+        session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
+    }
+}


Property changes on: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java	                        (rev 0)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -0,0 +1,105 @@
+package org.hibernate.envers.strategy;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.Session;
+import org.hibernate.envers.RevisionType;
+import org.hibernate.envers.configuration.AuditConfiguration;
+import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
+import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
+import org.hibernate.envers.entities.mapper.id.IdMapper;
+import org.hibernate.envers.tools.query.QueryBuilder;
+
+/**
+ * Audit strategy which additionally manages the end-revision number: updates the end-revision field on the last
+ * revision that was persisted before the current one.
+ * 
+ * @author Stephanie Pau
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ValidTimeAuditStrategy implements AuditStrategy {
+    public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
+                        Object revision) {
+        AuditEntitiesConfiguration audEntCfg = auditCfg.getAuditEntCfg();
+        String auditedEntityName = audEntCfg.getAuditEntityName(entityName);
+
+        // Update the end date of the previous row if this operation is expected to have a previous row
+        if (getRevisionType(auditCfg, data) != RevisionType.ADD) {
+            /*
+             Constructing a query:
+             select e from audited_ent e where e.end_rev is null and e.id = :id
+             */
+
+            QueryBuilder qb = new QueryBuilder(auditedEntityName, "e");
+
+            // e.id = :id
+            IdMapper idMapper = auditCfg.getEntCfg().get(entityName).getIdMapper();
+            idMapper.addIdEqualsToQuery(qb.getRootParameters(), id, auditCfg.getAuditEntCfg().getOriginalIdPropName(), true);
+
+            updateLastRevision(session, auditCfg, qb, id, auditedEntityName, revision);
+        }
+
+        // Save the audit data
+        session.save(auditedEntityName, data);
+    }
+
+    @SuppressWarnings({"unchecked"})
+    public void performCollectionChange(Session session, AuditConfiguration auditCfg,
+                                        PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
+        // Update the end date of the previous row if this operation is expected to have a previous row
+        if (getRevisionType(auditCfg, persistentCollectionChangeData.getData()) != RevisionType.ADD) {
+            /*
+             Constructing a query (there are multiple id fields):
+             select e from audited_middle_ent e where e.end_rev is null and e.id1 = :id1 and e.id2 = :id2 ...
+             */
+
+            QueryBuilder qb = new QueryBuilder(persistentCollectionChangeData.getEntityName(), "e");
+
+            // Adding a parameter for each id component, except the rev number
+            String originalIdPropName = auditCfg.getAuditEntCfg().getOriginalIdPropName();
+            Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
+                    originalIdPropName);
+            for (Map.Entry<String, Object> originalIdEntry : originalId.entrySet()) {
+                if (!auditCfg.getAuditEntCfg().getRevisionFieldName().equals(originalIdEntry.getKey())) {
+                    qb.getRootParameters().addWhereWithParam(originalIdPropName + "." + originalIdEntry.getKey(),
+                            true, "=", originalIdEntry.getValue());
+                }
+            }
+
+            updateLastRevision(session, auditCfg, qb, originalId, persistentCollectionChangeData.getEntityName(), revision);
+        }
+
+        // Save the audit data
+        session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
+    }
+
+    @SuppressWarnings({"unchecked"})
+    private RevisionType getRevisionType(AuditConfiguration auditCfg, Object data) {
+        return (RevisionType) ((Map<String, Object>) data).get(auditCfg.getAuditEntCfg().getRevisionTypePropName());
+    }
+
+    @SuppressWarnings({"unchecked"})
+    private void updateLastRevision(Session session, AuditConfiguration auditCfg, QueryBuilder qb,
+                                    Object id, String auditedEntityName, Object revision) {
+        String revisionEndFieldName = auditCfg.getAuditEntCfg().getRevisionEndFieldName();
+
+        // e.end_rev is null
+        qb.getRootParameters().addWhere(revisionEndFieldName, true, "is", "null", false);
+
+        List l = qb.toQuery(session).list();
+
+        // There should be one entry
+        if (l.size() == 1) {
+            // Setting the end revision to be the current rev
+            Object previousData = l.get(0);
+            ((Map<String, Object>) previousData).put(revisionEndFieldName, revision);
+
+            // Saving the previous version
+            session.save(auditedEntityName, previousData);
+        } else {
+            throw new RuntimeException("Cannot find previous revision for entity " + auditedEntityName + " and id " + id);
+        }
+    }
+}


Property changes on: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java
___________________________________________________________________
Name: svn:executable
   + *

Modified: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/AbstractAuditWorkUnit.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/AbstractAuditWorkUnit.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/AbstractAuditWorkUnit.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -33,15 +33,18 @@
 
 import org.hibernate.Session;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.envers.strategy.AuditStrategy;
 
 /**
  * @author Adam Warski (adam at warski dot org)
+ * @author Stephanie Pau at Markit Group Plc
  */
 public abstract class AbstractAuditWorkUnit implements AuditWorkUnit {
 	protected final SessionImplementor sessionImplementor;
     protected final AuditConfiguration verCfg;
     protected final Serializable id;
     protected final String entityName;
+    protected final AuditStrategy auditStrategy;
 
     private Object performedData;
 
@@ -51,6 +54,7 @@
         this.verCfg = verCfg;
         this.id = id;
         this.entityName = entityName;
+        this.auditStrategy = verCfg.getAuditStrategy();
     }
 
     protected void fillDataWithId(Map<String, Object> data, Object revision, RevisionType revisionType) {
@@ -67,7 +71,7 @@
     public void perform(Session session, Object revisionData) {
         Map<String, Object> data = generateData(revisionData);
 
-        session.save(verCfg.getAuditEntCfg().getAuditEntityName(getEntityName()), data);
+        auditStrategy.perform(session, getEntityName(), verCfg, id, data, revisionData);
 
         setPerformed(data);
     }

Modified: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -29,6 +29,7 @@
 import java.util.HashMap;
 import java.util.ArrayList;
 
+import org.hibernate.envers.RevisionType;
 import org.hibernate.envers.configuration.AuditConfiguration;
 import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
 import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
@@ -84,7 +85,7 @@
             ((Map<String, Object>) persistentCollectionChangeData.getData().get(entitiesCfg.getOriginalIdPropName()))
                     .put(entitiesCfg.getRevisionFieldName(), revisionData);
 
-            session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
+            auditStrategy.performCollectionChange(session, verCfg, persistentCollectionChangeData, revisionData);
         }
     }
 
@@ -137,13 +138,24 @@
 
             // Including only those original changes, which are not overshadowed by new ones.
             for (PersistentCollectionChangeData originalCollectionChangeData : original.getCollectionChanges()) {
-                if (!newChangesIdMap.containsKey(getOriginalId(originalCollectionChangeData))) {
+                Object originalOriginalId = getOriginalId(originalCollectionChangeData);
+                if (!newChangesIdMap.containsKey(originalOriginalId)) {
                     mergedChanges.add(originalCollectionChangeData);
+                } else {
+                    // If the changes collide, checking if the first one isn't a DEL, and the second a subsequent ADD
+                    // If so, removing the change alltogether.
+                    String revTypePropName = verCfg.getAuditEntCfg().getRevisionTypePropName();
+                    if (RevisionType.ADD.equals(newChangesIdMap.get(originalOriginalId).getData().get(
+                            revTypePropName)) && RevisionType.DEL.equals(originalCollectionChangeData.getData().get(
+                            revTypePropName))) {
+                        newChangesIdMap.remove(originalOriginalId);
+                    }
                 }
             }
 
-            // Finally adding all of the new changes to the end of the list
-            mergedChanges.addAll(getCollectionChanges());
+            // Finally adding all of the new changes to the end of the list (the map values may differ from
+            // getCollectionChanges() because of the last operation above).
+            mergedChanges.addAll(newChangesIdMap.values());
 
             return new PersistentCollectionChangeWorkUnit(sessionImplementor, entityName, verCfg, id, mergedChanges, 
                     referencingPropertyName);

Modified: core/trunk/envers/src/main/java/org/hibernate/envers/tools/query/QueryBuilder.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/tools/query/QueryBuilder.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/tools/query/QueryBuilder.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -24,9 +24,12 @@
 package org.hibernate.envers.tools.query;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.hibernate.Query;
+import org.hibernate.Session;
 import org.hibernate.envers.tools.MutableInteger;
 import org.hibernate.envers.tools.Pair;
 import org.hibernate.envers.tools.StringTools;
@@ -197,4 +200,18 @@
 
         return orderList;
     }
+
+    public Query toQuery(Session session) {
+        StringBuilder querySb = new StringBuilder();
+        Map<String, Object> queryParamValues = new HashMap<String, Object>();
+
+        build(querySb, queryParamValues);
+
+        Query query = session.createQuery(querySb.toString());
+        for (Map.Entry<String, Object> paramValue : queryParamValues.entrySet()) {
+            query.setParameter(paramValue.getKey(), paramValue.getValue());
+        }
+
+        return query;
+    }
 }

Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -30,9 +30,7 @@
 import org.hibernate.envers.AuditReader;
 import org.hibernate.envers.AuditReaderFactory;
 import org.hibernate.envers.event.AuditEventListener;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.AfterClass;
+import org.testng.annotations.*;
 
 import org.hibernate.ejb.Ejb3Configuration;
 import org.hibernate.event.*;
@@ -78,17 +76,23 @@
     }
 
     @BeforeClass
-    public void init() throws IOException {
-        init(true);
+    @Parameters("auditStrategy")    
+    public void init(@Optional String auditStrategy) throws IOException {
+        init(true, auditStrategy);
     }
 
-    protected void init(boolean audited) throws IOException {
+    protected void init(boolean audited, String auditStrategy) throws IOException {
         this.audited = audited;
 
         cfg = new Ejb3Configuration();
         if (audited) {
             initListeners();
         }
+
+        if (auditStrategy != null && !"".equals(auditStrategy)) {
+            cfg.setProperty("org.hibernate.envers.audit_strategy", auditStrategy);
+        }       
+
         cfg.configure("hibernate.test.cfg.xml");
         configure(cfg);
         emf = cfg.buildEntityManagerFactory();

Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/customtype/CompositeTestUserType.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/customtype/CompositeTestUserType.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/customtype/CompositeTestUserType.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -90,9 +90,6 @@
     public Object nullSafeGet(final ResultSet rs, final String[] names,
                               final SessionImplementor session,
                               final Object owner) throws HibernateException, SQLException {
-        if (rs.wasNull()) {
-            return null;
-        }
         final String prop1 = rs.getString(names[0]);
         if (prop1 == null) {
             return null;

Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/sametable/BasicSametable.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/sametable/BasicSametable.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/sametable/BasicSametable.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -66,7 +66,7 @@
         session.createSQLQuery("DROP TABLE children").executeUpdate();
         session.createSQLQuery("CREATE TABLE children(parent_id integer, child1_id integer NULL, child2_id integer NULL)").executeUpdate();
         session.createSQLQuery("DROP TABLE children_AUD").executeUpdate();
-        session.createSQLQuery("CREATE TABLE children_AUD(REV integer NOT NULL, REVTYPE tinyint, " +
+        session.createSQLQuery("CREATE TABLE children_AUD(REV integer NOT NULL, REVEND integer, REVTYPE tinyint, " +
                 "parent_id integer, child1_id integer NULL, child2_id integer NULL)").executeUpdate();
         em.getTransaction().commit();
         em.clear();

Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/performance/AbstractPerformanceTest.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/performance/AbstractPerformanceTest.java	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/performance/AbstractPerformanceTest.java	2010-07-02 06:32:13 UTC (rev 19888)
@@ -88,11 +88,11 @@
         List<Long> unauditedRuns = new ArrayList<Long>();
         List<Long> auditedRuns = new ArrayList<Long>();
 
-        init(true);
+        init(true, null);
         long audited = run(numberOfRuns, auditedRuns);
         close();
 
-        init(false);
+        init(false, null);
         long unaudited = run(numberOfRuns, unauditedRuns);
         close();
 

Modified: core/trunk/envers/src/test/resources/hibernate.test.cfg.xml
===================================================================
--- core/trunk/envers/src/test/resources/hibernate.test.cfg.xml	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/resources/hibernate.test.cfg.xml	2010-07-02 06:32:13 UTC (rev 19888)
@@ -23,6 +23,8 @@
         <!--<property name="connection.username">root</property>-->
         <!--<property name="connection.password"></property>-->
 
+        <!--<property name="org.hibernate.envers.audit_strategy">org.hibernate.envers.strategy.ValidTimeAuditStrategy</property>-->
+
         <!--<property name="hibernate.jdbc.batch_size">100</property>-->
 
         <!--<event type="post-insert">

Modified: core/trunk/envers/src/test/resources/testng.xml
===================================================================
--- core/trunk/envers/src/test/resources/testng.xml	2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/resources/testng.xml	2010-07-02 06:32:13 UTC (rev 19888)
@@ -1,8 +1,5 @@
-<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
-
-<suite name="Envers">
-    <test name="All">
-        <packages>
+<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" [
+   <!ENTITY packages '
             <package name="org.hibernate.envers.test.integration.accesstype" />
             <package name="org.hibernate.envers.test.integration.auditReader" />
             <package name="org.hibernate.envers.test.integration.basic" />
@@ -71,6 +68,19 @@
             <package name="org.hibernate.envers.test.integration.secondary.ids" />
             <package name="org.hibernate.envers.test.integration.serialization" />
             <package name="org.hibernate.envers.test.integration.superclass" />
+		'>
+]>
+
+<suite name="Envers">
+    <test name="All">
+        <packages>
+            &packages;
         </packages>
     </test>
+    <test name="ValidTimeAuditStrategy">
+        <parameter name="auditStrategy" value="org.hibernate.envers.strategy.ValidTimeAuditStrategy" />
+        <packages>
+            &packages;
+        </packages>
+    </test>
 </suite>



More information about the hibernate-commits mailing list