Merge pull request #176 from lukasz-antoniak/HHH-6696
HHH-6696 - Allow specifying revision listener apart from @RevisionEntity annotation
This commit is contained in:
commit
550865e3d3
|
@ -407,6 +407,10 @@
|
||||||
You tell Envers your custom <interfacename>org.hibernate.envers.RevisionListener</interfacename>
|
You tell Envers your custom <interfacename>org.hibernate.envers.RevisionListener</interfacename>
|
||||||
implementation to use by specifying it on the
|
implementation to use by specifying it on the
|
||||||
<interfacename>@org.hibernate.envers.RevisionEntity</interfacename> annotation, using the
|
<interfacename>@org.hibernate.envers.RevisionEntity</interfacename> annotation, using the
|
||||||
|
<methodname>value</methodname> attribute. If your <interfacename>RevisionListener</interfacename>
|
||||||
|
class is inaccessible from <interfacename>@RevisionEntity</interfacename> (e.g. exists in a different
|
||||||
|
module), set <property>org.hibernate.envers.revision_listener</property> property to it's fully
|
||||||
|
qualified name. Class name defined by the configuration parameter overrides revision entity's
|
||||||
<methodname>value</methodname> attribute.
|
<methodname>value</methodname> attribute.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration;
|
package org.hibernate.envers.configuration;
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.envers.RevisionListener;
|
||||||
|
|
||||||
import static org.hibernate.envers.tools.Tools.getProperty;
|
import static org.hibernate.envers.tools.Tools.getProperty;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@ -49,6 +52,9 @@ public class GlobalConfiguration {
|
||||||
// Should Envers track (persist) entity names that have been changed during each revision.
|
// Should Envers track (persist) entity names that have been changed during each revision.
|
||||||
private boolean trackEntitiesChangedInRevisionEnabled;
|
private boolean trackEntitiesChangedInRevisionEnabled;
|
||||||
|
|
||||||
|
// Revision listener class name.
|
||||||
|
private final Class<? extends RevisionListener> revisionListenerClass;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Which operator to use in correlated subqueries (when we want a property to be equal to the result of
|
Which operator to use in correlated subqueries (when we want a property to be equal to the result of
|
||||||
a correlated subquery, for example: e.p <operator> (select max(e2.p) where e2.p2 = e.p2 ...).
|
a correlated subquery, for example: e.p <operator> (select max(e2.p) where e2.p2 = e.p2 ...).
|
||||||
|
@ -87,6 +93,17 @@ public class GlobalConfiguration {
|
||||||
"org.hibernate.envers.track_entities_changed_in_revision",
|
"org.hibernate.envers.track_entities_changed_in_revision",
|
||||||
"false");
|
"false");
|
||||||
trackEntitiesChangedInRevisionEnabled = Boolean.parseBoolean(trackEntitiesChangedInRevisionEnabledStr);
|
trackEntitiesChangedInRevisionEnabled = Boolean.parseBoolean(trackEntitiesChangedInRevisionEnabledStr);
|
||||||
|
|
||||||
|
String revisionListenerClassName = properties.getProperty("org.hibernate.envers.revision_listener", null);
|
||||||
|
if (revisionListenerClassName != null) {
|
||||||
|
try {
|
||||||
|
revisionListenerClass = (Class<? extends RevisionListener>) Thread.currentThread().getContextClassLoader().loadClass(revisionListenerClassName);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new MappingException("Revision listener class not found: " + revisionListenerClassName + ".", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
revisionListenerClass = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGenerateRevisionsForCollections() {
|
public boolean isGenerateRevisionsForCollections() {
|
||||||
|
@ -120,4 +137,8 @@ public class GlobalConfiguration {
|
||||||
public void setTrackEntitiesChangedInRevisionEnabled(boolean trackEntitiesChangedInRevisionEnabled) {
|
public void setTrackEntitiesChangedInRevisionEnabled(boolean trackEntitiesChangedInRevisionEnabled) {
|
||||||
this.trackEntitiesChangedInRevisionEnabled = trackEntitiesChangedInRevisionEnabled;
|
this.trackEntitiesChangedInRevisionEnabled = trackEntitiesChangedInRevisionEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<? extends RevisionListener> getRevisionListenerClass() {
|
||||||
|
return revisionListenerClass;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,8 +286,8 @@ public class RevisionInfoConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
revisionInfoEntityName = pc.getEntityName();
|
revisionInfoEntityName = pc.getEntityName();
|
||||||
|
|
||||||
revisionInfoClass = pc.getMappedClass();
|
revisionInfoClass = pc.getMappedClass();
|
||||||
|
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(revisionEntity.value());
|
||||||
revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType();
|
revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType();
|
||||||
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled() ||
|
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled() ||
|
||||||
DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass) ||
|
DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass) ||
|
||||||
|
@ -295,12 +295,12 @@ public class RevisionInfoConfiguration {
|
||||||
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
|
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
|
||||||
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
|
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
|
||||||
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName,
|
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName,
|
||||||
revisionInfoClass, revisionEntity.value(), revisionInfoTimestampData, isTimestampAsDate(),
|
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
|
||||||
modifiedEntityNamesData);
|
modifiedEntityNamesData);
|
||||||
globalCfg.setTrackEntitiesChangedInRevisionEnabled(true);
|
globalCfg.setTrackEntitiesChangedInRevisionEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
||||||
revisionEntity.value(), revisionInfoTimestampData, isTimestampAsDate());
|
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,16 +308,18 @@ public class RevisionInfoConfiguration {
|
||||||
// In case of a custom revision info generator, the mapping will be null.
|
// In case of a custom revision info generator, the mapping will be null.
|
||||||
Document revisionInfoXmlMapping = null;
|
Document revisionInfoXmlMapping = null;
|
||||||
|
|
||||||
|
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(RevisionListener.class);
|
||||||
|
|
||||||
if (revisionInfoGenerator == null) {
|
if (revisionInfoGenerator == null) {
|
||||||
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) {
|
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) {
|
||||||
revisionInfoClass = DefaultTrackingModifiedEntitiesRevisionEntity.class;
|
revisionInfoClass = DefaultTrackingModifiedEntitiesRevisionEntity.class;
|
||||||
revisionInfoEntityName = DefaultTrackingModifiedEntitiesRevisionEntity.class.getName();
|
revisionInfoEntityName = DefaultTrackingModifiedEntitiesRevisionEntity.class.getName();
|
||||||
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
||||||
RevisionListener.class, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData);
|
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData);
|
||||||
} else {
|
} else {
|
||||||
revisionInfoClass = DefaultRevisionEntity.class;
|
revisionInfoClass = DefaultRevisionEntity.class;
|
||||||
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
|
||||||
RevisionListener.class, revisionInfoTimestampData, isTimestampAsDate());
|
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
|
||||||
}
|
}
|
||||||
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
|
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
|
||||||
}
|
}
|
||||||
|
@ -337,6 +339,18 @@ public class RevisionInfoConfiguration {
|
||||||
String typename = revisionInfoTimestampType.getName();
|
String typename = revisionInfoTimestampType.getName();
|
||||||
return "date".equals(typename) || "time".equals(typename) || "timestamp".equals(typename);
|
return "date".equals(typename) || "time".equals(typename) || "timestamp".equals(typename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener}
|
||||||
|
* parameter has not been set.
|
||||||
|
* @return Revision listener.
|
||||||
|
*/
|
||||||
|
private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> defaultListener) {
|
||||||
|
if (globalCfg.getRevisionListenerClass() != null) {
|
||||||
|
return globalCfg.getRevisionListenerClass();
|
||||||
|
}
|
||||||
|
return defaultListener;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RevisionInfoConfigurationResult {
|
class RevisionInfoConfigurationResult {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.hibernate.envers.test.integration.reventity;
|
||||||
|
|
||||||
|
import org.hibernate.envers.RevisionListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class CountingRevisionListener implements RevisionListener {
|
||||||
|
public static int revisionCount = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void newRevision(Object revisionEntity) {
|
||||||
|
++revisionCount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package org.hibernate.envers.test.integration.reventity;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
import org.hibernate.envers.test.AbstractEntityTest;
|
||||||
|
import org.hibernate.envers.test.Priority;
|
||||||
|
import org.hibernate.envers.test.entities.StrTestEntity;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-6696")
|
||||||
|
public class GloballyConfiguredRevListenerTest extends AbstractEntityTest {
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
cfg.addAnnotatedClass(StrTestEntity.class);
|
||||||
|
cfg.setProperty("org.hibernate.envers.revision_listener", "org.hibernate.envers.test.integration.reventity.CountingRevisionListener");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Priority(10)
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
|
||||||
|
CountingRevisionListener.revisionCount = 0;
|
||||||
|
|
||||||
|
// Revision 1
|
||||||
|
em.getTransaction().begin();
|
||||||
|
StrTestEntity te = new StrTestEntity("data");
|
||||||
|
em.persist(te);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
Assert.assertEquals(1, CountingRevisionListener.revisionCount);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.hibernate.envers.test.integration.reventity;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-6696")
|
||||||
|
public class OverrideCustomRevListenerTest extends GloballyConfiguredRevListenerTest {
|
||||||
|
@Override
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
super.configure(cfg);
|
||||||
|
cfg.addAnnotatedClass(ListenerRevEntity.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.hibernate.envers.test.integration.reventity;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-6696")
|
||||||
|
public class OverrideDefaultRevListenerTest extends GloballyConfiguredRevListenerTest {
|
||||||
|
@Override
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
super.configure(cfg);
|
||||||
|
cfg.addAnnotatedClass(LongRevNumberRevEntity.class);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue