Merge pull request #108 from lukasz-antoniak/HHH-5580-v1.1

HHH-5580 - Persisting entity name instead of entity class when tracking which entities changed at a given revision
This commit is contained in:
Adam Warski 2011-06-13 01:52:57 -07:00
commit 671a6a38db
23 changed files with 320 additions and 312 deletions

View File

@ -252,12 +252,10 @@
</entry>
<entry>
Should entity types, that have been modified during each revision, be tracked. The default
implementation creates <literal>REVCHANGES</literal> table that stores fully qualified names
of Java classes modified in a specified revision. Single record encapsulates the revision
identifier (foreign key to <literal>REVINFO</literal> table) and a string value. This
feature shall be used when entity name can be clearly identified by Java class type. Otherwise
extend <interfacename>org.hibernate.envers.EntityTrackingRevisionListener</interfacename>
interface. For more information refer to <xref linkend="envers-tracking-modified-entities-revchanges"/>
implementation creates <literal>REVCHANGES</literal> table that stores entity names
of modified persistent objects. Single record encapsulates the revision identifier
(foreign key to <literal>REVINFO</literal> table) and a string value. For more
information refer to <xref linkend="envers-tracking-modified-entities-revchanges"/>
and <xref linkend="envers-tracking-modified-entities-queries"/>.
</entry>
</row>
@ -476,40 +474,38 @@ public class ExampleListener implements RevisionListener {
</example>
<section id="envers-tracking-modified-entities-revchanges">
<title>Tracking entity classes modified in revision</title>
<title>Tracking entity names modified during revisions</title>
<para>
By default entity types that have been changed in each revision are not being tracked. This implies the
necessity to query all tables storing audited data in order to retrieve changes made during
specified revision. Envers provides a simple mechanism that creates <literal>REVCHANGES</literal>
table which stores fully qualified names of Java classes modified in each revision.
Single record encapsulates the revision identifier (foreign key to <literal>REVINFO</literal> table)
and a string value. Note that this mechanism shall be used when entity name can be clearly identified
by Java class type. Otherwise extend <interfacename>org.hibernate.envers.EntityTrackingRevisionListener</interfacename>
interface (described further).
table which stores entity names of modified persistent objects. Single record encapsulates the revision
identifier (foreign key to <literal>REVINFO</literal> table) and a string value.
</para>
<para>
Tracking of modified entity types can be enabled in three different ways:
Tracking of modified entity names can be enabled in three different ways:
</para>
<orderedlist>
<listitem>
Set <property>org.hibernate.envers.track_entities_changed_in_revision</property> parameter to
<literal>true</literal>. In this case
<classname>org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity</classname> will
<classname>org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity</classname> will
be implicitly used as the revision log entity.
</listitem>
<listitem>
Create a custom revision entity that extends
<classname>org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity</classname> class.
<classname>org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity</classname> class.
<programlisting>
<![CDATA[@Entity
@RevisionEntity
public class ExtendedRevisionEntity extends DefaultTrackingModifiedTypesRevisionEntity {
public class ExtendedRevisionEntity
extends DefaultTrackingModifiedEntitiesRevisionEntity {
...
}]]></programlisting>
</listitem>
<listitem>
Mark an appropriate field of a custom revision entity with
<interfacename>@org.hibernate.envers.ModifiedEntityTypes</interfacename> annotation. The property is
<interfacename>@org.hibernate.envers.ModifiedEntityNames</interfacename> annotation. The property is
required to be of <literal><![CDATA[Set<String>]]></literal> type.
<programlisting>
<![CDATA[@Entity
@ -519,16 +515,16 @@ public class AnnotatedTrackingRevisionEntity {
@ElementCollection
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYTYPE")
@ModifiedEntityTypes
private Set<String> modifiedEntityTypes;
@Column(name = "ENTITYNAME")
@ModifiedEntityNames
private Set<String> modifiedEntityNames;
...
}]]></programlisting>
</listitem>
</orderedlist>
<para>
Users, that have chosen one of the approaches listed above, can retrieve all entities modified in
Users, that have chosen one of the approaches listed above, can retrieve all entities modified in a
specified revision by utilizing API described in <xref linkend="envers-tracking-modified-entities-queries"/>.
</para>
<para>
@ -545,11 +541,14 @@ public class AnnotatedTrackingRevisionEntity {
<programlisting>
<filename>CustomEntityTrackingRevisionListener.java</filename>
<![CDATA[
public class CustomEntityTrackingRevisionListener implements EntityTrackingRevisionListener {
public class CustomEntityTrackingRevisionListener
implements EntityTrackingRevisionListener {
@Override
public void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
public void entityChanged(Class entityClass, String entityName,
Serializable entityId, RevisionType revisionType,
Object revisionEntity) {
((CustomTrackingRevisionEntity)revisionEntity).addModifiedEntityType(entityClass.getName());
String type = entityClass.getName();
((CustomTrackingRevisionEntity)revisionEntity).addModifiedEntityType(type);
}
@Override
@ -571,7 +570,8 @@ public class CustomTrackingRevisionEntity {
private long customTimestamp;
@OneToMany(mappedBy="revision", cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private Set<ModifiedEntityTypeEntity> modifiedEntityTypes = new HashSet<ModifiedEntityTypeEntity>();
private Set<ModifiedEntityTypeEntity> modifiedEntityTypes =
new HashSet<ModifiedEntityTypeEntity>();
public void addModifiedEntityType(String entityClassName) {
modifiedEntityTypes.add(new ModifiedEntityTypeEntity(this, entityClassName));
@ -797,9 +797,9 @@ query.add(AuditEntity.relatedId("address").eq(relatedEntityId));]]></programlist
<section id="envers-tracking-modified-entities-queries">
<title>Querying for entities modified in a given revision</title>
<para>
The basic query allows retrieving entity types changed in a specified revision:
The basic query allows retrieving entity names and corresponding Java classes changed in a specified revision:
</para>
<programlisting><![CDATA[Set<Class> modifiedEntityTypes = getAuditReader()
<programlisting><![CDATA[Set<Pair<String, Class>> modifiedEntityTypes = getAuditReader()
.findEntityTypesChangedInRevision(revisionNumber);]]></programlisting>
<para>
Other queries (accessible from <interfacename>org.hibernate.envers.AuditReader</interfacename>):
@ -826,7 +826,7 @@ query.add(AuditEntity.relatedId("address").eq(relatedEntityId));]]></programlist
</orderedlist>
<para>
Note that methods described above can be legally used only when default mechanism of
tracking changed entity types is enabled (see <xref linkend="envers-tracking-modified-entities-revchanges"/>).
tracking changed entity names is enabled (see <xref linkend="envers-tracking-modified-entities-revchanges"/>).
</para>
</section>

View File

@ -28,6 +28,7 @@ import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.exception.NotAuditedException;
import org.hibernate.envers.exception.RevisionDoesNotExistException;
import org.hibernate.envers.query.AuditQueryCreator;
import org.hibernate.envers.tools.Pair;
import java.util.Date;
import java.util.List;
@ -222,9 +223,9 @@ public interface AuditReader {
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
* parameter is set to <code>true</code>.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity})
* extends {@link DefaultTrackingModifiedTypesRevisionEntity} base class.</li>
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* marked with {@link ModifiedEntityTypes} interface.</li>
* marked with {@link ModifiedEntityNames} interface.</li>
* </ul>
*/
List<Object> findEntitiesChangedInRevision(Number revision)
@ -237,15 +238,15 @@ public interface AuditReader {
* @param revisionType Type of modification.
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type.
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
* @throws AuditException If none of the following conditions is satisfied:
* <ul>
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
* parameter is set to <code>true</code>.</li>
* <li>{@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity})
* extends {@link DefaultTrackingModifiedTypesRevisionEntity} base class.</li>
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* marked with {@link ModifiedEntityTypes} interface.</li>
* marked with {@link ModifiedEntityNames} interface.</li>
* </ul>
*/
List<Object> findEntitiesChangedInRevision(Number revision, RevisionType revisionType)
@ -261,36 +262,36 @@ public interface AuditReader {
* @param revision Revision number.
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal).
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
* @throws AuditException If none of the following conditions is satisfied:
* <ul>
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
* parameter is set to <code>true</code>.</li>
* <li>{@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity})
* extends {@link DefaultTrackingModifiedTypesRevisionEntity} base class.</li>
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* marked with {@link ModifiedEntityTypes} interface.</li>
* marked with {@link ModifiedEntityNames} interface.</li>
* </ul>
*/
Map<RevisionType, List<Object>> findEntitiesChangedInRevisionGroupByRevisionType(Number revision)
throws IllegalStateException, IllegalArgumentException, AuditException;
/**
* Returns set of entity classes modified in a given revision.
* Returns set of entity names and corresponding Java classes modified in a given revision.
* @param revision Revision number.
* @return Set of classes modified in a given revision.
* @return Set of entity names and corresponding Java classes modified in a given revision.
* @throws IllegalStateException If the associated entity manager is closed.
* @throws IllegalArgumentException If a revision number is <code>null</code>, less or equal to 0.
* @throws IllegalArgumentException If a revision number is {@code null}, less or equal to 0.
* @throws AuditException If none of the following conditions is satisfied:
* <ul>
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
* parameter is set to <code>true</code>.</li>
* <li>{@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity})
* extends {@link DefaultTrackingModifiedTypesRevisionEntity} base class.</li>
* extends {@link DefaultTrackingModifiedEntitiesRevisionEntity} base class.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* marked with {@link ModifiedEntityTypes} interface.</li>
* marked with {@link ModifiedEntityNames} interface.</li>
* </ul>
*/
Set<Class> findEntityTypesChangedInRevision(Number revision)
Set<Pair<String, Class>> findEntityTypesChangedInRevision(Number revision)
throws IllegalStateException, IllegalArgumentException, AuditException;
}

View File

@ -0,0 +1,55 @@
package org.hibernate.envers;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
/**
* Extension of standard {@link DefaultRevisionEntity} that allows tracking entity names changed in each revision.
* This revision entity is implicitly used when {@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity {
@ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME")
@Fetch(FetchMode.JOIN)
@ModifiedEntityNames
private Set<String> modifiedEntityNames = new HashSet<String>();
public Set<String> getModifiedEntityNames() {
return modifiedEntityNames;
}
public void setModifiedEntityNames(Set<String> modifiedEntityNames) {
this.modifiedEntityNames = modifiedEntityNames;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultTrackingModifiedEntitiesRevisionEntity)) return false;
if (!super.equals(o)) return false;
DefaultTrackingModifiedEntitiesRevisionEntity that = (DefaultTrackingModifiedEntitiesRevisionEntity) o;
if (modifiedEntityNames != null ? !modifiedEntityNames.equals(that.modifiedEntityNames)
: that.modifiedEntityNames != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (modifiedEntityNames != null ? modifiedEntityNames.hashCode() : 0);
return result;
}
public String toString() {
return "DefaultTrackingModifiedEntitiesRevisionEntity(" + super.toString() + ", modifiedEntityNames = " + modifiedEntityNames + ")";
}
}

View File

@ -1,55 +0,0 @@
package org.hibernate.envers;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
/**
* Extension of {@link DefaultRevisionEntity} that allows tracking entity types changed in each revision. This revision
* entity is implicitly used when <code>org.hibernate.envers.track_entities_changed_in_revision</code> parameter
* is set to <code>true</code>.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
public class DefaultTrackingModifiedTypesRevisionEntity extends DefaultRevisionEntity {
@ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYTYPE")
@Fetch(FetchMode.JOIN)
@ModifiedEntityTypes
private Set<String> modifiedEntityTypes = new HashSet<String>();
public Set<String> getModifiedEntityTypes() {
return modifiedEntityTypes;
}
public void setModifiedEntityTypes(Set<String> modifiedEntityTypes) {
this.modifiedEntityTypes = modifiedEntityTypes;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultTrackingModifiedTypesRevisionEntity)) return false;
if (!super.equals(o)) return false;
DefaultTrackingModifiedTypesRevisionEntity that = (DefaultTrackingModifiedTypesRevisionEntity) o;
if (modifiedEntityTypes != null ? !modifiedEntityTypes.equals(that.modifiedEntityTypes)
: that.modifiedEntityTypes != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (modifiedEntityTypes != null ? modifiedEntityTypes.hashCode() : 0);
return result;
}
public String toString() {
return "DefaultTrackingModifiedTypesRevisionEntity(" + super.toString() + ", modifiedEntityTypes = " + modifiedEntityTypes + ")";
}
}

View File

@ -6,11 +6,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks a property which holds entity class names that have been modified during each revision.
* Marks a property which holds entity names that have been modified during each revision.
* This annotation expects field of <code>{@literal Set<String>}</code> type.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface ModifiedEntityTypes {
public @interface ModifiedEntityNames {
}

View File

@ -30,7 +30,7 @@ import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.cfg.Configuration;
import org.hibernate.envers.entities.EntitiesConfigurations;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.revisioninfo.ModifiedEntityTypesReader;
import org.hibernate.envers.revisioninfo.ModifiedEntityNamesReader;
import org.hibernate.envers.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator;
import org.hibernate.envers.strategy.AuditStrategy;
@ -51,7 +51,7 @@ public class AuditConfiguration {
private final EntitiesConfigurations entCfg;
private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final RevisionInfoNumberReader revisionInfoNumberReader;
private final ModifiedEntityTypesReader modifiedEntityTypesReader;
private final ModifiedEntityNamesReader modifiedEntityNamesReader;
public AuditEntitiesConfiguration getAuditEntCfg() {
return auditEntCfg;
@ -77,8 +77,8 @@ public class AuditConfiguration {
return revisionInfoNumberReader;
}
public ModifiedEntityTypesReader getModifiedEntityTypesReader() {
return modifiedEntityTypesReader;
public ModifiedEntityNamesReader getModifiedEntityNamesReader() {
return modifiedEntityNamesReader;
}
public AuditStrategy getAuditStrategy() {
@ -96,7 +96,7 @@ public class AuditConfiguration {
auditProcessManager = new AuditProcessManager(revInfoCfgResult.getRevisionInfoGenerator());
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
modifiedEntityTypesReader = revInfoCfgResult.getModifiedEntityTypesReader();
modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader();
auditStrategy = initializeAuditStrategy(revInfoCfgResult.getRevisionInfoClass(),
revInfoCfgResult.getRevisionInfoTimestampData());
entCfg = new EntitiesConfigurator().configure(cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy,

View File

@ -46,7 +46,7 @@ public class GlobalConfiguration {
// The default name of the catalog of the audit tables.
private final String defaultCatalogName;
// Should Envers track (persist) entity types that have been changed during each revision.
// Should Envers track (persist) entity names that have been changed during each revision.
private boolean trackEntitiesChangedInRevisionEnabled;
/*

View File

@ -36,8 +36,8 @@ import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cfg.Configuration;
import org.hibernate.envers.Audited;
import org.hibernate.envers.DefaultRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity;
import org.hibernate.envers.ModifiedEntityTypes;
import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.RevisionEntity;
import org.hibernate.envers.RevisionListener;
import org.hibernate.envers.RevisionNumber;
@ -46,8 +46,8 @@ import org.hibernate.envers.configuration.metadata.AuditTableData;
import org.hibernate.envers.configuration.metadata.MetadataTools;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.revisioninfo.DefaultRevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.DefaultTrackingModifiedTypesRevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.ModifiedEntityTypesReader;
import org.hibernate.envers.revisioninfo.DefaultTrackingModifiedEntitiesRevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.ModifiedEntityNamesReader;
import org.hibernate.envers.revisioninfo.RevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator;
@ -64,7 +64,7 @@ public class RevisionInfoConfiguration {
private String revisionInfoEntityName;
private PropertyData revisionInfoIdData;
private PropertyData revisionInfoTimestampData;
private PropertyData modifiedEntityTypesData;
private PropertyData modifiedEntityNamesData;
private Type revisionInfoTimestampType;
private GlobalConfiguration globalCfg;
@ -76,7 +76,7 @@ public class RevisionInfoConfiguration {
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
revisionInfoIdData = new PropertyData("id", "id", "field", null);
revisionInfoTimestampData = new PropertyData("timestamp", "timestamp", "field", null);
modifiedEntityTypesData = new PropertyData("modifiedEntityTypes", "modifiedEntityTypes", "field", null);
modifiedEntityNamesData = new PropertyData("modifiedEntityNames", "modifiedEntityNames", "field", null);
revisionInfoTimestampType = new LongType();
revisionPropType = "integer";
@ -99,7 +99,9 @@ public class RevisionInfoConfiguration {
MetadataTools.addColumn(timestampProperty, "REVTSTMP", null, 0, 0, null, null, null, false);
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) {
generateEntityTypesTrackingTableMapping(class_mapping, "modifiedEntityTypes", "REVCHANGES", "REV", "ENTITYTYPE", "string");
generateEntityNamesTrackingTableMapping(class_mapping, "modifiedEntityNames",
globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName(),
"REVCHANGES", "REV", "ENTITYNAME", "string");
}
return document;
@ -108,20 +110,24 @@ public class RevisionInfoConfiguration {
/**
* Generates mapping that represents a set of primitive types.<br />
* <code>
* &lt;set name="propertyName" table="joinTableName" cascade="persist, delete" lazy="false" fetch="join"&gt;<br />
* &lt;set name="propertyName" table="joinTableName" schema="joinTableSchema" catalog="joinTableCatalog"
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cascade="persist, delete" lazy="false" fetch="join"&gt;<br />
* &nbsp;&nbsp;&nbsp;&lt;key column="joinTablePrimaryKeyColumnName" /&gt;<br />
* &nbsp;&nbsp;&nbsp;&lt;element type="joinTableValueColumnType"&gt;<br />
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;column name="joinTableValueColumnName" /&gt;<br />
* &nbsp;&nbsp;&nbsp;&lt;/element&gt;<br />
* &lt;/set&gt;
* </code>
*/
private void generateEntityTypesTrackingTableMapping(Element class_mapping, String propertyName,
String joinTableName, String joinTablePrimaryKeyColumnName,
String joinTableValueColumnName, String joinTableValueColumnType) {
*/
private void generateEntityNamesTrackingTableMapping(Element class_mapping, String propertyName,
String joinTableSchema, String joinTableCatalog, String joinTableName,
String joinTablePrimaryKeyColumnName, String joinTableValueColumnName,
String joinTableValueColumnType) {
Element set = class_mapping.addElement("set");
set.addAttribute("name", propertyName);
set.addAttribute("table", joinTableName);
set.addAttribute("schema", joinTableSchema);
set.addAttribute("catalog", joinTableCatalog);
set.addAttribute("cascade", "persist, delete");
set.addAttribute("fetch", "join");
set.addAttribute("lazy", "false");
@ -149,11 +155,11 @@ public class RevisionInfoConfiguration {
private void searchForRevisionInfoCfgInProperties(XClass clazz, ReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
MutableBoolean modifiedEntityTypesFound, String accessType) {
MutableBoolean modifiedEntityNamesFound, String accessType) {
for (XProperty property : clazz.getDeclaredProperties(accessType)) {
RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class);
RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class);
ModifiedEntityTypes modifiedEntityTypes = property.getAnnotation(ModifiedEntityTypes.class);
ModifiedEntityNames modifiedEntityNames = property.getAnnotation(ModifiedEntityNames.class);
if (revisionNumber != null) {
if (revisionNumberFound.isSet()) {
@ -204,17 +210,17 @@ public class RevisionInfoConfiguration {
}
}
if (modifiedEntityTypes != null) {
if (modifiedEntityTypesFound.isSet()) {
throw new MappingException("Only one property may be annotated with @ModifiedEntityTypes!");
if (modifiedEntityNames != null) {
if (modifiedEntityNamesFound.isSet()) {
throw new MappingException("Only one property may be annotated with @ModifiedEntityNames!");
}
XClass modifiedEntityTypesClass = property.getType();
if (reflectionManager.equals(modifiedEntityTypesClass, Set.class) &&
XClass modifiedEntityNamesClass = property.getType();
if (reflectionManager.equals(modifiedEntityNamesClass, Set.class) &&
reflectionManager.equals(property.getElementClass(), String.class)) {
modifiedEntityTypesData = new PropertyData(property.getName(), property.getName(), accessType, null);
modifiedEntityTypesFound.set();
modifiedEntityNamesData = new PropertyData(property.getName(), property.getName(), accessType, null);
modifiedEntityNamesFound.set();
} else {
throw new MappingException("The field annotated with @ModifiedEntityTypes must be of Set<String> type.");
throw new MappingException("The field annotated with @ModifiedEntityNames must be of Set<String> type.");
}
}
}
@ -222,16 +228,16 @@ public class RevisionInfoConfiguration {
private void searchForRevisionInfoCfg(XClass clazz, ReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
MutableBoolean modifiedEntityTypesFound) {
MutableBoolean modifiedEntityNamesFound) {
XClass superclazz = clazz.getSuperclass();
if (!"java.lang.Object".equals(superclazz.getName())) {
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityTypesFound);
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
}
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityTypesFound, "field");
modifiedEntityNamesFound, "field");
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityTypesFound, "property");
modifiedEntityNamesFound, "property");
}
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
@ -265,9 +271,9 @@ public class RevisionInfoConfiguration {
MutableBoolean revisionNumberFound = new MutableBoolean();
MutableBoolean revisionTimestampFound = new MutableBoolean();
MutableBoolean modifiedEntityTypesFound = new MutableBoolean();
MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
searchForRevisionInfoCfg(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityTypesFound);
searchForRevisionInfoCfg(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
if (!revisionNumberFound.isSet()) {
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " +
@ -284,13 +290,13 @@ public class RevisionInfoConfiguration {
revisionInfoClass = pc.getMappedClass();
revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType();
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled() ||
DefaultTrackingModifiedTypesRevisionEntity.class.isAssignableFrom(revisionInfoClass) ||
modifiedEntityTypesFound.isSet()) {
DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass) ||
modifiedEntityNamesFound.isSet()) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedTypesRevisionEntity class, or @ModifiedEntityTypes annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedTypesRevisionInfoGenerator(revisionInfoEntityName,
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName,
revisionInfoClass, revisionEntity.value(), revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityTypesData);
modifiedEntityNamesData);
globalCfg.setTrackEntitiesChangedInRevisionEnabled(true);
} else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
@ -304,10 +310,10 @@ public class RevisionInfoConfiguration {
if (revisionInfoGenerator == null) {
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) {
revisionInfoClass = DefaultTrackingModifiedTypesRevisionEntity.class;
revisionInfoEntityName = DefaultTrackingModifiedTypesRevisionEntity.class.getName();
revisionInfoGenerator = new DefaultTrackingModifiedTypesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
RevisionListener.class, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityTypesData);
revisionInfoClass = DefaultTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoEntityName = DefaultTrackingModifiedEntitiesRevisionEntity.class.getName();
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
RevisionListener.class, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData);
} else {
revisionInfoClass = DefaultRevisionEntity.class;
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
@ -322,7 +328,7 @@ public class RevisionInfoConfiguration {
revisionInfoTimestampData.getName(), isTimestampAsDate()),
generateRevisionInfoRelationMapping(),
new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData),
globalCfg.isTrackEntitiesChangedInRevisionEnabled() ? new ModifiedEntityTypesReader(revisionInfoClass, modifiedEntityTypesData)
globalCfg.isTrackEntitiesChangedInRevisionEnabled() ? new ModifiedEntityNamesReader(revisionInfoClass, modifiedEntityNamesData)
: null,
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData);
}
@ -339,7 +345,7 @@ class RevisionInfoConfigurationResult {
private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final Element revisionInfoRelationMapping;
private final RevisionInfoNumberReader revisionInfoNumberReader;
private final ModifiedEntityTypesReader modifiedEntityTypesReader;
private final ModifiedEntityNamesReader modifiedEntityNamesReader;
private final String revisionInfoEntityName;
private final Class<?> revisionInfoClass;
private final PropertyData revisionInfoTimestampData;
@ -347,14 +353,14 @@ class RevisionInfoConfigurationResult {
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator,
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
ModifiedEntityTypesReader modifiedEntityTypesReader, String revisionInfoEntityName,
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
this.revisionInfoGenerator = revisionInfoGenerator;
this.revisionInfoXmlMapping = revisionInfoXmlMapping;
this.revisionInfoQueryCreator = revisionInfoQueryCreator;
this.revisionInfoRelationMapping = revisionInfoRelationMapping;
this.revisionInfoNumberReader = revisionInfoNumberReader;
this.modifiedEntityTypesReader = modifiedEntityTypesReader;
this.modifiedEntityNamesReader = modifiedEntityNamesReader;
this.revisionInfoEntityName = revisionInfoEntityName;
this.revisionInfoClass = revisionInfoClass;
this.revisionInfoTimestampData = revisionInfoTimestampData;
@ -392,7 +398,7 @@ class RevisionInfoConfigurationResult {
return revisionInfoTimestampData;
}
public ModifiedEntityTypesReader getModifiedEntityTypesReader() {
return modifiedEntityTypesReader;
public ModifiedEntityNamesReader getModifiedEntityNamesReader() {
return modifiedEntityNamesReader;
}
}

View File

@ -48,6 +48,8 @@ import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.query.AuditQueryCreator;
import org.hibernate.envers.query.criteria.RevisionTypeAuditExpression;
import org.hibernate.envers.synchronization.AuditProcess;
import org.hibernate.envers.tools.Pair;
import org.hibernate.envers.tools.Tools;
import org.hibernate.event.spi.EventSource;
import org.hibernate.proxy.HibernateProxy;
@ -248,10 +250,10 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"})
public List<Object> findEntitiesChangedInRevision(Number revision) throws IllegalStateException,
IllegalArgumentException, AuditException {
Set<Class> clazz = findEntityTypesChangedInRevision(revision);
Set<Pair<String, Class>> entityTypes = findEntityTypesChangedInRevision(revision);
List<Object> result = new ArrayList<Object>();
for (Class c : clazz) {
result.addAll(createQuery().forEntitiesModifiedAtRevision(c, revision).getResultList());
for (Pair<String, Class> type : entityTypes) {
result.addAll(createQuery().forEntitiesModifiedAtRevision(type.getSecond(), type.getFirst(), revision).getResultList());
}
return result;
}
@ -259,10 +261,10 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"})
public List<Object> findEntitiesChangedInRevision(Number revision, RevisionType revisionType)
throws IllegalStateException, IllegalArgumentException, AuditException {
Set<Class> clazz = findEntityTypesChangedInRevision(revision);
Set<Pair<String, Class>> entityTypes = findEntityTypesChangedInRevision(revision);
List<Object> result = new ArrayList<Object>();
for (Class c : clazz) {
result.addAll(createQuery().forEntitiesModifiedAtRevision(c, revision)
for (Pair<String, Class> type : entityTypes) {
result.addAll(createQuery().forEntitiesModifiedAtRevision(type.getSecond(), type.getFirst(), revision)
.add(new RevisionTypeAuditExpression(revisionType, "=")).getResultList());
}
return result;
@ -271,12 +273,12 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"})
public Map<RevisionType, List<Object>> findEntitiesChangedInRevisionGroupByRevisionType(Number revision)
throws IllegalStateException, IllegalArgumentException, AuditException {
Set<Class> clazz = findEntityTypesChangedInRevision(revision);
Set<Pair<String, Class>> entityTypes = findEntityTypesChangedInRevision(revision);
Map<RevisionType, List<Object>> result = new HashMap<RevisionType, List<Object>>();
for (RevisionType revisionType : RevisionType.values()) {
result.put(revisionType, new ArrayList());
for (Class c : clazz) {
List<Object> list = createQuery().forEntitiesModifiedAtRevision(c, revision)
result.put(revisionType, new ArrayList<Object>());
for (Pair<String, Class> type : entityTypes) {
List<Object> list = createQuery().forEntitiesModifiedAtRevision(type.getSecond(), type.getFirst(), revision)
.add(new RevisionTypeAuditExpression(revisionType, "=")).getResultList();
result.get(revisionType).addAll(list);
}
@ -285,14 +287,14 @@ public class AuditReaderImpl implements AuditReaderImplementor {
}
@SuppressWarnings({"unchecked"})
public Set<Class> findEntityTypesChangedInRevision(Number revision) throws IllegalStateException,
IllegalArgumentException, AuditException {
public Set<Pair<String, Class>> findEntityTypesChangedInRevision(Number revision) throws IllegalStateException,
IllegalArgumentException, AuditException {
checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision");
checkSession();
if (!verCfg.getGlobalCfg().isTrackEntitiesChangedInRevisionEnabled()) {
throw new AuditException("This query is designed for Envers default mechanism of tracking entities modified in a given revision."
+ " Extend DefaultTrackingModifiedTypesRevisionEntity, utilize @ModifiedEntityTypes annotation or set "
+ " Extend DefaultTrackingModifiedEntitiesRevisionEntity, utilize @ModifiedEntityNames annotation or set "
+ "'org.hibernate.envers.track_entities_changed_in_revision' parameter to true.");
}
Set<Number> revisions = new HashSet<Number>(1);
@ -300,8 +302,16 @@ public class AuditReaderImpl implements AuditReaderImplementor {
Criteria query = verCfg.getRevisionInfoQueryCreator().getRevisionsQuery(session, revisions);
Object revisionInfo = query.uniqueResult();
if (revisionInfo != null) {
// If revision exists
return verCfg.getModifiedEntityTypesReader().getModifiedEntityTypes(revisionInfo);
// If revision exists.
Set<String> entityNames = verCfg.getModifiedEntityNamesReader().getModifiedEntityNames(revisionInfo);
if (entityNames != null) {
// Generate result that contains entity names and corresponding Java classes.
Set<Pair<String, Class>> result = new HashSet<Pair<String, Class>>();
for (String entityName : entityNames) {
result.add(Pair.make(entityName, Tools.getEntityClass(sessionImplementor, session, entityName)));
}
return result;
}
}
return Collections.EMPTY_SET;
}

View File

@ -0,0 +1,47 @@
package org.hibernate.envers.revisioninfo;
import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.RevisionListener;
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.property.Getter;
import org.hibernate.property.Setter;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
* Automatically adds entity names, that have been changed during current revision, to revision entity.
* @see ModifiedEntityNames
* @see DefaultTrackingModifiedEntitiesRevisionEntity
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class DefaultTrackingModifiedEntitiesRevisionInfoGenerator extends DefaultRevisionInfoGenerator {
private final Setter modifiedEntityNamesSetter;
private final Getter modifiedEntityNamesGetter;
public DefaultTrackingModifiedEntitiesRevisionInfoGenerator(String revisionInfoEntityName, Class<?> revisionInfoClass,
Class<? extends RevisionListener> listenerClass,
PropertyData revisionInfoTimestampData, boolean timestampAsDate,
PropertyData modifiedEntityNamesData) {
super(revisionInfoEntityName, revisionInfoClass, listenerClass, revisionInfoTimestampData, timestampAsDate);
modifiedEntityNamesSetter = ReflectionTools.getSetter(revisionInfoClass, modifiedEntityNamesData);
modifiedEntityNamesGetter = ReflectionTools.getGetter(revisionInfoClass, modifiedEntityNamesData);
}
@Override
@SuppressWarnings({"unchecked"})
public void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity) {
super.entityChanged(entityClass, entityName, entityId, revisionType, revisionEntity);
Set<String> modifiedEntityNames = (Set<String>) modifiedEntityNamesGetter.get(revisionEntity);
if (modifiedEntityNames == null) {
modifiedEntityNames = new HashSet<String>();
modifiedEntityNamesSetter.set(revisionEntity, modifiedEntityNames, null);
}
modifiedEntityNames.add(entityName);
}
}

View File

@ -1,47 +0,0 @@
package org.hibernate.envers.revisioninfo;
import org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity;
import org.hibernate.envers.ModifiedEntityTypes;
import org.hibernate.envers.RevisionListener;
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.property.Getter;
import org.hibernate.property.Setter;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
* Automatically adds entity class names, that have been changed during current revision, to revision entity.
* @see ModifiedEntityTypes
* @see DefaultTrackingModifiedTypesRevisionEntity
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class DefaultTrackingModifiedTypesRevisionInfoGenerator extends DefaultRevisionInfoGenerator {
private final Setter modifiedEntityTypesSetter;
private final Getter modifiedEntityTypesGetter;
public DefaultTrackingModifiedTypesRevisionInfoGenerator(String revisionInfoEntityName, Class<?> revisionInfoClass,
Class<? extends RevisionListener> listenerClass,
PropertyData revisionInfoTimestampData, boolean timestampAsDate,
PropertyData modifiedEntityTypesData) {
super(revisionInfoEntityName, revisionInfoClass, listenerClass, revisionInfoTimestampData, timestampAsDate);
modifiedEntityTypesSetter = ReflectionTools.getSetter(revisionInfoClass, modifiedEntityTypesData);
modifiedEntityTypesGetter = ReflectionTools.getGetter(revisionInfoClass, modifiedEntityTypesData);
}
@Override
@SuppressWarnings({"unchecked"})
public void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity) {
super.entityChanged(entityClass, entityName, entityId, revisionType, revisionEntity);
Set<String> modifiedEntityTypes = (Set<String>) modifiedEntityTypesGetter.get(revisionEntity);
if (modifiedEntityTypes == null) {
modifiedEntityTypes = new HashSet<String>();
modifiedEntityTypesSetter.set(revisionEntity, modifiedEntityTypes, null);
}
modifiedEntityTypes.add(entityClass.getName());
}
}

View File

@ -0,0 +1,26 @@
package org.hibernate.envers.revisioninfo;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.property.Getter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Returns modified entity names from a persisted revision info entity.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class ModifiedEntityNamesReader {
private final Getter modifiedEntityNamesGetter;
public ModifiedEntityNamesReader(Class<?> revisionInfoClass, PropertyData modifiedEntityNamesData) {
modifiedEntityNamesGetter = ReflectionTools.getGetter(revisionInfoClass, modifiedEntityNamesData);
}
@SuppressWarnings({"unchecked"})
public Set<String> getModifiedEntityNames(Object revisionEntity) {
return (Set<String>) modifiedEntityNamesGetter.get(revisionEntity);
}
}

View File

@ -1,41 +0,0 @@
package org.hibernate.envers.revisioninfo;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.property.Getter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Returns modified entity types from a persisted revision info entity.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class ModifiedEntityTypesReader {
private final Getter modifiedEntityTypesGetter;
public ModifiedEntityTypesReader(Class<?> revisionInfoClass, PropertyData modifiedEntityTypesData) {
modifiedEntityTypesGetter = ReflectionTools.getGetter(revisionInfoClass, modifiedEntityTypesData);
}
@SuppressWarnings({"unchecked"})
public Set<Class> getModifiedEntityTypes(Object revisionEntity) {
// The default mechanism of tracking entity types that have been changed during each revision stores
// fully qualified Java class names.
Set<String> modifiedEntityClassNames = (Set<String>) modifiedEntityTypesGetter.get(revisionEntity);
if (modifiedEntityClassNames != null) {
Set<Class> result = new HashSet<Class>(modifiedEntityClassNames.size());
for (String entityClassName : modifiedEntityClassNames) {
try {
result.add(Thread.currentThread().getContextClassLoader().loadClass(entityClassName));
} catch (ClassNotFoundException e) {
// This shall never happen
throw new RuntimeException(e);
}
}
return result;
}
return Collections.EMPTY_SET;
}
}

View File

@ -6,7 +6,7 @@ import org.hibernate.envers.RevisionType;
import org.hibernate.envers.revisioninfo.RevisionInfoGenerator;
import org.hibernate.envers.synchronization.work.AuditWorkUnit;
import org.hibernate.envers.synchronization.work.PersistentCollectionChangeWorkUnit;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.envers.tools.Tools;
import java.io.Serializable;
@ -36,16 +36,8 @@ public class EntityChangeNotifier {
// Notify about a change in collection owner entity.
entityId = ((PersistentCollectionChangeWorkUnit.PersistentCollectionChangeWorkUnitId) entityId).getOwnerId();
}
Class entityClass = getEntityClass(session, vwu.getEntityName());
Class entityClass = Tools.getEntityClass(sessionImplementor, session, vwu.getEntityName());
revisionInfoGenerator.entityChanged(entityClass, vwu.getEntityName(), entityId, vwu.getRevisionType(),
currentRevisionData);
}
/**
* @return Java class mapped to specified entity name.
*/
private Class getEntityClass(Session session, String entityName) {
EntityPersister entityPersister = sessionImplementor.getFactory().getEntityPersister(entityName);
return entityPersister.getClassMetadata().getMappedClass(session.getEntityMode());
}
}

View File

@ -35,6 +35,7 @@ import javassist.util.proxy.ProxyFactory;
import org.hibernate.Session;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
/**
@ -178,4 +179,12 @@ public class Tools {
return value;
}
}
/**
* @return Java class mapped to specified entity name.
*/
public static Class getEntityClass(SessionImplementor sessionImplementor, Session session, String entityName) {
EntityPersister entityPersister = sessionImplementor.getFactory().getEntityPersister(entityName);
return entityPersister.getClassMetadata().getMappedClass(session.getEntityMode());
}
}

View File

@ -1,6 +1,6 @@
package org.hibernate.envers.test.entities.reventity.trackmodifiedentities;
import org.hibernate.envers.ModifiedEntityTypes;
import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.RevisionEntity;
import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp;
@ -9,7 +9,7 @@ import javax.persistence.*;
import java.util.Set;
/**
* Sample revision entity that uses {@link ModifiedEntityTypes} annotation.
* Sample revision entity that uses {@link ModifiedEntityNames} annotation.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@ -25,9 +25,9 @@ public class AnnotatedTrackingRevisionEntity {
@ElementCollection
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYTYPE")
@ModifiedEntityTypes
private Set<String> entityTypes;
@Column(name = "ENTITYNAME")
@ModifiedEntityNames
private Set<String> entityNames;
public int getCustomId() {
return customId;
@ -45,12 +45,12 @@ public class AnnotatedTrackingRevisionEntity {
this.customTimestamp = customTimestamp;
}
public Set<String> getEntityTypes() {
return entityTypes;
public Set<String> getEntityNames() {
return entityNames;
}
public void setEntityTypes(Set<String> entityTypes) {
this.entityTypes = entityTypes;
public void setEntityNames(Set<String> entityNames) {
this.entityNames = entityNames;
}
public boolean equals(Object o) {
@ -61,7 +61,7 @@ public class AnnotatedTrackingRevisionEntity {
if (customId != that.customId) return false;
if (customTimestamp != that.customTimestamp) return false;
if (entityTypes != null ? !entityTypes.equals(that.entityTypes) : that.entityTypes != null) return false;
if (entityNames != null ? !entityNames.equals(that.entityNames) : that.entityNames != null) return false;
return true;
}
@ -69,12 +69,12 @@ public class AnnotatedTrackingRevisionEntity {
public int hashCode() {
int result = customId;
result = 31 * result + (int) (customTimestamp ^ (customTimestamp >>> 32));
result = 31 * result + (entityTypes != null ? entityTypes.hashCode() : 0);
result = 31 * result + (entityNames != null ? entityNames.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "AnnotatedTrackingRevisionEntity(customId = " + customId + ", customTimestamp = " + customTimestamp + ", entityTypes=" + entityTypes + ")";
return "AnnotatedTrackingRevisionEntity(customId = " + customId + ", customTimestamp = " + customTimestamp + ", entityNames=" + entityNames + ")";
}
}

View File

@ -1,7 +1,6 @@
package org.hibernate.envers.test.entities.reventity.trackmodifiedentities;
import org.hibernate.envers.DefaultRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.RevisionEntity;
import javax.persistence.Entity;
@ -11,14 +10,14 @@ import javax.persistence.Entity;
*/
@Entity
@RevisionEntity(ExtendedRevisionListener.class)
public class ExtendedRevisionEntity extends DefaultTrackingModifiedTypesRevisionEntity {
private String commnent;
public class ExtendedRevisionEntity extends DefaultTrackingModifiedEntitiesRevisionEntity {
private String comment;
public String getCommnent() {
return commnent;
public String getComment() {
return comment;
}
public void setCommnent(String commnent) {
this.commnent = commnent;
public void setComment(String comment) {
this.comment = comment;
}
}

View File

@ -9,6 +9,6 @@ public class ExtendedRevisionListener implements RevisionListener {
public static final String COMMENT_VALUE = "Comment";
public void newRevision(Object revisionEntity) {
((ExtendedRevisionEntity)revisionEntity).setCommnent(COMMENT_VALUE);
((ExtendedRevisionEntity)revisionEntity).setComment(COMMENT_VALUE);
}
}

View File

@ -1,11 +1,11 @@
package org.hibernate.envers.test.integration.reventity.trackmodifiedentities;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.ModifiedEntityTypes;
import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.AnnotatedTrackingRevisionEntity;
/**
* Tests proper behavior of revision entity that utilizes {@link ModifiedEntityTypes} annotation.
* Tests proper behavior of revision entity that utilizes {@link ModifiedEntityNames} annotation.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class AnnotatedTrackingEntitiesTest extends DefaultTrackingEntitiesTest {

View File

@ -1,7 +1,6 @@
package org.hibernate.envers.test.integration.reventity.trackmodifiedentities;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.EntityTrackingRevisionListener;
import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.test.AbstractEntityTest;
@ -19,7 +18,7 @@ import javax.persistence.EntityManager;
/**
* Tests proper behavior of entity listener that implements {@link EntityTrackingRevisionListener}
* interface. {@link CustomTrackingRevisionListener} shall be notified whenever an entity instance has been
* added, modified or removed, so that changed entity type can be persisted.
* added, modified or removed, so that changed entity name can be persisted.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class CustomTrackingEntitiesTest extends AbstractEntityTest {
@ -69,8 +68,7 @@ public class CustomTrackingEntitiesTest extends AbstractEntityTest {
ModifiedEntityTypeEntity steDescriptor = new ModifiedEntityTypeEntity(StrTestEntity.class.getName());
ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName());
AuditReader vr = getAuditReader();
CustomTrackingRevisionEntity ctre = vr.findRevision(CustomTrackingRevisionEntity.class, 1);
CustomTrackingRevisionEntity ctre = getAuditReader().findRevision(CustomTrackingRevisionEntity.class, 1);
assert ctre.getModifiedEntityTypes() != null;
assert ctre.getModifiedEntityTypes().size() == 2;
@ -81,8 +79,7 @@ public class CustomTrackingEntitiesTest extends AbstractEntityTest {
public void testTrackModifiedEntities() {
ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName());
AuditReader vr = getAuditReader();
CustomTrackingRevisionEntity ctre = vr.findRevision(CustomTrackingRevisionEntity.class, 2);
CustomTrackingRevisionEntity ctre = getAuditReader().findRevision(CustomTrackingRevisionEntity.class, 2);
assert ctre.getModifiedEntityTypes() != null;
assert ctre.getModifiedEntityTypes().size() == 1;
@ -94,8 +91,7 @@ public class CustomTrackingEntitiesTest extends AbstractEntityTest {
ModifiedEntityTypeEntity steDescriptor = new ModifiedEntityTypeEntity(StrTestEntity.class.getName());
ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName());
AuditReader vr = getAuditReader();
CustomTrackingRevisionEntity ctre = vr.findRevision(CustomTrackingRevisionEntity.class, 3);
CustomTrackingRevisionEntity ctre = getAuditReader().findRevision(CustomTrackingRevisionEntity.class, 3);
assert ctre.getModifiedEntityTypes() != null;
assert ctre.getModifiedEntityTypes().size() == 2;

View File

@ -7,6 +7,7 @@ import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.envers.tools.Pair;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;
import org.junit.Test;
@ -17,7 +18,7 @@ import java.util.List;
import java.util.Map;
/**
* Tests proper behavior of tracking modified entity types when {@code org.hibernate.envers.track_entities_changed_in_revision}
* Tests proper behavior of tracking modified entity names when {@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to {@code true}.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@ -71,7 +72,7 @@ public class DefaultTrackingEntitiesTest extends AbstractEntityTest {
if ("REVCHANGES".equals(table.getName())) {
assert table.getColumnSpan() == 2;
assert table.getColumn(new Column("REV")) != null;
assert table.getColumn(new Column("ENTITYTYPE")) != null;
assert table.getColumn(new Column("ENTITYNAME")) != null;
return;
}
}
@ -163,8 +164,15 @@ public class DefaultTrackingEntitiesTest extends AbstractEntityTest {
@Test
public void testFindEntityTypesChangedInRevision() {
assert TestTools.makeSet(StrTestEntity.class, StrIntTestEntity.class).equals(getAuditReader().findEntityTypesChangedInRevision(1));
assert TestTools.makeSet(StrIntTestEntity.class).equals(getAuditReader().findEntityTypesChangedInRevision(2));
assert TestTools.makeSet(StrTestEntity.class, StrIntTestEntity.class).equals(getAuditReader().findEntityTypesChangedInRevision(3));
assert TestTools.makeSet(Pair.make(StrTestEntity.class.getName(), StrTestEntity.class),
Pair.make(StrIntTestEntity.class.getName(), StrIntTestEntity.class))
.equals(getAuditReader().findEntityTypesChangedInRevision(1));
assert TestTools.makeSet(Pair.make(StrIntTestEntity.class.getName(), StrIntTestEntity.class))
.equals(getAuditReader().findEntityTypesChangedInRevision(2));
assert TestTools.makeSet(Pair.make(StrTestEntity.class.getName(), StrTestEntity.class),
Pair.make(StrIntTestEntity.class.getName(), StrIntTestEntity.class))
.equals(getAuditReader().findEntityTypesChangedInRevision(3));
}
}

View File

@ -6,13 +6,13 @@ import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.entityNames.manyToManyAudited.Car;
import org.hibernate.envers.test.integration.entityNames.manyToManyAudited.Person;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.envers.tools.Pair;
import org.junit.Test;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -62,7 +62,11 @@ public class EntityNamesTest extends AbstractSessionTest {
@Test
@SuppressWarnings("unchecked")
public void testModifiedEntityTypes() {
assert TestTools.makeSet(Car.class, Person.class).equals(getAuditReader().findEntityTypesChangedInRevision(1));
assert TestTools.makeSet(Car.class, Person.class).equals(getAuditReader().findEntityTypesChangedInRevision(2));
assert TestTools.makeSet(Pair.make(Car.class.getName(), Car.class),
Pair.make("Personaje", Person.class))
.equals(getAuditReader().findEntityTypesChangedInRevision(1));
assert TestTools.makeSet(Pair.make(Car.class.getName(), Car.class),
Pair.make("Personaje", Person.class))
.equals(getAuditReader().findEntityTypesChangedInRevision(2));
}
}

View File

@ -1,14 +1,13 @@
package org.hibernate.envers.test.integration.reventity.trackmodifiedentities;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.ExtendedRevisionEntity;
import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.ExtendedRevisionListener;
import org.junit.Test;
/**
* Tests proper behavior of revision entity that extends {@link DefaultTrackingModifiedTypesRevisionEntity}.
* Tests proper behavior of revision entity that extends {@link DefaultTrackingModifiedEntitiesRevisionEntity}.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class ExtendedRevisionEntityTest extends DefaultTrackingEntitiesTest {
@ -21,9 +20,8 @@ public class ExtendedRevisionEntityTest extends DefaultTrackingEntitiesTest {
@Test
public void testCommentPropertyValue() {
AuditReader vr = getAuditReader();
ExtendedRevisionEntity ere = vr.findRevision(ExtendedRevisionEntity.class, 1);
ExtendedRevisionEntity ere = getAuditReader().findRevision(ExtendedRevisionEntity.class, 1);
assert ExtendedRevisionListener.COMMENT_VALUE.equals(ere.getCommnent());
assert ExtendedRevisionListener.COMMENT_VALUE.equals(ere.getComment());
}
}