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

View File

@ -28,6 +28,7 @@ import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.exception.NotAuditedException; import org.hibernate.envers.exception.NotAuditedException;
import org.hibernate.envers.exception.RevisionDoesNotExistException; import org.hibernate.envers.exception.RevisionDoesNotExistException;
import org.hibernate.envers.query.AuditQueryCreator; import org.hibernate.envers.query.AuditQueryCreator;
import org.hibernate.envers.tools.Pair;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -222,9 +223,9 @@ public interface AuditReader {
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code> * <li><code>org.hibernate.envers.track_entities_changed_in_revision</code>
* parameter is set to <code>true</code>.</li> * parameter is set to <code>true</code>.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) * <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 * <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* marked with {@link ModifiedEntityTypes} interface.</li> * marked with {@link ModifiedEntityNames} interface.</li>
* </ul> * </ul>
*/ */
List<Object> findEntitiesChangedInRevision(Number revision) List<Object> findEntitiesChangedInRevision(Number revision)
@ -237,15 +238,15 @@ public interface AuditReader {
* @param revisionType Type of modification. * @param revisionType Type of modification.
* @return Snapshots of all audited entities changed in a given revision and filtered by modification type. * @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 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: * @throws AuditException If none of the following conditions is satisfied:
* <ul> * <ul>
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code> * <li>{@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to <code>true</code>.</li> * parameter is set to {@code true}.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) * <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 * <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* marked with {@link ModifiedEntityTypes} interface.</li> * marked with {@link ModifiedEntityNames} interface.</li>
* </ul> * </ul>
*/ */
List<Object> findEntitiesChangedInRevision(Number revision, RevisionType revisionType) List<Object> findEntitiesChangedInRevision(Number revision, RevisionType revisionType)
@ -261,36 +262,36 @@ public interface AuditReader {
* @param revision Revision number. * @param revision Revision number.
* @return Map containing lists of entity snapshots grouped by modification operation (e.g. addition, update, removal). * @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 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: * @throws AuditException If none of the following conditions is satisfied:
* <ul> * <ul>
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code> * <li>{@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to <code>true</code>.</li> * parameter is set to {@code true}.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) * <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 * <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* marked with {@link ModifiedEntityTypes} interface.</li> * marked with {@link ModifiedEntityNames} interface.</li>
* </ul> * </ul>
*/ */
Map<RevisionType, List<Object>> findEntitiesChangedInRevisionGroupByRevisionType(Number revision) Map<RevisionType, List<Object>> findEntitiesChangedInRevisionGroupByRevisionType(Number revision)
throws IllegalStateException, IllegalArgumentException, AuditException; 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. * @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 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: * @throws AuditException If none of the following conditions is satisfied:
* <ul> * <ul>
* <li><code>org.hibernate.envers.track_entities_changed_in_revision</code> * <li>{@code org.hibernate.envers.track_entities_changed_in_revision}
* parameter is set to <code>true</code>.</li> * parameter is set to {@code true}.</li>
* <li>Custom revision entity (annotated with {@link RevisionEntity}) * <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 * <li>Custom revision entity (annotated with {@link RevisionEntity}) encapsulates a field
* marked with {@link ModifiedEntityTypes} interface.</li> * marked with {@link ModifiedEntityNames} interface.</li>
* </ul> * </ul>
*/ */
Set<Class> findEntityTypesChangedInRevision(Number revision) Set<Pair<String, Class>> findEntityTypesChangedInRevision(Number revision)
throws IllegalStateException, IllegalArgumentException, AuditException; 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; 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. * This annotation expects field of <code>{@literal Set<String>}</code> type.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD}) @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.cfg.Configuration;
import org.hibernate.envers.entities.EntitiesConfigurations; import org.hibernate.envers.entities.EntitiesConfigurations;
import org.hibernate.envers.entities.PropertyData; 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.RevisionInfoNumberReader;
import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator; import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator;
import org.hibernate.envers.strategy.AuditStrategy; import org.hibernate.envers.strategy.AuditStrategy;
@ -51,7 +51,7 @@ public class AuditConfiguration {
private final EntitiesConfigurations entCfg; private final EntitiesConfigurations entCfg;
private final RevisionInfoQueryCreator revisionInfoQueryCreator; private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final RevisionInfoNumberReader revisionInfoNumberReader; private final RevisionInfoNumberReader revisionInfoNumberReader;
private final ModifiedEntityTypesReader modifiedEntityTypesReader; private final ModifiedEntityNamesReader modifiedEntityNamesReader;
public AuditEntitiesConfiguration getAuditEntCfg() { public AuditEntitiesConfiguration getAuditEntCfg() {
return auditEntCfg; return auditEntCfg;
@ -77,8 +77,8 @@ public class AuditConfiguration {
return revisionInfoNumberReader; return revisionInfoNumberReader;
} }
public ModifiedEntityTypesReader getModifiedEntityTypesReader() { public ModifiedEntityNamesReader getModifiedEntityNamesReader() {
return modifiedEntityTypesReader; return modifiedEntityNamesReader;
} }
public AuditStrategy getAuditStrategy() { public AuditStrategy getAuditStrategy() {
@ -96,7 +96,7 @@ public class AuditConfiguration {
auditProcessManager = new AuditProcessManager(revInfoCfgResult.getRevisionInfoGenerator()); auditProcessManager = new AuditProcessManager(revInfoCfgResult.getRevisionInfoGenerator());
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator(); revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader(); revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
modifiedEntityTypesReader = revInfoCfgResult.getModifiedEntityTypesReader(); modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader();
auditStrategy = initializeAuditStrategy(revInfoCfgResult.getRevisionInfoClass(), auditStrategy = initializeAuditStrategy(revInfoCfgResult.getRevisionInfoClass(),
revInfoCfgResult.getRevisionInfoTimestampData()); revInfoCfgResult.getRevisionInfoTimestampData());
entCfg = new EntitiesConfigurator().configure(cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy, 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. // The default name of the catalog of the audit tables.
private final String defaultCatalogName; 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; private boolean trackEntitiesChangedInRevisionEnabled;
/* /*

View File

@ -36,8 +36,8 @@ import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import org.hibernate.envers.Audited; import org.hibernate.envers.Audited;
import org.hibernate.envers.DefaultRevisionEntity; import org.hibernate.envers.DefaultRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity; import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.ModifiedEntityTypes; import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.RevisionEntity; import org.hibernate.envers.RevisionEntity;
import org.hibernate.envers.RevisionListener; import org.hibernate.envers.RevisionListener;
import org.hibernate.envers.RevisionNumber; 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.configuration.metadata.MetadataTools;
import org.hibernate.envers.entities.PropertyData; import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.revisioninfo.DefaultRevisionInfoGenerator; import org.hibernate.envers.revisioninfo.DefaultRevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.DefaultTrackingModifiedTypesRevisionInfoGenerator; import org.hibernate.envers.revisioninfo.DefaultTrackingModifiedEntitiesRevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.ModifiedEntityTypesReader; import org.hibernate.envers.revisioninfo.ModifiedEntityNamesReader;
import org.hibernate.envers.revisioninfo.RevisionInfoGenerator; import org.hibernate.envers.revisioninfo.RevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.RevisionInfoNumberReader; import org.hibernate.envers.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator; import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator;
@ -64,7 +64,7 @@ public class RevisionInfoConfiguration {
private String revisionInfoEntityName; private String revisionInfoEntityName;
private PropertyData revisionInfoIdData; private PropertyData revisionInfoIdData;
private PropertyData revisionInfoTimestampData; private PropertyData revisionInfoTimestampData;
private PropertyData modifiedEntityTypesData; private PropertyData modifiedEntityNamesData;
private Type revisionInfoTimestampType; private Type revisionInfoTimestampType;
private GlobalConfiguration globalCfg; private GlobalConfiguration globalCfg;
@ -76,7 +76,7 @@ public class RevisionInfoConfiguration {
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity"; revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
revisionInfoIdData = new PropertyData("id", "id", "field", null); revisionInfoIdData = new PropertyData("id", "id", "field", null);
revisionInfoTimestampData = new PropertyData("timestamp", "timestamp", "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(); revisionInfoTimestampType = new LongType();
revisionPropType = "integer"; revisionPropType = "integer";
@ -99,7 +99,9 @@ public class RevisionInfoConfiguration {
MetadataTools.addColumn(timestampProperty, "REVTSTMP", null, 0, 0, null, null, null, false); MetadataTools.addColumn(timestampProperty, "REVTSTMP", null, 0, 0, null, null, null, false);
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) { 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; return document;
@ -108,20 +110,24 @@ public class RevisionInfoConfiguration {
/** /**
* Generates mapping that represents a set of primitive types.<br /> * Generates mapping that represents a set of primitive types.<br />
* <code> * <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;key column="joinTablePrimaryKeyColumnName" /&gt;<br />
* &nbsp;&nbsp;&nbsp;&lt;element type="joinTableValueColumnType"&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;&nbsp;&nbsp;&nbsp;&lt;column name="joinTableValueColumnName" /&gt;<br />
* &nbsp;&nbsp;&nbsp;&lt;/element&gt;<br /> * &nbsp;&nbsp;&nbsp;&lt;/element&gt;<br />
* &lt;/set&gt; * &lt;/set&gt;
* </code> * </code>
*/ */
private void generateEntityTypesTrackingTableMapping(Element class_mapping, String propertyName, private void generateEntityNamesTrackingTableMapping(Element class_mapping, String propertyName,
String joinTableName, String joinTablePrimaryKeyColumnName, String joinTableSchema, String joinTableCatalog, String joinTableName,
String joinTableValueColumnName, String joinTableValueColumnType) { String joinTablePrimaryKeyColumnName, String joinTableValueColumnName,
String joinTableValueColumnType) {
Element set = class_mapping.addElement("set"); Element set = class_mapping.addElement("set");
set.addAttribute("name", propertyName); set.addAttribute("name", propertyName);
set.addAttribute("table", joinTableName); set.addAttribute("table", joinTableName);
set.addAttribute("schema", joinTableSchema);
set.addAttribute("catalog", joinTableCatalog);
set.addAttribute("cascade", "persist, delete"); set.addAttribute("cascade", "persist, delete");
set.addAttribute("fetch", "join"); set.addAttribute("fetch", "join");
set.addAttribute("lazy", "false"); set.addAttribute("lazy", "false");
@ -149,11 +155,11 @@ public class RevisionInfoConfiguration {
private void searchForRevisionInfoCfgInProperties(XClass clazz, ReflectionManager reflectionManager, private void searchForRevisionInfoCfgInProperties(XClass clazz, ReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound, MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
MutableBoolean modifiedEntityTypesFound, String accessType) { MutableBoolean modifiedEntityNamesFound, String accessType) {
for (XProperty property : clazz.getDeclaredProperties(accessType)) { for (XProperty property : clazz.getDeclaredProperties(accessType)) {
RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class); RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class);
RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class); RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class);
ModifiedEntityTypes modifiedEntityTypes = property.getAnnotation(ModifiedEntityTypes.class); ModifiedEntityNames modifiedEntityNames = property.getAnnotation(ModifiedEntityNames.class);
if (revisionNumber != null) { if (revisionNumber != null) {
if (revisionNumberFound.isSet()) { if (revisionNumberFound.isSet()) {
@ -204,17 +210,17 @@ public class RevisionInfoConfiguration {
} }
} }
if (modifiedEntityTypes != null) { if (modifiedEntityNames != null) {
if (modifiedEntityTypesFound.isSet()) { if (modifiedEntityNamesFound.isSet()) {
throw new MappingException("Only one property may be annotated with @ModifiedEntityTypes!"); throw new MappingException("Only one property may be annotated with @ModifiedEntityNames!");
} }
XClass modifiedEntityTypesClass = property.getType(); XClass modifiedEntityNamesClass = property.getType();
if (reflectionManager.equals(modifiedEntityTypesClass, Set.class) && if (reflectionManager.equals(modifiedEntityNamesClass, Set.class) &&
reflectionManager.equals(property.getElementClass(), String.class)) { reflectionManager.equals(property.getElementClass(), String.class)) {
modifiedEntityTypesData = new PropertyData(property.getName(), property.getName(), accessType, null); modifiedEntityNamesData = new PropertyData(property.getName(), property.getName(), accessType, null);
modifiedEntityTypesFound.set(); modifiedEntityNamesFound.set();
} else { } 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, private void searchForRevisionInfoCfg(XClass clazz, ReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound, MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
MutableBoolean modifiedEntityTypesFound) { MutableBoolean modifiedEntityNamesFound) {
XClass superclazz = clazz.getSuperclass(); XClass superclazz = clazz.getSuperclass();
if (!"java.lang.Object".equals(superclazz.getName())) { if (!"java.lang.Object".equals(superclazz.getName())) {
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityTypesFound); searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
} }
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityTypesFound, "field"); modifiedEntityNamesFound, "field");
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityTypesFound, "property"); modifiedEntityNamesFound, "property");
} }
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) { public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
@ -265,9 +271,9 @@ public class RevisionInfoConfiguration {
MutableBoolean revisionNumberFound = new MutableBoolean(); MutableBoolean revisionNumberFound = new MutableBoolean();
MutableBoolean revisionTimestampFound = 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()) { if (!revisionNumberFound.isSet()) {
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " + throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " +
@ -284,13 +290,13 @@ public class RevisionInfoConfiguration {
revisionInfoClass = pc.getMappedClass(); revisionInfoClass = pc.getMappedClass();
revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType(); revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType();
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled() || if (globalCfg.isTrackEntitiesChangedInRevisionEnabled() ||
DefaultTrackingModifiedTypesRevisionEntity.class.isAssignableFrom(revisionInfoClass) || DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass) ||
modifiedEntityTypesFound.isSet()) { modifiedEntityNamesFound.isSet()) {
// 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 DefaultTrackingModifiedTypesRevisionEntity class, or @ModifiedEntityTypes annotation is used. // of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedTypesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName,
revisionInfoClass, revisionEntity.value(), revisionInfoTimestampData, isTimestampAsDate(), revisionInfoClass, revisionEntity.value(), revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityTypesData); modifiedEntityNamesData);
globalCfg.setTrackEntitiesChangedInRevisionEnabled(true); globalCfg.setTrackEntitiesChangedInRevisionEnabled(true);
} else { } else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass, revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
@ -304,10 +310,10 @@ public class RevisionInfoConfiguration {
if (revisionInfoGenerator == null) { if (revisionInfoGenerator == null) {
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) { if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) {
revisionInfoClass = DefaultTrackingModifiedTypesRevisionEntity.class; revisionInfoClass = DefaultTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoEntityName = DefaultTrackingModifiedTypesRevisionEntity.class.getName(); revisionInfoEntityName = DefaultTrackingModifiedEntitiesRevisionEntity.class.getName();
revisionInfoGenerator = new DefaultTrackingModifiedTypesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass, revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
RevisionListener.class, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityTypesData); RevisionListener.class, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData);
} else { } else {
revisionInfoClass = DefaultRevisionEntity.class; revisionInfoClass = DefaultRevisionEntity.class;
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass, revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
@ -322,7 +328,7 @@ public class RevisionInfoConfiguration {
revisionInfoTimestampData.getName(), isTimestampAsDate()), revisionInfoTimestampData.getName(), isTimestampAsDate()),
generateRevisionInfoRelationMapping(), generateRevisionInfoRelationMapping(),
new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData), new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData),
globalCfg.isTrackEntitiesChangedInRevisionEnabled() ? new ModifiedEntityTypesReader(revisionInfoClass, modifiedEntityTypesData) globalCfg.isTrackEntitiesChangedInRevisionEnabled() ? new ModifiedEntityNamesReader(revisionInfoClass, modifiedEntityNamesData)
: null, : null,
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData); revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData);
} }
@ -339,7 +345,7 @@ class RevisionInfoConfigurationResult {
private final RevisionInfoQueryCreator revisionInfoQueryCreator; private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final Element revisionInfoRelationMapping; private final Element revisionInfoRelationMapping;
private final RevisionInfoNumberReader revisionInfoNumberReader; private final RevisionInfoNumberReader revisionInfoNumberReader;
private final ModifiedEntityTypesReader modifiedEntityTypesReader; private final ModifiedEntityNamesReader modifiedEntityNamesReader;
private final String revisionInfoEntityName; private final String revisionInfoEntityName;
private final Class<?> revisionInfoClass; private final Class<?> revisionInfoClass;
private final PropertyData revisionInfoTimestampData; private final PropertyData revisionInfoTimestampData;
@ -347,14 +353,14 @@ class RevisionInfoConfigurationResult {
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator, RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator,
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator, Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader, Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
ModifiedEntityTypesReader modifiedEntityTypesReader, String revisionInfoEntityName, ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) { Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
this.revisionInfoGenerator = revisionInfoGenerator; this.revisionInfoGenerator = revisionInfoGenerator;
this.revisionInfoXmlMapping = revisionInfoXmlMapping; this.revisionInfoXmlMapping = revisionInfoXmlMapping;
this.revisionInfoQueryCreator = revisionInfoQueryCreator; this.revisionInfoQueryCreator = revisionInfoQueryCreator;
this.revisionInfoRelationMapping = revisionInfoRelationMapping; this.revisionInfoRelationMapping = revisionInfoRelationMapping;
this.revisionInfoNumberReader = revisionInfoNumberReader; this.revisionInfoNumberReader = revisionInfoNumberReader;
this.modifiedEntityTypesReader = modifiedEntityTypesReader; this.modifiedEntityNamesReader = modifiedEntityNamesReader;
this.revisionInfoEntityName = revisionInfoEntityName; this.revisionInfoEntityName = revisionInfoEntityName;
this.revisionInfoClass = revisionInfoClass; this.revisionInfoClass = revisionInfoClass;
this.revisionInfoTimestampData = revisionInfoTimestampData; this.revisionInfoTimestampData = revisionInfoTimestampData;
@ -392,7 +398,7 @@ class RevisionInfoConfigurationResult {
return revisionInfoTimestampData; return revisionInfoTimestampData;
} }
public ModifiedEntityTypesReader getModifiedEntityTypesReader() { public ModifiedEntityNamesReader getModifiedEntityNamesReader() {
return modifiedEntityTypesReader; 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.AuditQueryCreator;
import org.hibernate.envers.query.criteria.RevisionTypeAuditExpression; import org.hibernate.envers.query.criteria.RevisionTypeAuditExpression;
import org.hibernate.envers.synchronization.AuditProcess; 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.event.spi.EventSource;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
@ -248,10 +250,10 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public List<Object> findEntitiesChangedInRevision(Number revision) throws IllegalStateException, public List<Object> findEntitiesChangedInRevision(Number revision) throws IllegalStateException,
IllegalArgumentException, AuditException { IllegalArgumentException, AuditException {
Set<Class> clazz = findEntityTypesChangedInRevision(revision); Set<Pair<String, Class>> entityTypes = findEntityTypesChangedInRevision(revision);
List<Object> result = new ArrayList<Object>(); List<Object> result = new ArrayList<Object>();
for (Class c : clazz) { for (Pair<String, Class> type : entityTypes) {
result.addAll(createQuery().forEntitiesModifiedAtRevision(c, revision).getResultList()); result.addAll(createQuery().forEntitiesModifiedAtRevision(type.getSecond(), type.getFirst(), revision).getResultList());
} }
return result; return result;
} }
@ -259,10 +261,10 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public List<Object> findEntitiesChangedInRevision(Number revision, RevisionType revisionType) public List<Object> findEntitiesChangedInRevision(Number revision, RevisionType revisionType)
throws IllegalStateException, IllegalArgumentException, AuditException { throws IllegalStateException, IllegalArgumentException, AuditException {
Set<Class> clazz = findEntityTypesChangedInRevision(revision); Set<Pair<String, Class>> entityTypes = findEntityTypesChangedInRevision(revision);
List<Object> result = new ArrayList<Object>(); List<Object> result = new ArrayList<Object>();
for (Class c : clazz) { for (Pair<String, Class> type : entityTypes) {
result.addAll(createQuery().forEntitiesModifiedAtRevision(c, revision) result.addAll(createQuery().forEntitiesModifiedAtRevision(type.getSecond(), type.getFirst(), revision)
.add(new RevisionTypeAuditExpression(revisionType, "=")).getResultList()); .add(new RevisionTypeAuditExpression(revisionType, "=")).getResultList());
} }
return result; return result;
@ -271,12 +273,12 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public Map<RevisionType, List<Object>> findEntitiesChangedInRevisionGroupByRevisionType(Number revision) public Map<RevisionType, List<Object>> findEntitiesChangedInRevisionGroupByRevisionType(Number revision)
throws IllegalStateException, IllegalArgumentException, AuditException { 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>>(); Map<RevisionType, List<Object>> result = new HashMap<RevisionType, List<Object>>();
for (RevisionType revisionType : RevisionType.values()) { for (RevisionType revisionType : RevisionType.values()) {
result.put(revisionType, new ArrayList()); result.put(revisionType, new ArrayList<Object>());
for (Class c : clazz) { for (Pair<String, Class> type : entityTypes) {
List<Object> list = createQuery().forEntitiesModifiedAtRevision(c, revision) List<Object> list = createQuery().forEntitiesModifiedAtRevision(type.getSecond(), type.getFirst(), revision)
.add(new RevisionTypeAuditExpression(revisionType, "=")).getResultList(); .add(new RevisionTypeAuditExpression(revisionType, "=")).getResultList();
result.get(revisionType).addAll(list); result.get(revisionType).addAll(list);
} }
@ -285,14 +287,14 @@ public class AuditReaderImpl implements AuditReaderImplementor {
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public Set<Class> findEntityTypesChangedInRevision(Number revision) throws IllegalStateException, public Set<Pair<String, Class>> findEntityTypesChangedInRevision(Number revision) throws IllegalStateException,
IllegalArgumentException, AuditException { IllegalArgumentException, AuditException {
checkNotNull(revision, "Entity revision"); checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision"); checkPositive(revision, "Entity revision");
checkSession(); checkSession();
if (!verCfg.getGlobalCfg().isTrackEntitiesChangedInRevisionEnabled()) { if (!verCfg.getGlobalCfg().isTrackEntitiesChangedInRevisionEnabled()) {
throw new AuditException("This query is designed for Envers default mechanism of tracking entities modified in a given revision." 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."); + "'org.hibernate.envers.track_entities_changed_in_revision' parameter to true.");
} }
Set<Number> revisions = new HashSet<Number>(1); Set<Number> revisions = new HashSet<Number>(1);
@ -300,8 +302,16 @@ public class AuditReaderImpl implements AuditReaderImplementor {
Criteria query = verCfg.getRevisionInfoQueryCreator().getRevisionsQuery(session, revisions); Criteria query = verCfg.getRevisionInfoQueryCreator().getRevisionsQuery(session, revisions);
Object revisionInfo = query.uniqueResult(); Object revisionInfo = query.uniqueResult();
if (revisionInfo != null) { if (revisionInfo != null) {
// If revision exists // If revision exists.
return verCfg.getModifiedEntityTypesReader().getModifiedEntityTypes(revisionInfo); 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; 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.revisioninfo.RevisionInfoGenerator;
import org.hibernate.envers.synchronization.work.AuditWorkUnit; import org.hibernate.envers.synchronization.work.AuditWorkUnit;
import org.hibernate.envers.synchronization.work.PersistentCollectionChangeWorkUnit; import org.hibernate.envers.synchronization.work.PersistentCollectionChangeWorkUnit;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.envers.tools.Tools;
import java.io.Serializable; import java.io.Serializable;
@ -36,16 +36,8 @@ public class EntityChangeNotifier {
// Notify about a change in collection owner entity. // Notify about a change in collection owner entity.
entityId = ((PersistentCollectionChangeWorkUnit.PersistentCollectionChangeWorkUnitId) entityId).getOwnerId(); 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(), revisionInfoGenerator.entityChanged(entityClass, vwu.getEntityName(), entityId, vwu.getRevisionType(),
currentRevisionData); 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.Session;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
/** /**
@ -178,4 +179,12 @@ public class Tools {
return value; 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; 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.RevisionEntity;
import org.hibernate.envers.RevisionNumber; import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp; import org.hibernate.envers.RevisionTimestamp;
@ -9,7 +9,7 @@ import javax.persistence.*;
import java.util.Set; 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) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
@Entity @Entity
@ -25,9 +25,9 @@ public class AnnotatedTrackingRevisionEntity {
@ElementCollection @ElementCollection
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV")) @JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYTYPE") @Column(name = "ENTITYNAME")
@ModifiedEntityTypes @ModifiedEntityNames
private Set<String> entityTypes; private Set<String> entityNames;
public int getCustomId() { public int getCustomId() {
return customId; return customId;
@ -45,12 +45,12 @@ public class AnnotatedTrackingRevisionEntity {
this.customTimestamp = customTimestamp; this.customTimestamp = customTimestamp;
} }
public Set<String> getEntityTypes() { public Set<String> getEntityNames() {
return entityTypes; return entityNames;
} }
public void setEntityTypes(Set<String> entityTypes) { public void setEntityNames(Set<String> entityNames) {
this.entityTypes = entityTypes; this.entityNames = entityNames;
} }
public boolean equals(Object o) { public boolean equals(Object o) {
@ -61,7 +61,7 @@ public class AnnotatedTrackingRevisionEntity {
if (customId != that.customId) return false; if (customId != that.customId) return false;
if (customTimestamp != that.customTimestamp) 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; return true;
} }
@ -69,12 +69,12 @@ public class AnnotatedTrackingRevisionEntity {
public int hashCode() { public int hashCode() {
int result = customId; int result = customId;
result = 31 * result + (int) (customTimestamp ^ (customTimestamp >>> 32)); 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; return result;
} }
@Override @Override
public String toString() { 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; package org.hibernate.envers.test.entities.reventity.trackmodifiedentities;
import org.hibernate.envers.DefaultRevisionEntity; import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity;
import org.hibernate.envers.RevisionEntity; import org.hibernate.envers.RevisionEntity;
import javax.persistence.Entity; import javax.persistence.Entity;
@ -11,14 +10,14 @@ import javax.persistence.Entity;
*/ */
@Entity @Entity
@RevisionEntity(ExtendedRevisionListener.class) @RevisionEntity(ExtendedRevisionListener.class)
public class ExtendedRevisionEntity extends DefaultTrackingModifiedTypesRevisionEntity { public class ExtendedRevisionEntity extends DefaultTrackingModifiedEntitiesRevisionEntity {
private String commnent; private String comment;
public String getCommnent() { public String getComment() {
return commnent; return comment;
} }
public void setCommnent(String commnent) { public void setComment(String comment) {
this.commnent = commnent; this.comment = comment;
} }
} }

View File

@ -9,6 +9,6 @@ public class ExtendedRevisionListener implements RevisionListener {
public static final String COMMENT_VALUE = "Comment"; public static final String COMMENT_VALUE = "Comment";
public void newRevision(Object revisionEntity) { 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; package org.hibernate.envers.test.integration.reventity.trackmodifiedentities;
import org.hibernate.ejb.Ejb3Configuration; import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.ModifiedEntityTypes; import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.AnnotatedTrackingRevisionEntity; 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) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public class AnnotatedTrackingEntitiesTest extends DefaultTrackingEntitiesTest { public class AnnotatedTrackingEntitiesTest extends DefaultTrackingEntitiesTest {

View File

@ -1,7 +1,6 @@
package org.hibernate.envers.test.integration.reventity.trackmodifiedentities; package org.hibernate.envers.test.integration.reventity.trackmodifiedentities;
import org.hibernate.ejb.Ejb3Configuration; import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.EntityTrackingRevisionListener; import org.hibernate.envers.EntityTrackingRevisionListener;
import org.hibernate.envers.exception.AuditException; import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.test.AbstractEntityTest; import org.hibernate.envers.test.AbstractEntityTest;
@ -19,7 +18,7 @@ import javax.persistence.EntityManager;
/** /**
* Tests proper behavior of entity listener that implements {@link EntityTrackingRevisionListener} * Tests proper behavior of entity listener that implements {@link EntityTrackingRevisionListener}
* interface. {@link CustomTrackingRevisionListener} shall be notified whenever an entity instance has been * 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) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public class CustomTrackingEntitiesTest extends AbstractEntityTest { public class CustomTrackingEntitiesTest extends AbstractEntityTest {
@ -69,8 +68,7 @@ public class CustomTrackingEntitiesTest extends AbstractEntityTest {
ModifiedEntityTypeEntity steDescriptor = new ModifiedEntityTypeEntity(StrTestEntity.class.getName()); ModifiedEntityTypeEntity steDescriptor = new ModifiedEntityTypeEntity(StrTestEntity.class.getName());
ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName()); ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName());
AuditReader vr = getAuditReader(); CustomTrackingRevisionEntity ctre = getAuditReader().findRevision(CustomTrackingRevisionEntity.class, 1);
CustomTrackingRevisionEntity ctre = vr.findRevision(CustomTrackingRevisionEntity.class, 1);
assert ctre.getModifiedEntityTypes() != null; assert ctre.getModifiedEntityTypes() != null;
assert ctre.getModifiedEntityTypes().size() == 2; assert ctre.getModifiedEntityTypes().size() == 2;
@ -81,8 +79,7 @@ public class CustomTrackingEntitiesTest extends AbstractEntityTest {
public void testTrackModifiedEntities() { public void testTrackModifiedEntities() {
ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName()); ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName());
AuditReader vr = getAuditReader(); CustomTrackingRevisionEntity ctre = getAuditReader().findRevision(CustomTrackingRevisionEntity.class, 2);
CustomTrackingRevisionEntity ctre = vr.findRevision(CustomTrackingRevisionEntity.class, 2);
assert ctre.getModifiedEntityTypes() != null; assert ctre.getModifiedEntityTypes() != null;
assert ctre.getModifiedEntityTypes().size() == 1; assert ctre.getModifiedEntityTypes().size() == 1;
@ -94,8 +91,7 @@ public class CustomTrackingEntitiesTest extends AbstractEntityTest {
ModifiedEntityTypeEntity steDescriptor = new ModifiedEntityTypeEntity(StrTestEntity.class.getName()); ModifiedEntityTypeEntity steDescriptor = new ModifiedEntityTypeEntity(StrTestEntity.class.getName());
ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName()); ModifiedEntityTypeEntity siteDescriptor = new ModifiedEntityTypeEntity(StrIntTestEntity.class.getName());
AuditReader vr = getAuditReader(); CustomTrackingRevisionEntity ctre = getAuditReader().findRevision(CustomTrackingRevisionEntity.class, 3);
CustomTrackingRevisionEntity ctre = vr.findRevision(CustomTrackingRevisionEntity.class, 3);
assert ctre.getModifiedEntityTypes() != null; assert ctre.getModifiedEntityTypes() != null;
assert ctre.getModifiedEntityTypes().size() == 2; 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.StrIntTestEntity;
import org.hibernate.envers.test.entities.StrTestEntity; import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.tools.TestTools; import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.envers.tools.Pair;
import org.hibernate.mapping.Column; import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.junit.Test; import org.junit.Test;
@ -17,7 +18,7 @@ import java.util.List;
import java.util.Map; 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}. * parameter is set to {@code true}.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
@ -71,7 +72,7 @@ public class DefaultTrackingEntitiesTest extends AbstractEntityTest {
if ("REVCHANGES".equals(table.getName())) { if ("REVCHANGES".equals(table.getName())) {
assert table.getColumnSpan() == 2; assert table.getColumnSpan() == 2;
assert table.getColumn(new Column("REV")) != null; assert table.getColumn(new Column("REV")) != null;
assert table.getColumn(new Column("ENTITYTYPE")) != null; assert table.getColumn(new Column("ENTITYNAME")) != null;
return; return;
} }
} }
@ -163,8 +164,15 @@ public class DefaultTrackingEntitiesTest extends AbstractEntityTest {
@Test @Test
public void testFindEntityTypesChangedInRevision() { public void testFindEntityTypesChangedInRevision() {
assert TestTools.makeSet(StrTestEntity.class, StrIntTestEntity.class).equals(getAuditReader().findEntityTypesChangedInRevision(1)); assert TestTools.makeSet(Pair.make(StrTestEntity.class.getName(), StrTestEntity.class),
assert TestTools.makeSet(StrIntTestEntity.class).equals(getAuditReader().findEntityTypesChangedInRevision(2)); Pair.make(StrIntTestEntity.class.getName(), StrIntTestEntity.class))
assert TestTools.makeSet(StrTestEntity.class, StrIntTestEntity.class).equals(getAuditReader().findEntityTypesChangedInRevision(3)); .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.Car;
import org.hibernate.envers.test.integration.entityNames.manyToManyAudited.Person; import org.hibernate.envers.test.integration.entityNames.manyToManyAudited.Person;
import org.hibernate.envers.test.tools.TestTools; import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.envers.tools.Pair;
import org.junit.Test; import org.junit.Test;
import java.io.File; import java.io.File;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@ -62,7 +62,11 @@ public class EntityNamesTest extends AbstractSessionTest {
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void testModifiedEntityTypes() { public void testModifiedEntityTypes() {
assert TestTools.makeSet(Car.class, Person.class).equals(getAuditReader().findEntityTypesChangedInRevision(1)); assert TestTools.makeSet(Pair.make(Car.class.getName(), Car.class),
assert TestTools.makeSet(Car.class, Person.class).equals(getAuditReader().findEntityTypesChangedInRevision(2)); 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; package org.hibernate.envers.test.integration.reventity.trackmodifiedentities;
import org.hibernate.ejb.Ejb3Configuration; import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.AuditReader; import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedTypesRevisionEntity;
import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.ExtendedRevisionEntity; import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.ExtendedRevisionEntity;
import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.ExtendedRevisionListener; import org.hibernate.envers.test.entities.reventity.trackmodifiedentities.ExtendedRevisionListener;
import org.junit.Test; 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) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public class ExtendedRevisionEntityTest extends DefaultTrackingEntitiesTest { public class ExtendedRevisionEntityTest extends DefaultTrackingEntitiesTest {
@ -21,9 +20,8 @@ public class ExtendedRevisionEntityTest extends DefaultTrackingEntitiesTest {
@Test @Test
public void testCommentPropertyValue() { public void testCommentPropertyValue() {
AuditReader vr = getAuditReader(); ExtendedRevisionEntity ere = getAuditReader().findRevision(ExtendedRevisionEntity.class, 1);
ExtendedRevisionEntity ere = vr.findRevision(ExtendedRevisionEntity.class, 1);
assert ExtendedRevisionListener.COMMENT_VALUE.equals(ere.getCommnent()); assert ExtendedRevisionListener.COMMENT_VALUE.equals(ere.getComment());
} }
} }