Author: adamw
Date: 2009-12-08 11:16:27 -0500 (Tue, 08 Dec 2009)
New Revision: 18165
Added:
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/ternary/TernaryMapFlush.java
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/GlobalConfiguration.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java
Log:
svn merge -r 18150:18163
https://svn.jboss.org/repos/hibernate/core/trunk/envers .
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/GlobalConfiguration.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/GlobalConfiguration.java 2009-12-08
16:09:42 UTC (rev 18164)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/GlobalConfiguration.java 2009-12-08
16:16:27 UTC (rev 18165)
@@ -74,8 +74,8 @@
"false");
storeDataAtDelete = Boolean.parseBoolean(storeDataDeletedEntityStr);
- defaultSchemaName =
properties.getProperty("org.hibernate.envers.default_audit_table_schema_name",
null);
- defaultCatalogName =
properties.getProperty("org.hibernate.envers.default_audit_table_catalog_name",
null);
+ defaultSchemaName =
properties.getProperty("org.hibernate.envers.default_schema", null);
+ defaultCatalogName =
properties.getProperty("org.hibernate.envers.default_catalog", null);
correlatedSubqueryOperator =
"org.hibernate.dialect.HSQLDialect".equals(
properties.getProperty("hibernate.dialect")) ? "in" :
"=";
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java 2009-12-08
16:09:42 UTC (rev 18164)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java 2009-12-08
16:16:27 UTC (rev 18165)
@@ -26,6 +26,8 @@
import java.io.Serializable;
import java.util.List;
import java.util.Map;
+import java.util.HashMap;
+import java.util.ArrayList;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
@@ -45,14 +47,14 @@
private final String referencingPropertyName;
public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor,
String entityName,
- AuditConfiguration verCfg, PersistentCollection collection,
+ AuditConfiguration auditCfg, PersistentCollection collection,
CollectionEntry collectionEntry, Serializable snapshot, Serializable id) {
- super(sessionImplementor, entityName, verCfg, null);
+ super(sessionImplementor, entityName, auditCfg, new
PersistentCollectionChangeWorkUnitId(id, collectionEntry.getRole()));
String ownerEntityName = ((AbstractCollectionPersister)
collectionEntry.getLoadedPersister()).getOwnerEntityName();
referencingPropertyName = collectionEntry.getRole().substring(ownerEntityName.length()
+ 1);
- collectionChanges = verCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
+ collectionChanges =
auditCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
.mapCollectionChanges(referencingPropertyName, collection, snapshot,
id);
}
@@ -98,6 +100,82 @@
}
public KeepCheckResult dispatch(KeepCheckVisitor first) {
- return null;
+ if (first instanceof PersistentCollectionChangeWorkUnit) {
+ PersistentCollectionChangeWorkUnit original =
(PersistentCollectionChangeWorkUnit) first;
+
+ // Merging the collection changes in both work units.
+
+ // First building a map from the ids of the collection-entry-entities from
the "second" collection changes,
+ // to the PCCD objects. That way, we will be later able to check if an
"original" collection change
+ // should be added, or if it is overshadowed by a new one.
+ Map<Object, PersistentCollectionChangeData> newChangesIdMap = new
HashMap<Object, PersistentCollectionChangeData>();
+ for (PersistentCollectionChangeData persistentCollectionChangeData :
getCollectionChanges()) {
+ newChangesIdMap.put(
+ getOriginalId(persistentCollectionChangeData),
+ persistentCollectionChangeData);
+ }
+
+ // Storing the current changes
+ List<PersistentCollectionChangeData> newChanges = new
ArrayList<PersistentCollectionChangeData>();
+ newChanges.addAll(collectionChanges);
+
+ // And building the change list again
+ collectionChanges.clear();
+ for (PersistentCollectionChangeData originalCollectionChangeData :
original.getCollectionChanges()) {
+ if
(!newChangesIdMap.containsKey(getOriginalId(originalCollectionChangeData))) {
+ collectionChanges.add(originalCollectionChangeData);
+ }
+ }
+
+ // Finally adding all of the new changes to the end of the list
+ collectionChanges.addAll(newChanges);
+ } else {
+ throw new RuntimeException("Trying to merge a " + first + "
with a PersitentCollectionChangeWorkUnit. " +
+ "This is not really possible.");
+ }
+
+ return KeepCheckResult.SECOND;
}
+
+ private Object getOriginalId(PersistentCollectionChangeData
persistentCollectionChangeData) {
+ return
persistentCollectionChangeData.getData().get(verCfg.getAuditEntCfg().getOriginalIdPropName());
+ }
+
+ /**
+ * A unique identifier for a collection work unit. Consists of an id of the owning
entity and the name of
+ * the entity plus the name of the field (the role). This is needed because such
collections aren't entities
+ * in the "normal" mapping, but they are entities for Envers.
+ */
+ private static class PersistentCollectionChangeWorkUnitId implements Serializable {
+ private static final long serialVersionUID = -8007831518629167537L;
+
+ private final Serializable ownerId;
+ private final String role;
+
+ public PersistentCollectionChangeWorkUnitId(Serializable ownerId, String role) {
+ this.ownerId = ownerId;
+ this.role = role;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PersistentCollectionChangeWorkUnitId that =
(PersistentCollectionChangeWorkUnitId) o;
+
+ if (ownerId != null ? !ownerId.equals(that.ownerId) : that.ownerId != null)
return false;
+ //noinspection RedundantIfStatement
+ if (role != null ? !role.equals(that.role) : that.role != null) return
false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = ownerId != null ? ownerId.hashCode() : 0;
+ result = 31 * result + (role != null ? role.hashCode() : 0);
+ return result;
+ }
+ }
}
Copied:
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/ternary/TernaryMapFlush.java
(from rev 18163,
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/ternary/TernaryMapFlush.java)
===================================================================
---
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/ternary/TernaryMapFlush.java
(rev 0)
+++
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/ternary/TernaryMapFlush.java 2009-12-08
16:16:27 UTC (rev 18165)
@@ -0,0 +1,144 @@
+/*
+ * 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.test.integration.manytomany.ternary;
+
+import org.hibernate.ejb.Ejb3Configuration;
+import org.hibernate.envers.test.AbstractEntityTest;
+import org.hibernate.envers.test.entities.IntTestEntity;
+import org.hibernate.envers.test.entities.StrTestEntity;
+import org.hibernate.envers.test.tools.TestTools;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+
+import javax.persistence.EntityManager;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class TernaryMapFlush extends AbstractEntityTest {
+ private Integer str1_id;
+ private Integer str2_id;
+ private Integer int1_id;
+ private Integer int2_id;
+ private Integer map1_id;
+
+ public void configure(Ejb3Configuration cfg) {
+ cfg.addAnnotatedClass(TernaryMapEntity.class);
+ cfg.addAnnotatedClass(StrTestEntity.class);
+ cfg.addAnnotatedClass(IntTestEntity.class);
+ }
+
+ @Test
+ public void createData() {
+ EntityManager em = getEntityManager();
+
+ StrTestEntity str1 = new StrTestEntity("a");
+ StrTestEntity str2 = new StrTestEntity("b");
+ IntTestEntity int1 = new IntTestEntity(1);
+ IntTestEntity int2 = new IntTestEntity(2);
+ TernaryMapEntity map1 = new TernaryMapEntity();
+
+ // Revision 1 (int1 -> str1)
+ em.getTransaction().begin();
+
+ em.persist(str1);
+ em.persist(str2);
+ em.persist(int1);
+ em.persist(int2);
+
+ map1.getMap().put(int1, str1);
+
+ em.persist(map1);
+
+ em.getTransaction().commit();
+
+ // Revision 2 (removing int1->str1, flushing, adding int1->str1 again and a
new int2->str2 mapping to force a change)
+
+ em.getTransaction().begin();
+
+ map1 = em.find(TernaryMapEntity.class, map1.getId());
+ str1 = em.find(StrTestEntity.class, str1.getId());
+ int1 = em.find(IntTestEntity.class, int1.getId());
+
+ map1.setMap(new HashMap<IntTestEntity, StrTestEntity>());
+
+ em.flush();
+
+ map1.getMap().put(int1, str1);
+ map1.getMap().put(int2, str2);
+
+ em.getTransaction().commit();
+
+ // Revision 3 (removing int1->str1, flushing, overwriting int2->str1)
+
+ em.getTransaction().begin();
+
+ map1 = em.find(TernaryMapEntity.class, map1.getId());
+ str1 = em.find(StrTestEntity.class, str1.getId());
+ int1 = em.find(IntTestEntity.class, int1.getId());
+
+ map1.getMap().remove(int1);
+
+ em.flush();
+
+ map1.getMap().put(int2, str1);
+
+ em.getTransaction().commit();
+
+ //
+
+ map1_id = map1.getId();
+ str1_id = str1.getId();
+ str2_id = str2.getId();
+ int1_id = int1.getId();
+ int2_id = int2.getId();
+ }
+
+ @Test(dependsOnMethods = "createData")
+ public void testRevisionsCounts() {
+ assertEquals(Arrays.asList(1, 2, 3),
getAuditReader().getRevisions(TernaryMapEntity.class, map1_id));
+ assertEquals(Arrays.asList(1), getAuditReader().getRevisions(StrTestEntity.class,
str1_id));
+ assertEquals(Arrays.asList(1), getAuditReader().getRevisions(StrTestEntity.class,
str2_id));
+ assertEquals(Arrays.asList(1) ,getAuditReader().getRevisions(IntTestEntity.class,
int1_id));
+ assertEquals(Arrays.asList(1) ,getAuditReader().getRevisions(IntTestEntity.class,
int2_id));
+ }
+
+ @Test(dependsOnMethods = "createData")
+ public void testHistoryOfMap1() {
+ StrTestEntity str1 = getEntityManager().find(StrTestEntity.class, str1_id);
+ StrTestEntity str2 = getEntityManager().find(StrTestEntity.class, str2_id);
+ IntTestEntity int1 = getEntityManager().find(IntTestEntity.class, int1_id);
+ IntTestEntity int2 = getEntityManager().find(IntTestEntity.class, int2_id);
+
+ TernaryMapEntity rev1 = getAuditReader().find(TernaryMapEntity.class, map1_id,
1);
+ TernaryMapEntity rev2 = getAuditReader().find(TernaryMapEntity.class, map1_id,
2);
+ TernaryMapEntity rev3 = getAuditReader().find(TernaryMapEntity.class, map1_id,
3);
+
+ assertEquals(rev1.getMap(), TestTools.makeMap(int1, str1));
+ assertEquals(rev2.getMap(), TestTools.makeMap(int1, str1, int2, str2));
+ assertEquals(rev3.getMap(), TestTools.makeMap(int2, str1));
+ }
+}
\ No newline at end of file