Author: adamw
Date: 2009-11-24 10:21:10 -0500 (Tue, 24 Nov 2009)
New Revision: 18032
Added:
core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/reventity/CustomDateRevEntity.java
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/CustomDate.java
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/configuration/RevisionInfoConfiguration.java
core/trunk/envers/src/main/java/org/hibernate/envers/reader/AuditReaderImpl.java
core/trunk/envers/src/main/java/org/hibernate/envers/revisioninfo/DefaultRevisionInfoGenerator.java
core/trunk/envers/src/main/java/org/hibernate/envers/revisioninfo/RevisionInfoQueryCreator.java
Log:
HHH-4540:
- applying patch from Nicolas Roug?\195?\169
- the revision timestamp can now be a j.u.Date or a j.s.Date, and be mapped to a Date in
the DB
- test
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/configuration/RevisionInfoConfiguration.java
===================================================================
---
core/trunk/envers/src/main/java/org/hibernate/envers/configuration/RevisionInfoConfiguration.java 2009-11-24
09:44:21 UTC (rev 18031)
+++
core/trunk/envers/src/main/java/org/hibernate/envers/configuration/RevisionInfoConfiguration.java 2009-11-24
15:21:10 UTC (rev 18032)
@@ -23,6 +23,7 @@
*/
package org.hibernate.envers.configuration;
+import java.util.Date;
import java.util.Iterator;
import org.dom4j.Document;
@@ -45,6 +46,8 @@
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.cfg.Configuration;
import org.hibernate.mapping.PersistentClass;
+import org.hibernate.type.LongType;
+import org.hibernate.type.Type;
/**
* @author Adam Warski (adam at warski dot org)
@@ -53,7 +56,7 @@
private String revisionInfoEntityName;
private PropertyData revisionInfoIdData;
private PropertyData revisionInfoTimestampData;
- private String revisionInfoTimestampType;
+ private Type revisionInfoTimestampType;
private String revisionPropType;
@@ -61,7 +64,7 @@
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
revisionInfoIdData = new PropertyData("id", "id",
"field", null);
revisionInfoTimestampData = new PropertyData("timestamp",
"timestamp", "field", null);
- revisionInfoTimestampType = "long";
+ revisionInfoTimestampType = new LongType();
revisionPropType = "integer";
}
@@ -79,7 +82,7 @@
MetadataTools.addColumn(idProperty, "REV", null, 0, 0, null);
Element timestampProperty = MetadataTools.addProperty(class_mapping,
revisionInfoTimestampData.getName(),
- revisionInfoTimestampType, true, false);
+ revisionInfoTimestampType.getName(), true, false);
MetadataTools.addColumn(timestampProperty, "REVTSTMP", null, 0, 0,
null);
return document;
@@ -131,12 +134,14 @@
XClass revisionTimestampClass = property.getType();
if (reflectionManager.equals(revisionTimestampClass, Long.class) ||
- reflectionManager.equals(revisionTimestampClass, Long.TYPE)) {
+ reflectionManager.equals(revisionTimestampClass, Long.TYPE) ||
+ reflectionManager.equals(revisionTimestampClass, Date.class) ||
+ reflectionManager.equals(revisionTimestampClass,
java.sql.Date.class)) {
revisionInfoTimestampData = new PropertyData(property.getName(),
property.getName(), accessType, null);
revisionTimestampFound.set();
} else {
throw new MappingException("The field annotated with
@RevisionTimestamp must be of type " +
- "long or Long");
+ "long, Long, java.util.Date or java.sql.Date");
}
}
}
@@ -203,8 +208,9 @@
revisionInfoEntityName = pc.getEntityName();
revisionInfoClass = pc.getMappedClass();
+ revisionInfoTimestampType =
pc.getProperty(revisionInfoTimestampData.getName()).getType();
revisionInfoGenerator = new
DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
- revisionEntity.value(), revisionInfoTimestampData);
+ revisionEntity.value(), revisionInfoTimestampData,
isTimestampAsDate());
}
}
@@ -214,17 +220,22 @@
if (revisionInfoGenerator == null) {
revisionInfoClass = DefaultRevisionEntity.class;
revisionInfoGenerator = new
DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
- RevisionListener.class, revisionInfoTimestampData);
+ RevisionListener.class, revisionInfoTimestampData,
isTimestampAsDate());
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
}
return new RevisionInfoConfigurationResult(
revisionInfoGenerator, revisionInfoXmlMapping,
new RevisionInfoQueryCreator(revisionInfoEntityName,
revisionInfoIdData.getName(),
- revisionInfoTimestampData.getName()),
+ revisionInfoTimestampData.getName(), isTimestampAsDate()),
generateRevisionInfoRelationMapping(),
new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData),
revisionInfoEntityName);
}
+
+ private boolean isTimestampAsDate() {
+ String typename = revisionInfoTimestampType.getName();
+ return "date".equals(typename) || "time".equals(typename) ||
"timestamp".equals(typename);
+ }
}
class RevisionInfoConfigurationResult {
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 2009-11-24
09:44:21 UTC (rev 18031)
+++
core/trunk/envers/src/main/java/org/hibernate/envers/reader/AuditReaderImpl.java 2009-11-24
15:21:10 UTC (rev 18032)
@@ -141,12 +141,13 @@
Query query = verCfg.getRevisionInfoQueryCreator().getRevisionDateQuery(session,
revision);
try {
- Long timestamp = (Long) query.uniqueResult();
- if (timestamp == null) {
+ Object timestampObject = query.uniqueResult();
+ if (timestampObject == null) {
throw new RevisionDoesNotExistException(revision);
}
- return new Date(timestamp);
+ // The timestamp object is either a date or a long
+ return timestampObject instanceof Date ? (Date) timestampObject : new
Date((Long) timestampObject);
} catch (NonUniqueResultException e) {
throw new AuditException(e);
}
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/revisioninfo/DefaultRevisionInfoGenerator.java
===================================================================
---
core/trunk/envers/src/main/java/org/hibernate/envers/revisioninfo/DefaultRevisionInfoGenerator.java 2009-11-24
09:44:21 UTC (rev 18031)
+++
core/trunk/envers/src/main/java/org/hibernate/envers/revisioninfo/DefaultRevisionInfoGenerator.java 2009-11-24
15:21:10 UTC (rev 18032)
@@ -23,12 +23,13 @@
*/
package org.hibernate.envers.revisioninfo;
+import java.util.Date;
+
+import org.hibernate.MappingException;
+import org.hibernate.Session;
import org.hibernate.envers.RevisionListener;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.tools.reflection.ReflectionTools;
-
-import org.hibernate.MappingException;
-import org.hibernate.Session;
import org.hibernate.property.Setter;
/**
@@ -38,13 +39,16 @@
private final String revisionInfoEntityName;
private final RevisionListener listener;
private final Setter revisionTimestampSetter;
+ private final boolean timestampAsDate;
private final Class<?> revisionInfoClass;
public DefaultRevisionInfoGenerator(String revisionInfoEntityName, Class<?>
revisionInfoClass,
Class<? extends RevisionListener>
listenerClass,
- PropertyData revisionInfoTimestampData) {
+ PropertyData revisionInfoTimestampData,
+ boolean timestampAsDate) {
this.revisionInfoEntityName = revisionInfoEntityName;
this.revisionInfoClass = revisionInfoClass;
+ this.timestampAsDate = timestampAsDate;
revisionTimestampSetter = ReflectionTools.getSetter(revisionInfoClass,
revisionInfoTimestampData);
@@ -75,7 +79,8 @@
throw new RuntimeException(e);
}
- revisionTimestampSetter.set(revisionInfo, System.currentTimeMillis(), null);
+ long timestamp = System.currentTimeMillis();
+ revisionTimestampSetter.set(revisionInfo, timestampAsDate ? new Date(timestamp) :
timestamp, null);
if (listener != null) {
listener.newRevision(revisionInfo);
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/revisioninfo/RevisionInfoQueryCreator.java
===================================================================
---
core/trunk/envers/src/main/java/org/hibernate/envers/revisioninfo/RevisionInfoQueryCreator.java 2009-11-24
09:44:21 UTC (rev 18031)
+++
core/trunk/envers/src/main/java/org/hibernate/envers/revisioninfo/RevisionInfoQueryCreator.java 2009-11-24
15:21:10 UTC (rev 18032)
@@ -35,9 +35,12 @@
private final String revisionDateQuery;
private final String revisionNumberForDateQuery;
private final String revisionQuery;
+ private final boolean timestampAsDate;
public RevisionInfoQueryCreator(String revisionInfoEntityName, String
revisionInfoIdName,
- String revisionInfoTimestampName) {
+ String revisionInfoTimestampName, boolean
timestampAsDate) {
+ this.timestampAsDate = timestampAsDate;
+
revisionDateQuery = new StringBuilder()
.append("select rev.").append(revisionInfoTimestampName)
.append(" from ").append(revisionInfoEntityName)
@@ -62,7 +65,7 @@
}
public Query getRevisionNumberForDateQuery(Session session, Date date) {
- return
session.createQuery(revisionNumberForDateQuery).setParameter("_revision_date",
date.getTime());
+ return
session.createQuery(revisionNumberForDateQuery).setParameter("_revision_date",
timestampAsDate ? date : date.getTime());
}
public Query getRevisionQuery(Session session, Number revision) {
Copied:
core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/reventity/CustomDateRevEntity.java
(from rev 18023,
core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/reventity/CustomRevEntity.java)
===================================================================
---
core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/reventity/CustomDateRevEntity.java
(rev 0)
+++
core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/reventity/CustomDateRevEntity.java 2009-11-24
15:21:10 UTC (rev 18032)
@@ -0,0 +1,86 @@
+/*
+ * 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.entities.reventity;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.hibernate.envers.RevisionEntity;
+import org.hibernate.envers.RevisionNumber;
+import org.hibernate.envers.RevisionTimestamp;
+
+import java.util.Date;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+@Entity
+@RevisionEntity
+public class CustomDateRevEntity {
+ @Id
+ @GeneratedValue
+ @RevisionNumber
+ private int customId;
+
+ @RevisionTimestamp
+ private Date dateTimestamp;
+
+ public int getCustomId() {
+ return customId;
+ }
+
+ public void setCustomId(int customId) {
+ this.customId = customId;
+ }
+
+ public Date getDateTimestamp() {
+ return dateTimestamp;
+ }
+
+ public void setDateTimestamp(Date dateTimestamp) {
+ this.dateTimestamp = dateTimestamp;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ CustomDateRevEntity that = (CustomDateRevEntity) o;
+
+ if (customId != that.customId) return false;
+ if (dateTimestamp != null ? !dateTimestamp.equals(that.dateTimestamp) :
that.dateTimestamp != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = customId;
+ result = 31 * result + (dateTimestamp != null ? dateTimestamp.hashCode() : 0);
+ return result;
+ }
+}
\ No newline at end of file
Copied:
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/CustomDate.java
(from rev 18023,
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/Custom.java)
===================================================================
---
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/CustomDate.java
(rev 0)
+++
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/reventity/CustomDate.java 2009-11-24
15:21:10 UTC (rev 18032)
@@ -0,0 +1,135 @@
+/*
+ * 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.reventity;
+
+import java.util.Arrays;
+import java.util.Date;
+import javax.persistence.EntityManager;
+
+import org.hibernate.envers.AuditReader;
+import org.hibernate.envers.exception.RevisionDoesNotExistException;
+import org.hibernate.envers.test.AbstractEntityTest;
+import org.hibernate.envers.test.entities.StrTestEntity;
+import org.hibernate.envers.test.entities.reventity.CustomDateRevEntity;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.hibernate.ejb.Ejb3Configuration;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class CustomDate extends AbstractEntityTest {
+ private Integer id;
+ private long timestamp1;
+ private long timestamp2;
+ private long timestamp3;
+
+ public void configure(Ejb3Configuration cfg) {
+ cfg.addAnnotatedClass(StrTestEntity.class);
+ cfg.addAnnotatedClass(CustomDateRevEntity.class);
+ }
+
+ @BeforeClass(dependsOnMethods = "init")
+ public void initData() throws InterruptedException {
+ timestamp1 = System.currentTimeMillis();
+
+ Thread.sleep(100);
+
+ // Revision 1
+ EntityManager em = getEntityManager();
+ em.getTransaction().begin();
+ StrTestEntity te = new StrTestEntity("x");
+ em.persist(te);
+ id = te.getId();
+ em.getTransaction().commit();
+
+ timestamp2 = System.currentTimeMillis();
+
+ Thread.sleep(100);
+
+ // Revision 2
+ em.getTransaction().begin();
+ te = em.find(StrTestEntity.class, id);
+ te.setStr("y");
+ em.getTransaction().commit();
+
+ timestamp3 = System.currentTimeMillis();
+ }
+
+ @Test(expectedExceptions = RevisionDoesNotExistException.class)
+ public void testTimestamps1() {
+ getAuditReader().getRevisionNumberForDate(new Date(timestamp1));
+ }
+
+ @Test
+ public void testTimestamps() {
+ assert getAuditReader().getRevisionNumberForDate(new Date(timestamp2)).intValue()
== 1;
+ assert getAuditReader().getRevisionNumberForDate(new Date(timestamp3)).intValue()
== 2;
+ }
+
+ @Test
+ public void testDatesForRevisions() {
+ AuditReader vr = getAuditReader();
+ assert vr.getRevisionNumberForDate(vr.getRevisionDate(1)).intValue() == 1;
+ assert vr.getRevisionNumberForDate(vr.getRevisionDate(2)).intValue() == 2;
+ }
+
+ @Test
+ public void testRevisionsForDates() {
+ AuditReader vr = getAuditReader();
+
+ assert vr.getRevisionDate(vr.getRevisionNumberForDate(new
Date(timestamp2))).getTime() <= timestamp2;
+ assert vr.getRevisionDate(vr.getRevisionNumberForDate(new
Date(timestamp2)).intValue()+1).getTime() > timestamp2;
+
+ assert vr.getRevisionDate(vr.getRevisionNumberForDate(new
Date(timestamp3))).getTime() <= timestamp3;
+ }
+
+ @Test
+ public void testFindRevision() {
+ AuditReader vr = getAuditReader();
+
+ long rev1Timestamp = vr.findRevision(CustomDateRevEntity.class,
1).getDateTimestamp().getTime();
+ assert rev1Timestamp > timestamp1;
+ assert rev1Timestamp <= timestamp2;
+
+ long rev2Timestamp = vr.findRevision(CustomDateRevEntity.class,
2).getDateTimestamp().getTime();
+ assert rev2Timestamp > timestamp2;
+ assert rev2Timestamp <= timestamp3;
+ }
+
+ @Test
+ public void testRevisionsCounts() {
+ assert Arrays.asList(1,
2).equals(getAuditReader().getRevisions(StrTestEntity.class, id));
+ }
+
+ @Test
+ public void testHistoryOfId1() {
+ StrTestEntity ver1 = new StrTestEntity("x", id);
+ StrTestEntity ver2 = new StrTestEntity("y", id);
+
+ assert getAuditReader().find(StrTestEntity.class, id, 1).equals(ver1);
+ assert getAuditReader().find(StrTestEntity.class, id, 2).equals(ver2);
+ }
+}
\ No newline at end of file