/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.envers.test.integration.strategy; import java.sql.Types; import java.util.Arrays; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.Query; import org.hibernate.Session; import org.hibernate.envers.configuration.EnversSettings; import org.hibernate.envers.strategy.ValidityAuditStrategy; import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase; import org.hibernate.envers.test.Priority; import org.hibernate.envers.test.entities.manytomany.sametable.Child1Entity; import org.hibernate.envers.test.entities.manytomany.sametable.Child2Entity; import org.hibernate.envers.test.entities.manytomany.sametable.ParentEntity; import org.hibernate.envers.test.entities.reventity.CustomDateRevEntity; import org.hibernate.envers.test.tools.TestTools; import org.junit.Test; /** * Test which checks that the revision end timestamp is correctly set for * {@link ValidityAuditStrategy}. * * @author Erik-Berndt Scheper */ public class ValidityAuditStrategyRevEndTestCustomRevEnt extends BaseEnversJPAFunctionalTestCase { private final String revendTimestampColumName = "REVEND_TIMESTAMP"; private Integer p1_id; private Integer p2_id; private Integer c1_1_id; private Integer c1_2_id; private Integer c2_1_id; private Integer c2_2_id; private Map<Number, CustomDateRevEntity> revisions; @Override protected Class<?>[] getAnnotatedClasses() { return new Class[] { ParentEntity.class, Child1Entity.class, Child2Entity.class, CustomDateRevEntity.class }; } @Override protected void addConfigOptions(Map options) { super.addConfigOptions( options ); options.put( EnversSettings.AUDIT_STRATEGY, "org.hibernate.envers.strategy.ValidityAuditStrategy" ); options.put( EnversSettings.AUDIT_STRATEGY_VALIDITY_STORE_REVEND_TIMESTAMP, "true" ); options.put( EnversSettings.AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME, revendTimestampColumName ); } @Test @Priority(10) public void initData() { EntityManager em = getEntityManager(); // We need first to modify the columns in the middle (join table) to // allow null values. Hbm2ddl doesn't seem // to allow this. em.getTransaction().begin(); Session session = (Session) em.getDelegate(); session.createSQLQuery( "DROP TABLE children" ).executeUpdate(); session .createSQLQuery( "CREATE TABLE children ( parent_id " + getDialect().getTypeName( Types.INTEGER ) + ", child1_id " + getDialect().getTypeName( Types.INTEGER ) + getDialect().getNullColumnString() + ", child2_id " + getDialect().getTypeName( Types.INTEGER ) + getDialect().getNullColumnString() + " )" ) .executeUpdate(); session.createSQLQuery( "DROP TABLE children_AUD" ).executeUpdate(); session .createSQLQuery( "CREATE TABLE children_AUD ( REV " + getDialect().getTypeName( Types.INTEGER ) + " NOT NULL" + ", REVEND " + getDialect().getTypeName( Types.INTEGER ) + ", " + revendTimestampColumName + " " + getDialect().getTypeName( Types.TIMESTAMP ) + ", REVTYPE " + getDialect().getTypeName( Types.TINYINT ) + ", parent_id " + getDialect().getTypeName( Types.INTEGER ) + ", child1_id " + getDialect().getTypeName( Types.INTEGER ) + getDialect().getNullColumnString() + ", child2_id " + getDialect().getTypeName( Types.INTEGER ) + getDialect().getNullColumnString() + " )" ) .executeUpdate(); em.getTransaction().commit(); em.clear(); ParentEntity p1 = new ParentEntity( "parent_1" ); ParentEntity p2 = new ParentEntity( "parent_2" ); Child1Entity c1_1 = new Child1Entity( "child1_1" ); Child1Entity c1_2 = new Child1Entity( "child1_2" ); Child2Entity c2_1 = new Child2Entity( "child2_1" ); Child2Entity c2_2 = new Child2Entity( "child2_2" ); // Revision 1 em.getTransaction().begin(); em.persist( p1 ); em.persist( p2 ); em.persist( c1_1 ); em.persist( c1_2 ); em.persist( c2_1 ); em.persist( c2_2 ); em.getTransaction().commit(); em.clear(); // Revision 2 - (p1: c1_1, p2: c2_1) em.getTransaction().begin(); p1 = em.find( ParentEntity.class, p1.getId() ); p2 = em.find( ParentEntity.class, p2.getId() ); c1_1 = em.find( Child1Entity.class, c1_1.getId() ); c2_1 = em.find( Child2Entity.class, c2_1.getId() ); p1.getChildren1().add( c1_1 ); p2.getChildren2().add( c2_1 ); em.getTransaction().commit(); em.clear(); // Revision 3 - (p1: c1_1, c1_2, c2_2, p2: c1_1, c2_1) em.getTransaction().begin(); p1 = em.find( ParentEntity.class, p1.getId() ); p2 = em.find( ParentEntity.class, p2.getId() ); c1_1 = em.find( Child1Entity.class, c1_1.getId() ); c1_2 = em.find( Child1Entity.class, c1_2.getId() ); c2_2 = em.find( Child2Entity.class, c2_2.getId() ); p1.getChildren1().add( c1_2 ); p1.getChildren2().add( c2_2 ); p2.getChildren1().add( c1_1 ); em.getTransaction().commit(); em.clear(); // Revision 4 - (p1: c1_2, c2_2, p2: c1_1, c2_1, c2_2) em.getTransaction().begin(); p1 = em.find( ParentEntity.class, p1.getId() ); p2 = em.find( ParentEntity.class, p2.getId() ); c1_1 = em.find( Child1Entity.class, c1_1.getId() ); c2_2 = em.find( Child2Entity.class, c2_2.getId() ); p1.getChildren1().remove( c1_1 ); p2.getChildren2().add( c2_2 ); em.getTransaction().commit(); em.clear(); // Revision 5 - (p1: c2_2, p2: c1_1, c2_1) em.getTransaction().begin(); p1 = em.find( ParentEntity.class, p1.getId() ); p2 = em.find( ParentEntity.class, p2.getId() ); c1_2 = em.find( Child1Entity.class, c1_2.getId() ); c2_2 = em.find( Child2Entity.class, c2_2.getId() ); c2_2.getParents().remove( p2 ); c1_2.getParents().remove( p1 ); em.getTransaction().commit(); em.clear(); // p1_id = p1.getId(); p2_id = p2.getId(); c1_1_id = c1_1.getId(); c1_2_id = c1_2.getId(); c2_1_id = c2_1.getId(); c2_2_id = c2_2.getId(); Set<Number> revisionNumbers = new HashSet<Number>(); revisionNumbers.addAll( Arrays.asList( 1, 2, 3, 4, 5 ) ); revisions = getAuditReader().findRevisions( CustomDateRevEntity.class, revisionNumbers ); assert revisions.size() == 5; } @Test public void testRevisionsCounts() { assert Arrays.asList( 1, 2, 3, 4 ).equals( getAuditReader().getRevisions( ParentEntity.class, p1_id ) ); assert Arrays.asList( 1, 2, 3, 4 ).equals( getAuditReader().getRevisions( ParentEntity.class, p2_id ) ); assert Arrays.asList( 1 ).equals( getAuditReader().getRevisions( Child1Entity.class, c1_1_id ) ); assert Arrays.asList( 1, 5 ).equals( getAuditReader().getRevisions( Child1Entity.class, c1_2_id ) ); assert Arrays.asList( 1 ).equals( getAuditReader().getRevisions( Child2Entity.class, c2_1_id ) ); assert Arrays.asList( 1, 5 ).equals( getAuditReader().getRevisions( Child2Entity.class, c2_2_id ) ); } @Test public void testAllRevEndTimeStamps() { List<Map<String, Object>> p1RevList = getRevisions( ParentEntity.class, p1_id ); List<Map<String, Object>> p2RevList = getRevisions( ParentEntity.class, p2_id ); List<Map<String, Object>> c1_1_List = getRevisions( Child1Entity.class, c1_1_id ); List<Map<String, Object>> c1_2_List = getRevisions( Child1Entity.class, c1_2_id ); List<Map<String, Object>> c2_1_List = getRevisions( Child2Entity.class, c2_1_id ); List<Map<String, Object>> c2_2_List = getRevisions( Child2Entity.class, c2_2_id ); verifyRevEndTimeStamps( "ParentEntity: " + p1_id, p1RevList ); verifyRevEndTimeStamps( "ParentEntity: " + p2_id, p2RevList ); verifyRevEndTimeStamps( "Child1Entity: " + c1_1_id, c1_1_List ); verifyRevEndTimeStamps( "Child1Entity: " + c1_2_id, c1_2_List ); verifyRevEndTimeStamps( "Child2Entity: " + c2_1_id, c2_1_List ); verifyRevEndTimeStamps( "Child2Entity: " + c2_2_id, c2_2_List ); } @Test public void testHistoryOfParent1() { Child1Entity c1_1 = getEntityManager() .find( Child1Entity.class, c1_1_id ); Child1Entity c1_2 = getEntityManager() .find( Child1Entity.class, c1_2_id ); Child2Entity c2_2 = getEntityManager() .find( Child2Entity.class, c2_2_id ); ParentEntity rev1 = getAuditReader().find( ParentEntity.class, p1_id, 1 ); ParentEntity rev2 = getAuditReader().find( ParentEntity.class, p1_id, 2 ); ParentEntity rev3 = getAuditReader().find( ParentEntity.class, p1_id, 3 ); ParentEntity rev4 = getAuditReader().find( ParentEntity.class, p1_id, 4 ); ParentEntity rev5 = getAuditReader().find( ParentEntity.class, p1_id, 5 ); assert TestTools.checkCollection( rev1.getChildren1() ); assert TestTools.checkCollection( rev2.getChildren1(), c1_1 ); assert TestTools.checkCollection( rev3.getChildren1(), c1_1, c1_2 ); assert TestTools.checkCollection( rev4.getChildren1(), c1_2 ); assert TestTools.checkCollection( rev5.getChildren1() ); assert TestTools.checkCollection( rev1.getChildren2() ); assert TestTools.checkCollection( rev2.getChildren2() ); assert TestTools.checkCollection( rev3.getChildren2(), c2_2 ); assert TestTools.checkCollection( rev4.getChildren2(), c2_2 ); assert TestTools.checkCollection( rev5.getChildren2(), c2_2 ); } @Test public void testHistoryOfParent2() { Child1Entity c1_1 = getEntityManager() .find( Child1Entity.class, c1_1_id ); Child2Entity c2_1 = getEntityManager() .find( Child2Entity.class, c2_1_id ); Child2Entity c2_2 = getEntityManager() .find( Child2Entity.class, c2_2_id ); ParentEntity rev1 = getAuditReader().find( ParentEntity.class, p2_id, 1 ); ParentEntity rev2 = getAuditReader().find( ParentEntity.class, p2_id, 2 ); ParentEntity rev3 = getAuditReader().find( ParentEntity.class, p2_id, 3 ); ParentEntity rev4 = getAuditReader().find( ParentEntity.class, p2_id, 4 ); ParentEntity rev5 = getAuditReader().find( ParentEntity.class, p2_id, 5 ); assert TestTools.checkCollection( rev1.getChildren1() ); assert TestTools.checkCollection( rev2.getChildren1() ); assert TestTools.checkCollection( rev3.getChildren1(), c1_1 ); assert TestTools.checkCollection( rev4.getChildren1(), c1_1 ); assert TestTools.checkCollection( rev5.getChildren1(), c1_1 ); assert TestTools.checkCollection( rev1.getChildren2() ); assert TestTools.checkCollection( rev2.getChildren2(), c2_1 ); assert TestTools.checkCollection( rev3.getChildren2(), c2_1 ); assert TestTools.checkCollection( rev4.getChildren2(), c2_1, c2_2 ); assert TestTools.checkCollection( rev5.getChildren2(), c2_1 ); } @Test public void testHistoryOfChild1_1() { ParentEntity p1 = getEntityManager().find( ParentEntity.class, p1_id ); ParentEntity p2 = getEntityManager().find( ParentEntity.class, p2_id ); Child1Entity rev1 = getAuditReader().find( Child1Entity.class, c1_1_id, 1 ); Child1Entity rev2 = getAuditReader().find( Child1Entity.class, c1_1_id, 2 ); Child1Entity rev3 = getAuditReader().find( Child1Entity.class, c1_1_id, 3 ); Child1Entity rev4 = getAuditReader().find( Child1Entity.class, c1_1_id, 4 ); Child1Entity rev5 = getAuditReader().find( Child1Entity.class, c1_1_id, 5 ); assert TestTools.checkCollection( rev1.getParents() ); assert TestTools.checkCollection( rev2.getParents(), p1 ); assert TestTools.checkCollection( rev3.getParents(), p1, p2 ); assert TestTools.checkCollection( rev4.getParents(), p2 ); assert TestTools.checkCollection( rev5.getParents(), p2 ); } // TODO: this was disabled? @Test public void testHistoryOfChild1_2() { ParentEntity p1 = getEntityManager().find( ParentEntity.class, p1_id ); Child1Entity rev1 = getAuditReader().find( Child1Entity.class, c1_2_id, 1 ); Child1Entity rev2 = getAuditReader().find( Child1Entity.class, c1_2_id, 2 ); Child1Entity rev3 = getAuditReader().find( Child1Entity.class, c1_2_id, 3 ); Child1Entity rev4 = getAuditReader().find( Child1Entity.class, c1_2_id, 4 ); Child1Entity rev5 = getAuditReader().find( Child1Entity.class, c1_2_id, 5 ); assert TestTools.checkCollection( rev1.getParents() ); assert TestTools.checkCollection( rev2.getParents() ); assert TestTools.checkCollection( rev3.getParents(), p1 ); assert TestTools.checkCollection( rev4.getParents(), p1 ); assert TestTools.checkCollection( rev5.getParents() ); } @Test public void testHistoryOfChild2_1() { ParentEntity p2 = getEntityManager().find( ParentEntity.class, p2_id ); Child2Entity rev1 = getAuditReader().find( Child2Entity.class, c2_1_id, 1 ); Child2Entity rev2 = getAuditReader().find( Child2Entity.class, c2_1_id, 2 ); Child2Entity rev3 = getAuditReader().find( Child2Entity.class, c2_1_id, 3 ); Child2Entity rev4 = getAuditReader().find( Child2Entity.class, c2_1_id, 4 ); Child2Entity rev5 = getAuditReader().find( Child2Entity.class, c2_1_id, 5 ); assert TestTools.checkCollection( rev1.getParents() ); assert TestTools.checkCollection( rev2.getParents(), p2 ); assert TestTools.checkCollection( rev3.getParents(), p2 ); assert TestTools.checkCollection( rev4.getParents(), p2 ); assert TestTools.checkCollection( rev5.getParents(), p2 ); } @Test public void testHistoryOfChild2_2() { ParentEntity p1 = getEntityManager().find( ParentEntity.class, p1_id ); ParentEntity p2 = getEntityManager().find( ParentEntity.class, p2_id ); Child2Entity rev1 = getAuditReader().find( Child2Entity.class, c2_2_id, 1 ); Child2Entity rev2 = getAuditReader().find( Child2Entity.class, c2_2_id, 2 ); Child2Entity rev3 = getAuditReader().find( Child2Entity.class, c2_2_id, 3 ); Child2Entity rev4 = getAuditReader().find( Child2Entity.class, c2_2_id, 4 ); Child2Entity rev5 = getAuditReader().find( Child2Entity.class, c2_2_id, 5 ); assert TestTools.checkCollection( rev1.getParents() ); assert TestTools.checkCollection( rev2.getParents() ); assert TestTools.checkCollection( rev3.getParents(), p1 ); assert TestTools.checkCollection( rev4.getParents(), p1, p2 ); assert TestTools.checkCollection( rev5.getParents(), p1 ); } private List<Map<String, Object>> getRevisions( Class<?> originalEntityClazz, Integer originalEntityId) { // Build the query: // select auditEntity from // org.hibernate.envers.test.entities.manytomany.sametable.ParentEntity_AUD // auditEntity where auditEntity.originalId.id = :originalEntityId StringBuilder builder = new StringBuilder( "select auditEntity from " ); builder.append( originalEntityClazz.getName() ) .append( "_AUD auditEntity" ); builder.append( " where auditEntity.originalId.id = :originalEntityId" ); Query qry = getEntityManager().createQuery( builder.toString() ); qry.setParameter( "originalEntityId", originalEntityId ); @SuppressWarnings("unchecked") List<Map<String, Object>> resultList = qry.getResultList(); return resultList; } private void verifyRevEndTimeStamps( String debugInfo, List<Map<String, Object>> revisionEntities) { for ( Map<String, Object> revisionEntity : revisionEntities ) { Date revendTimestamp = (Date) revisionEntity .get( revendTimestampColumName ); CustomDateRevEntity revEnd = (CustomDateRevEntity) revisionEntity .get( "REVEND" ); if ( revendTimestamp == null ) { assert revEnd == null; } else { assert revendTimestamp.getTime() == revEnd.getDateTimestamp().getTime(); } } } }