HHH-6605: Merging changes by Michal Skowronek. Thanks! Merge remote-tracking branch 'mskowron/change_info'

Conflicts:
	hibernate-envers/src/main/java/org/hibernate/envers/configuration/GlobalConfiguration.java
	hibernate-envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
	hibernate-envers/src/main/java/org/hibernate/envers/configuration/metadata/ComponentMetadataGenerator.java
	hibernate-envers/src/main/java/org/hibernate/envers/configuration/metadata/MetadataTools.java
	hibernate-envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java
	hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/ComponentPropertyMapper.java
	hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/MultiPropertyMapper.java
	hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/PropertyMapper.java
	hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/SinglePropertyMapper.java
	hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/SubclassPropertyMapper.java
	hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/AbstractCollectionMapper.java
	hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/OneToOneNotOwningMapper.java
	hibernate-envers/src/main/java/org/hibernate/envers/event/BaseEnversCollectionEventListener.java
	hibernate-envers/src/main/java/org/hibernate/envers/query/criteria/AuditProperty.java
	hibernate-envers/src/main/java/org/hibernate/envers/synchronization/work/AddWorkUnit.java
	hibernate-envers/src/main/java/org/hibernate/envers/synchronization/work/CollectionChangeWorkUnit.java
	hibernate-envers/src/main/java/org/hibernate/envers/synchronization/work/DelWorkUnit.java
	hibernate-envers/src/main/java/org/hibernate/envers/synchronization/work/FakeBidirectionalRelationWorkUnit.java
	hibernate-envers/src/main/java/org/hibernate/envers/tools/Tools.java
	hibernate-envers/src/matrix/java/org/hibernate/envers/test/AbstractOneSessionTest.java
	hibernate-envers/src/matrix/java/org/hibernate/envers/test/AbstractSessionTest.java
	hibernate-envers/src/matrix/java/org/hibernate/envers/test/integration/components/relations/ManyToOneInComponent.java
	hibernate-envers/src/matrix/java/org/hibernate/envers/test/integration/components/relations/NotAuditedManyToOneInComponent.java
	hibernate-envers/src/matrix/java/org/hibernate/envers/test/integration/components/relations/OneToManyInComponent.java
	hibernate-envers/src/matrix/java/org/hibernate/envers/test/integration/entityNames/singleAssociatedAudited/SingleDomainObjectToMultipleTablesTest.java
	hibernate-envers/src/matrix/java/org/hibernate/envers/test/integration/inheritance/joined/notownedrelation/NotOwnedBidirectional.java
This commit is contained in:
Adam Warski 2012-01-20 20:47:12 +01:00
commit b109633b66
53 changed files with 3762 additions and 129 deletions

View File

@ -267,6 +267,35 @@
and <xref linkend="envers-tracking-modified-entities-queries"/>.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.global_with_modified_flag</property>
</entry>
<entry>
false, can be individually overriden with <literal>@Audited(withModifiedFlag=true)</literal>
</entry>
<entry>
Should property modification flags be stored for all audited entities and all properties.
When set to true, for all properties an additional boolean column in the audit tables will
be created, filled with information if the given property changed in the given revision.
When set to false, such column can be added to selected entities or properties using the
<literal>@Audited</literal> annotation.
For more information refer to <xref linkend="envers-tracking-properties-changes"/>
and <xref linkend="envers-envers-tracking-properties-changes-queries"/>.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.modified_flag_suffix</property>
</entry>
<entry>
_MOD
</entry>
<entry>
The suffix for columns storing "Modified Flags".
For example: a property called "age", will by default get modified flag with column name "age_MOD".
</entry>
</row>
</tbody>
</tgroup>
</table>
@ -278,6 +307,12 @@
<listitem>
org.hibernate.envers.track_entities_changed_in_revision
</listitem>
<listitem>
org.hibernate.envers.using_modified_flag
</listitem>
<listitem>
org.hibernate.envers.modified_flag_suffix
</listitem>
</orderedlist>
</para>
</important>
@ -627,6 +662,54 @@ Set<ModifiedEntityTypeEntity> modifiedEntityTypes = revEntity.getModifiedEntityT
</section>
<section id="envers-tracking-properties-changes">
<title>Tracking entity changes at property level</title>
<para>
By default the only information stored by Envers are revisions of modified entities.
This approach lets user create audit queries based on historical values of entity's properties.
Sometimes it is useful to store additional metadata for each revision, when you are interested also in
the type of changes, not only about the resulting values. The feature described in
<xref linkend="envers-tracking-modified-entities-revchanges"/>
makes it possible to tell which entities were modified in given revision.
Feature described here takes it one step further. "Modification Flags" enable Envers to track which
properties of audited entities were modified in a given revision.
</para>
<para>
Tracking entity changes at property level can be enabled by:
</para>
<orderedlist>
<listitem>
setting
<property>org.hibernate.envers.global_with_modified_flag</property>
configuration property to
<literal>true</literal>.
This global switch will cause adding modification flags for all audited
properties in all audited entities.
</listitem>
<listitem>
using <literal>@Audited(withModifiedFlag=true)</literal>
on a property or on an entity.
</listitem>
</orderedlist>
<para>
The trade-off coming with this functionality is an increased size of
audit tables and a very little, almost negligible, performance drop
during audit writes. This is due to the fact that every tracked
property has to have an accompanying boolean column in the
schema that stores information about the property's modifications. Of
course it is Envers' job to fill these columns accordingly - no additional work by the
developer is required. Because of costs mentioned, it is recommended
to enable the feature selectively, when needed with use of the
granular configuration means described above.
</para>
<para>
To see how "Modified Flags" can be utilized, check out the very
simple query API that uses them: <xref linkend="envers-envers-tracking-properties-changes-queries"/>.
</para>
</section>
<section id="envers-queries">
<title>Queries</title>
@ -816,6 +899,78 @@ query.add(AuditEntity.relatedId("address").eq(relatedEntityId));]]></programlist
</section>
<section id="envers-envers-tracking-properties-changes-queries">
<title>Querying for revisions of entity that modified given property</title>
<para>
For the two types of queries described above it's possible to use
special Audit criteria called
<literal>hasChanged()</literal>
and
<literal>hasNotChanged()</literal>
that makes use of the functionality
described in <xref linkend="envers-tracking-properties-changes"/>.
They're best suited for vertical queries,
however existing API doesn't restrict their usage for horizontal
ones.
Let's have a look at following examples:
</para>
<programlisting><![CDATA[
AuditQuery query = getAuditReader().createQuery()
.forRevisionsOfEntity(MyEntity.class, false, true)
.add(AuditEntity.id().eq(id));
.add(AuditEntity.property("actualDate").hasChanged())]]>
</programlisting>
<para>
This query will return all revisions of MyEntity with given id,
where the
<property>actualDate</property>
property has been changed.
Using this query we won't get all other revisions in which
<property>actualDate</property>
wasn't touched. Of course nothing prevents user from combining
hasChanged condition with some additional criteria - add method
can be used here in a normal way.
</para>
<programlisting><![CDATA[
AuditQuery query = getAuditReader().createQuery()
.forEntitiesAtRevision(MyEntity.class, revisionNumber)
.add(AuditEntity.property("prop1").hasChanged())
.add(AuditEntity.property("prop2").hasNotChanged());]]>
</programlisting>
<para>
This query will return horizontal slice for MyEntity at the time
revisionNumber was generated. It will be limited to revisions
that modified
<property>prop1</property>
but not <property>prop2</property>.
Note that the result set will usually also contain revisions
with numbers lower than the revisionNumber, so we cannot read
this query as "Give me all MyEntities changed in revisionNumber
with
<property>prop1</property>
modified and
<property>prop2</property>
untouched". To get such result we have to use the
<literal>forEntitiesModifiedAtRevision</literal> query:
</para>
<programlisting><![CDATA[
AuditQuery query = getAuditReader().createQuery()
.forEntitiesModifiedAtRevision(MyEntity.class, revisionNumber)
.add(AuditEntity.property("prop1").hasChanged())
.add(AuditEntity.property("prop2").hasNotChanged());]]>
</programlisting>
</section>
<section id="envers-tracking-modified-entities-queries">
<title>Querying for entities modified in a given revision</title>
<para>

View File

@ -33,6 +33,7 @@ import java.lang.annotation.Target;
* @author Adam Warski (adam at warski dot org)
* @author Tomasz Bech
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@ -59,4 +60,11 @@ public @interface Audited {
* @deprecated Use {@code @AuditOverride(forClass=SomeEntity.class)} instead.
*/
Class[] auditParents() default {};
/**
* @return Should a modification flag be stored for each property in the annotated class or for the annotated
* property. The flag stores information if a property has been changed at a given revision.
* This can be used for example in queries.
*/
boolean withModifiedFlag() default false;
}

View File

@ -33,9 +33,14 @@ import static org.hibernate.envers.tools.Tools.getProperty;
* @author Adam Warski (adam at warski dot org)
* @author Nicolas Doroskevich
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class GlobalConfiguration {
// Should a revision be generated when a not-owned relation field changes
public static final String GLOBAL_WITH_MODIFIED_FLAG_PROPERTY = "org.hibernate.envers.global_with_modified_flag";
public static final String MODIFIED_FLAG_SUFFIX_PROPERTY = "org.hibernate.envers.modified_flag_suffix";
public static final String DEFAULT_MODIFIED_FLAG_SUFFIX = "_MOD";
// Should a revision be generated when a not-owned relation field changes
private final boolean generateRevisionsForCollections;
// Should the optimistic locking property of an entity be considered unversioned
@ -56,6 +61,15 @@ public class GlobalConfiguration {
// Revision listener class name.
private final Class<? extends RevisionListener> revisionListenerClass;
// Should Envers use modified property flags by default
private boolean globalWithModifiedFlag;
// Indicates that user defined global behavior for modified flags feature
private boolean hasGlobalSettingForWithModifiedFlag;
// Suffix to be used for modified flags columns
private String modifiedFlagSuffix;
/*
Which operator to use in correlated subqueries (when we want a property to be equal to the result of
a correlated subquery, for example: e.p <operator> (select max(e2.p) where e2.p2 = e.p2 ...).
@ -95,7 +109,20 @@ public class GlobalConfiguration {
"false");
trackEntitiesChangedInRevisionEnabled = Boolean.parseBoolean(trackEntitiesChangedInRevisionEnabledStr);
String revisionListenerClassName = properties.getProperty("org.hibernate.envers.revision_listener", null);
hasGlobalSettingForWithModifiedFlag =
properties.getProperty(GLOBAL_WITH_MODIFIED_FLAG_PROPERTY) != null;
String usingModifiedFlagStr = getProperty(properties,
GLOBAL_WITH_MODIFIED_FLAG_PROPERTY,
GLOBAL_WITH_MODIFIED_FLAG_PROPERTY,
"false");
globalWithModifiedFlag = Boolean.parseBoolean(usingModifiedFlagStr);
modifiedFlagSuffix =
getProperty(properties, MODIFIED_FLAG_SUFFIX_PROPERTY,
MODIFIED_FLAG_SUFFIX_PROPERTY,
DEFAULT_MODIFIED_FLAG_SUFFIX);
String revisionListenerClassName = properties.getProperty("org.hibernate.envers.revision_listener", null);
if (revisionListenerClassName != null) {
try {
revisionListenerClass = (Class<? extends RevisionListener>) Thread.currentThread().getContextClassLoader().loadClass(revisionListenerClassName);
@ -142,4 +169,16 @@ public class GlobalConfiguration {
public Class<? extends RevisionListener> getRevisionListenerClass() {
return revisionListenerClass;
}
public boolean hasSettingForUsingModifiedFlag() {
return hasGlobalSettingForWithModifiedFlag;
}
public boolean isGlobalWithModifiedFlag() {
return globalWithModifiedFlag;
}
public String getModifiedFlagSuffix() {
return modifiedFlagSuffix;
}
}

View File

@ -67,6 +67,7 @@ import org.hibernate.type.Type;
* @author Stephanie Pau at Markit Group Plc
* @author Hern&aacute;n Chanfreau
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public final class AuditMetadataGenerator {
@ -166,54 +167,79 @@ public final class AuditMetadataGenerator {
}
}
void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean firstPass) {
Type type = value.getType();
private void addValueInFirstPass(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean processModifiedFlag) {
Type type = value.getType();
// only first pass
if (firstPass) {
if (basicMetadataGenerator.addBasic(parent, propertyAuditingData, value, currentMapper,
insertable, false)) {
// The property was mapped by the basic generator.
return;
}
}
if (basicMetadataGenerator.addBasic(parent, propertyAuditingData, value, currentMapper, insertable, false)) {
// The property was mapped by the basic generator.
} else if (type instanceof ComponentType) {
componentMetadataGenerator.addComponent(parent, propertyAuditingData, value, currentMapper,
entityName, xmlMappingData, true);
} else {
if (!processedInSecondPass(type)) {
// If we got here in the first pass, it means the basic mapper didn't map it, and none of the
// above branches either.
throwUnsupportedTypeException(type, entityName, propertyAuditingData.getName());
}
return;
}
addModifiedFlagIfNeeded(parent, propertyAuditingData, processModifiedFlag);
}
private boolean processedInSecondPass(Type type) {
return type instanceof ComponentType || type instanceof ManyToOneType ||
type instanceof OneToOneType || type instanceof CollectionType;
}
private void addValueInSecondPass(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean processModifiedFlag) {
Type type = value.getType();
if (type instanceof ComponentType) {
// both passes
componentMetadataGenerator.addComponent(parent, propertyAuditingData, value, currentMapper,
entityName, xmlMappingData, firstPass);
entityName, xmlMappingData, false);
return;// mod flag field has been already generated in first pass
} else if (type instanceof ManyToOneType) {
// only second pass
if (!firstPass) {
toOneRelationMetadataGenerator.addToOne(parent, propertyAuditingData, value, currentMapper,
entityName, insertable);
}
} else if (type instanceof OneToOneType) {
// only second pass
if (!firstPass) {
toOneRelationMetadataGenerator.addOneToOneNotOwning(propertyAuditingData, value,
currentMapper, entityName);
}
} else if (type instanceof CollectionType) {
// only second pass
if (!firstPass) {
CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(this,
(Collection) value, currentMapper, entityName, xmlMappingData,
propertyAuditingData);
collectionMetadataGenerator.addCollection();
}
} else {
if (firstPass) {
// If we got here in the first pass, it means the basic mapper didn't map it, and none of the
// above branches either.
throwUnsupportedTypeException(type, entityName, propertyAuditingData.getName());
}
}
}
toOneRelationMetadataGenerator.addToOne(parent, propertyAuditingData, value, currentMapper,
entityName, insertable);
} else if (type instanceof OneToOneType) {
toOneRelationMetadataGenerator.addOneToOneNotOwning(propertyAuditingData, value,
currentMapper, entityName);
} else if (type instanceof CollectionType) {
CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(this,
(Collection) value, currentMapper, entityName, xmlMappingData,
propertyAuditingData);
collectionMetadataGenerator.addCollection();
} else {
return;
}
addModifiedFlagIfNeeded(parent, propertyAuditingData, processModifiedFlag);
}
private void addProperties(Element parent, Iterator<Property> properties, CompositeMapperBuilder currentMapper,
private void addModifiedFlagIfNeeded(Element parent, PropertyAuditingData propertyAuditingData, boolean processModifiedFlag) {
if (processModifiedFlag && propertyAuditingData.isUsingModifiedFlag()) {
MetadataTools.addModifiedFlagProperty(parent,
propertyAuditingData.getName(),
globalCfg.getModifiedFlagSuffix());
}
}
void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean firstPass, boolean processModifiedFlag) {
if (firstPass) {
addValueInFirstPass(parent, value, currentMapper, entityName,
xmlMappingData, propertyAuditingData, insertable, processModifiedFlag);
} else {
addValueInSecondPass(parent, value, currentMapper, entityName,
xmlMappingData, propertyAuditingData, insertable, processModifiedFlag);
}
}
private void addProperties(Element parent, Iterator<Property> properties, CompositeMapperBuilder currentMapper,
ClassAuditingData auditingData, String entityName, EntityXmlMappingData xmlMappingData,
boolean firstPass) {
while (properties.hasNext()) {
@ -222,7 +248,7 @@ public final class AuditMetadataGenerator {
PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData(propertyName);
if (propertyAuditingData != null) {
addValue(parent, property.getValue(), currentMapper, entityName, xmlMappingData, propertyAuditingData,
property.isInsertable(), firstPass);
property.isInsertable(), firstPass, true);
}
}
}

View File

@ -44,7 +44,7 @@ public final class ComponentMetadataGenerator {
// Checking if that property is audited
if (componentPropertyAuditingData != null) {
mainGenerator.addValue(parent, property.getValue(), componentMapper, entityName, xmlMappingData,
componentPropertyAuditingData, property.isInsertable(), firstPass);
componentPropertyAuditingData, property.isInsertable(), firstPass, false);
}
}
}

View File

@ -36,9 +36,11 @@ import org.hibernate.mapping.Formula;
/**
* @author Adam Warski (adam at warski dot org)
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class MetadataTools {
public static Element addNativelyGeneratedId(Element parent, String name, String type) {
public static Element addNativelyGeneratedId(Element parent, String name, String type) {
Element id_mapping = parent.addElement("id");
id_mapping.addAttribute("name", name).addAttribute("type", type);
@ -73,7 +75,15 @@ public class MetadataTools {
return addProperty(parent, name, type, insertable, false, key);
}
private static void addOrModifyAttribute(Element parent, String name, String value) {
public static Element addModifiedFlagProperty(Element parent, String propertyName, String suffix) {
return addProperty(parent, getModifiedFlagPropertyName(propertyName, suffix), "boolean", true, false, false);
}
public static String getModifiedFlagPropertyName(String propertyName, String suffix) {
return propertyName + suffix;
}
private static void addOrModifyAttribute(Element parent, String name, String value) {
Attribute attribute = parent.attribute(name);
if (attribute == null) {
parent.addAttribute(name, value);

View File

@ -23,6 +23,7 @@ import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.NotAudited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.configuration.metadata.MetadataTools;
import org.hibernate.envers.tools.MappingTools;
import org.hibernate.envers.tools.StringTools;
import org.hibernate.envers.tools.Tools;
@ -43,6 +44,7 @@ import static org.hibernate.envers.tools.Tools.newHashSet;
* @author Erik-Berndt Scheper
* @author Hern&aacut;n Chanfreau
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class AuditedPropertiesReader {
protected final ModificationStore defaultStore;
@ -392,9 +394,13 @@ public class AuditedPropertiesReader {
if(!this.checkAudited(property, propertyData, allClassAudited)){
return false;
}
propertyData.setName(propertyNamePrefix + property.getName());
String propertyName = propertyNamePrefix + property.getName();
propertyData.setName(propertyName);
propertyData.setModifiedFlagName(
MetadataTools.getModifiedFlagPropertyName(
propertyName,
globalCfg.getModifiedFlagSuffix()));
propertyData.setBeanName(property.getName());
propertyData.setAccessType(accessType);
@ -409,7 +415,7 @@ public class AuditedPropertiesReader {
return true;
}
protected boolean checkAudited(XProperty property,
PropertyAuditingData propertyData, Audited allClassAudited) {
// Checking if this property is explicitly audited or if all properties are.
@ -422,13 +428,19 @@ public class AuditedPropertiesReader {
if (aud != null) {
propertyData.setStore(aud.modStore());
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
return true;
} else {
return false;
}
}
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
protected boolean checkUsingModifiedFlag(Audited aud) {
return globalCfg.hasSettingForUsingModifiedFlag() ?
globalCfg.isGlobalWithModifiedFlag() : aud.withModifiedFlag();
}
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class);
if (auditMappedBy != null) {
propertyData.setAuditMappedBy(auditMappedBy.mappedBy());
@ -507,6 +519,7 @@ public class AuditedPropertiesReader {
public ModificationStore modStore() { return ModificationStore.FULL; }
public RelationTargetAuditMode targetAuditMode() { return RelationTargetAuditMode.AUDITED; }
public Class[] auditParents() { return new Class[0]; }
public boolean withModifiedFlag() { return false; }
public Class<? extends Annotation> annotationType() { return this.getClass(); }
};

View File

@ -9,7 +9,7 @@ import org.hibernate.envers.configuration.GlobalConfiguration;
* Reads the audited properties for components.
*
* @author Hern&aacut;n Chanfreau
*
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
@ -30,6 +30,7 @@ public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
if (aud != null) {
propertyData.setStore(aud.modStore());
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
} else {
propertyData.setStore(ModificationStore.FULL);
}

View File

@ -35,6 +35,7 @@ import org.hibernate.envers.entities.PropertyData;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class PropertyAuditingData {
private String name;
@ -48,6 +49,8 @@ public class PropertyAuditingData {
private String auditMappedBy;
private String positionMappedBy;
private boolean forceInsertable;
private boolean usingModifiedFlag;
private String modifiedFlagName;
public PropertyAuditingData() {
}
@ -115,7 +118,8 @@ public class PropertyAuditingData {
}
public PropertyData getPropertyData() {
return new PropertyData(name, beanName, accessType, store);
return new PropertyData(name, beanName, accessType, store,
usingModifiedFlag, modifiedFlagName);
}
public List<AuditOverride> getAuditingOverrides() {
@ -146,7 +150,19 @@ public class PropertyAuditingData {
this.forceInsertable = forceInsertable;
}
public void addAuditingOverride(AuditOverride annotation) {
public boolean isUsingModifiedFlag() {
return usingModifiedFlag;
}
public void setUsingModifiedFlag(boolean usingModifiedFlag) {
this.usingModifiedFlag = usingModifiedFlag;
}
public void setModifiedFlagName(String modifiedFlagName) {
this.modifiedFlagName = modifiedFlagName;
}
public void addAuditingOverride(AuditOverride annotation) {
if (annotation != null) {
String overrideName = annotation.name();
boolean present = false;

View File

@ -22,13 +22,18 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.entities;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Configuration of the user entities: property mapping of the entities, relations, inheritance.
* @author Adam Warski (adam at warski dot org)
* @author Hern&aacute;n Chanfreau
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class EntitiesConfigurations {
private Map<String, EntityConfiguration> entitiesConfigurations;
@ -113,4 +118,44 @@ public class EntitiesConfigurations {
}
}
private Collection<RelationDescription> getRelationDescriptions(String entityName) {
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
Collection<RelationDescription> descriptions = new ArrayList<RelationDescription>();
if (entCfg.getParentEntityName() != null) {
// collect descriptions from super classes
descriptions.addAll(getRelationDescriptions(entCfg.getParentEntityName()));
}
for (RelationDescription relationDescription : entCfg.getRelationsIterator()) {
descriptions.add(relationDescription);
}
return descriptions;
}
private void addWithParentEntityNames(String entityName, Set<String> entityNames) {
entityNames.add(entityName);
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
if (entCfg.getParentEntityName() != null) {
// collect descriptions from super classes
addWithParentEntityNames(entCfg.getParentEntityName(), entityNames);
}
}
private Set<String> getEntityAndParentsNames(String entityName) {
Set<String> names = new HashSet<String>();
addWithParentEntityNames(entityName, names);
return names;
}
public Set<String> getToPropertyNames(String fromEntityName, String fromPropertyName, String toEntityName) {
Set<String> entityAndParentsNames = getEntityAndParentsNames(fromEntityName);
Set<String> toPropertyNames = new HashSet<String>();
for (RelationDescription relationDescription : getRelationDescriptions(toEntityName)) {
String relToEntityName = relationDescription.getToEntityName();
String mappedByPropertyName = relationDescription.getMappedByPropertyName();
if (entityAndParentsNames.contains(relToEntityName) && mappedByPropertyName.equals(fromPropertyName)) {
toPropertyNames.add(relationDescription.getFromPropertyName());
}
}
return toPropertyNames;
}
}

View File

@ -36,6 +36,8 @@ public class PropertyData {
private final String beanName;
private final String accessType;
private final ModificationStore store;
private boolean usingModifiedFlag;
private String modifiedFlagName;
/**
* Copies the given property data, except the name.
@ -62,6 +64,19 @@ public class PropertyData {
this.store = store;
}
/**
* @param name Name of the property.
* @param beanName Name of the property in the bean.
* @param accessType Accessor type for this property.
* @param store How this property should be stored.
* @param usingModifiedFlag Defines if field changes should be tracked
*/
public PropertyData(String name, String beanName, String accessType, ModificationStore store, boolean usingModifiedFlag, String modifiedFlagName) {
this(name, beanName, accessType, store);
this.usingModifiedFlag = usingModifiedFlag;
this.modifiedFlagName = modifiedFlagName;
}
public String getName() {
return name;
}
@ -78,6 +93,14 @@ public class PropertyData {
return store;
}
public boolean isUsingModifiedFlag() {
return usingModifiedFlag;
}
public String getModifiedFlagPropertyName() {
return modifiedFlagName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -89,6 +112,7 @@ public class PropertyData {
if (beanName != null ? !beanName.equals(that.beanName) : that.beanName != null) return false;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
if (store != that.store) return false;
if (usingModifiedFlag != that.usingModifiedFlag) return false;
return true;
}
@ -99,6 +123,7 @@ public class PropertyData {
result = 31 * result + (beanName != null ? beanName.hashCode() : 0);
result = 31 * result + (accessType != null ? accessType.hashCode() : 0);
result = 31 * result + (store != null ? store.hashCode() : 0);
result = 31 * result + (usingModifiedFlag ? 1 : 0);
return result;
}
}

View File

@ -25,6 +25,7 @@ package org.hibernate.envers.entities.mapper;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionImplementor;
@ -38,6 +39,7 @@ import org.hibernate.property.Setter;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperBuilder {
private final PropertyData propertyData;
@ -66,7 +68,29 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
return delegate.mapToMapFromEntity(session, data, newObj, oldObj);
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
if (propertyData.isUsingModifiedFlag()) {
data.put(propertyData.getModifiedFlagPropertyName(),
delegate.mapToMapFromEntity(session, new HashMap<String, Object>(), newObj, oldObj));
}
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
if (propertyData.isUsingModifiedFlag()) {
boolean hasModifiedCollection = false;
for (PropertyData propData : delegate.getProperties().keySet()) {
if (collectionPropertyName.equals(propData.getName())) {
hasModifiedCollection = true;
break;
}
}
data.put(propertyData.getModifiedFlagPropertyName(), hasModifiedCollection);
}
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
if (data == null || obj == null) {
return;
}

View File

@ -32,12 +32,14 @@ import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.envers.tools.MappingTools;
import org.hibernate.envers.tools.Pair;
import org.hibernate.envers.tools.Tools;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.property.Getter;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class MultiPropertyMapper implements ExtendedPropertyMapper {
protected final Map<PropertyData, PropertyMapper> properties;
@ -80,9 +82,11 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
String propertyName = propertyNames[i];
if (propertyDatas.containsKey(propertyName)) {
ret |= properties.get(propertyDatas.get(propertyName)).mapToMapFromEntity(session, data,
getAtIndexOrNull(newState, i),
getAtIndexOrNull(oldState, i));
PropertyMapper propertyMapper = properties.get(propertyDatas.get(propertyName));
Object newObj = getAtIndexOrNull(newState, i);
Object oldObj = getAtIndexOrNull(oldState, i);
ret |= propertyMapper.mapToMapFromEntity(session, data, newObj, oldObj);
propertyMapper.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj);
}
}
@ -109,18 +113,33 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
return ret;
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
for (PropertyData propertyData : properties.keySet()) {
Getter getter;
if (newObj != null) {
getter = ReflectionTools.getGetter(newObj.getClass(), propertyData);
} else if (oldObj != null) {
getter = ReflectionTools.getGetter(oldObj.getClass(), propertyData);
} else {
return;
}
properties.get(propertyData).mapModifiedFlagsToMapFromEntity(session, data,
newObj == null ? null : getter.get(newObj),
oldObj == null ? null : getter.get(oldObj));
}
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
for (PropertyMapper mapper : properties.values()) {
mapper.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
}
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
// Name of the properyt, to which we will delegate the mapping.
private Pair<PropertyMapper, String> getMapperAndDelegatePropName(String referencingPropertyName){
// Name of the property, to which we will delegate the mapping.
String delegatePropertyName;
// Checking if the property name doesn't reference a collection in a component - then the name will containa a .
@ -140,14 +159,30 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
// If this is not a component, we delegate to the same property.
delegatePropertyName = referencingPropertyName;
}
return Pair.make(properties.get(propertyDatas.get(referencingPropertyName)), delegatePropertyName);
}
PropertyMapper mapper = properties.get(propertyDatas.get(referencingPropertyName));
if (mapper != null) {
return mapper.mapCollectionChanges(delegatePropertyName, newColl, oldColl, id);
} else {
return null;
}
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(collectionPropertyName);
PropertyMapper mapper = pair.getFirst();
if (mapper != null) {
mapper.mapModifiedFlagsToMapForCollectionChange(pair.getSecond(), data);
}
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(referencingPropertyName);
PropertyMapper mapper = pair.getFirst();
if (mapper != null) {
return mapper.mapCollectionChanges(pair.getSecond(), newColl, oldColl, id);
} else {
return null;
}
}
public Map<PropertyData, PropertyMapper> getProperties() {
return properties;

View File

@ -33,6 +33,7 @@ import org.hibernate.envers.reader.AuditReaderImplementor;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public interface PropertyMapper {
/**
@ -68,4 +69,8 @@ public interface PropertyMapper {
List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id);
void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj);
void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data);
}

View File

@ -41,6 +41,7 @@ import org.hibernate.property.Setter;
/**
* TODO: diff
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder {
private PropertyData propertyData;
@ -65,7 +66,18 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
return !Tools.objectsEqual(newObj, oldObj);
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
if (propertyData.isUsingModifiedFlag()) {
data.put(propertyData.getModifiedFlagPropertyName(), !Tools.objectsEqual(newObj, oldObj));
}
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
if (data == null || obj == null) {
return;

View File

@ -36,6 +36,7 @@ import org.hibernate.envers.reader.AuditReaderImplementor;
* A mapper which maps from a parent mapper and a "main" one, but adds only to the "main". The "main" mapper
* should be the mapper of the subclass.
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class SubclassPropertyMapper implements ExtendedPropertyMapper {
private ExtendedPropertyMapper main;
@ -60,7 +61,19 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
return parentDiffs || mainDiffs;
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
parentMapper.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj);
main.mapModifiedFlagsToMapFromEntity(session, data, newObj, oldObj);
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
parentMapper.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data);
main.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data);
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
parentMapper.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
main.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
}

View File

@ -37,6 +37,7 @@ import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
import org.hibernate.envers.entities.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
@ -47,6 +48,7 @@ import org.hibernate.property.Setter;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
protected final CommonCollectionMapperData commonCollectionMapperData;
@ -133,7 +135,39 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
return false;
}
protected abstract Initializor<T> getInitializor(AuditConfiguration verCfg,
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
if (propertyData.isUsingModifiedFlag()) {
if(isFromNullToEmptyOrFromEmptyToNull((PersistentCollection) newObj, (Serializable) oldObj)){
data.put(propertyData.getModifiedFlagPropertyName(), true);
} else {
List<PersistentCollectionChangeData> changes = mapCollectionChanges(
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(),
(PersistentCollection) newObj, (Serializable) oldObj, null);
data.put(propertyData.getModifiedFlagPropertyName(), !changes.isEmpty());
}
}
}
private boolean isFromNullToEmptyOrFromEmptyToNull(PersistentCollection newColl, Serializable oldColl) {
// Comparing new and old collection content.
Collection newCollection = getNewCollectionContent(newColl);
Collection oldCollection = getOldCollectionContent(oldColl);
return oldCollection == null && newCollection != null && newCollection.isEmpty()
|| newCollection == null && oldCollection != null && oldCollection.isEmpty();
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
PropertyData propertyData = commonCollectionMapperData.getCollectionReferencingPropertyData();
if (propertyData.isUsingModifiedFlag()) {
data.put(propertyData.getModifiedFlagPropertyName(), propertyData.getName().equals(collectionPropertyName));
}
}
protected abstract Initializor<T> getInitializor(AuditConfiguration verCfg,
AuditReaderImplementor versionsReader, Object primaryKey,
Number revision);

View File

@ -44,6 +44,7 @@ import org.hibernate.property.Setter;
/**
* @author Adam Warski (adam at warski dot org)
* @author Hern<EFBFBD>n Chanfreau
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class OneToOneNotOwningMapper implements PropertyMapper {
private String owningReferencePropertyName;
@ -61,7 +62,18 @@ public class OneToOneNotOwningMapper implements PropertyMapper {
return false;
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
if (propertyData.isUsingModifiedFlag()) {
data.put(propertyData.getModifiedFlagPropertyName(), collectionPropertyName.equals(propertyData.getName()));
}
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
if (obj == null) {
return;
}

View File

@ -45,6 +45,7 @@ import org.hibernate.property.Setter;
/**
* @author Adam Warski (adam at warski dot org)
* @author Hern<EFBFBD>n Chanfreau
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class ToOneIdMapper implements PropertyMapper {
private final IdMapper delegate;
@ -71,11 +72,29 @@ public class ToOneIdMapper implements PropertyMapper {
data.put(entry.getKey(), entry.getValue());
}
//noinspection SimplifiableConditionalExpression
return nonInsertableFake ? false : !Tools.entitiesEqual(session, referencedEntityName, newObj, oldObj);
return checkModified(session, newObj, oldObj);
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
@Override
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
if (propertyData.isUsingModifiedFlag()) {
data.put(propertyData.getModifiedFlagPropertyName(), checkModified(session, newObj, oldObj));
}
}
@Override
public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyName, Map<String, Object> data) {
if (propertyData.isUsingModifiedFlag()) {
data.put(propertyData.getModifiedFlagPropertyName(), collectionPropertyName.equals(propertyData.getName()));
}
}
private boolean checkModified(SessionImplementor session, Object newObj, Object oldObj) {
//noinspection SimplifiableConditionalExpression
return nonInsertableFake ? false : !Tools.entitiesEqual(session, referencedEntityName, newObj, oldObj);
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
if (obj == null) {
return;

View File

@ -25,6 +25,7 @@ package org.hibernate.envers.event;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
@ -48,6 +49,7 @@ import org.hibernate.persister.collection.AbstractCollectionPersister;
* @author Adam Warski (adam at warski dot org)
* @author Hern<EFBFBD>n Chanfreau
* @author Steve Ebersole
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public abstract class BaseEnversCollectionEventListener extends BaseEnversEventListener {
protected BaseEnversCollectionEventListener(AuditConfiguration enversConfiguration) {
@ -106,6 +108,7 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
new CollectionChangeWorkUnit(
event.getSession(),
event.getAffectedOwnerEntityName(),
referencingPropertyName,
getAuditConfiguration(),
event.getAffectedOwnerIdOrNull(),
event.getAffectedOwnerOrNull()
@ -174,6 +177,7 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(
event.getSession(),
realRelatedEntityName,
rd.getMappedByPropertyName(),
getAuditConfiguration(),
relatedId,
relatedObj
@ -200,6 +204,7 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
new CollectionChangeWorkUnit(
event.getSession(),
collectionEntityName,
referencingPropertyName,
getAuditConfiguration(),
event.getAffectedOwnerIdOrNull(),
event.getAffectedOwnerOrNull()
@ -224,6 +229,10 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
String relatedEntityName = rd.getToEntityName();
IdMapper relatedIdMapper = getAuditConfiguration().getEntCfg().get( relatedEntityName ).getIdMapper();
Set<String> toPropertyNames = getAuditConfiguration().getEntCfg()
.getToPropertyNames(event.getAffectedOwnerEntityName(), rd.getFromPropertyName(), relatedEntityName);
String toPropertyName = toPropertyNames.iterator().next();
for ( PersistentCollectionChangeData changeData : workUnit.getCollectionChanges() ) {
Object relatedObj = changeData.getChangedElement();
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity( relatedObj );
@ -232,6 +241,7 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
new CollectionChangeWorkUnit(
event.getSession(),
event.getSession().bestGuessEntityName(relatedObj),
toPropertyName,
getAuditConfiguration(),
relatedId,
relatedObj

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.event;
import java.io.Serializable;
import java.util.Set;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditConfiguration;
@ -42,6 +43,7 @@ import org.hibernate.proxy.HibernateProxy;
* @author Adam Warski (adam at warski dot org)
* @author Hern<EFBFBD>n Chanfreau
* @author Steve Ebersole
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public abstract class BaseEnversEventListener implements EnversListener {
private AuditConfiguration enversConfiguration;
@ -85,49 +87,41 @@ public abstract class BaseEnversEventListener implements EnversListener {
// We have to generate changes both in the old collection (size decreses) and new collection
// (size increases).
if (newValue != null) {
// relDesc.getToEntityName() doesn't always return the entity name of the value - in case
// of subclasses, this will be root class, no the actual class. So it can't be used here.
String toEntityName;
Serializable id;
if (newValue instanceof HibernateProxy ) {
HibernateProxy hibernateProxy = (HibernateProxy) newValue;
toEntityName = session.bestGuessEntityName(newValue);
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
// We've got to initialize the object from the proxy to later read its state.
newValue = Tools.getTargetFromProxy(session.getFactory(), hibernateProxy);
} else {
toEntityName = session.guessEntityName(newValue);
IdMapper idMapper = enversConfiguration.getEntCfg().get(toEntityName).getIdMapper();
id = (Serializable) idMapper.mapToIdFromEntity(newValue);
}
auditProcess.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, enversConfiguration, id, newValue));
addCollectionChangeWorkUnit(auditProcess, session, entityName, relDesc, newValue);
}
if (oldValue != null) {
String toEntityName;
Serializable id;
if(oldValue instanceof HibernateProxy) {
HibernateProxy hibernateProxy = (HibernateProxy) oldValue;
toEntityName = session.bestGuessEntityName(oldValue);
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
// We've got to initialize the object as we'll read it's state anyway.
oldValue = Tools.getTargetFromProxy(session.getFactory(), hibernateProxy);
} else {
toEntityName = session.guessEntityName(oldValue);
IdMapper idMapper = enversConfiguration.getEntCfg().get(toEntityName).getIdMapper();
id = (Serializable) idMapper.mapToIdFromEntity(oldValue);
}
auditProcess.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, enversConfiguration, id, oldValue));
addCollectionChangeWorkUnit(auditProcess, session, entityName, relDesc, oldValue);
}
}
}
}
}
private void addCollectionChangeWorkUnit(AuditProcess auditProcess, SessionImplementor session,
String fromEntityName, RelationDescription relDesc, Object value) {
// relDesc.getToEntityName() doesn't always return the entity name of the value - in case
// of subclasses, this will be root class, no the actual class. So it can't be used here.
String toEntityName;
Serializable id;
if (value instanceof HibernateProxy) {
HibernateProxy hibernateProxy = (HibernateProxy) value;
toEntityName = session.bestGuessEntityName(value);
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
} else {
toEntityName = session.guessEntityName(value);
IdMapper idMapper = enversConfiguration.getEntCfg().get(toEntityName).getIdMapper();
id = (Serializable) idMapper.mapToIdFromEntity(value);
}
Set<String> toPropertyNames = enversConfiguration.getEntCfg()
.getToPropertyNames(fromEntityName, relDesc.getFromPropertyName(), toEntityName);
String toPropertyName = toPropertyNames.iterator().next();
auditProcess.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName,
toPropertyName, enversConfiguration, id, value));
}
}

View File

@ -31,12 +31,14 @@ import org.hibernate.envers.query.order.AuditOrder;
import org.hibernate.envers.query.order.PropertyAuditOrder;
import org.hibernate.envers.query.projection.AuditProjection;
import org.hibernate.envers.query.projection.PropertyAuditProjection;
import org.hibernate.envers.query.property.ModifiedFlagPropertyName;
import org.hibernate.envers.query.property.PropertyNameGetter;
import org.hibernate.envers.tools.Triple;
/**
* Create restrictions, projections and specify order for a property of an audited entity.
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
@SuppressWarnings({"JavaDoc"})
public class AuditProperty<T> implements AuditProjection {
@ -46,7 +48,15 @@ public class AuditProperty<T> implements AuditProjection {
this.propertyNameGetter = propertyNameGetter;
}
/**
public AuditCriterion hasChanged() {
return new SimpleAuditExpression(new ModifiedFlagPropertyName(propertyNameGetter), true, "=");
}
public AuditCriterion hasNotChanged() {
return new SimpleAuditExpression(new ModifiedFlagPropertyName(propertyNameGetter), false, "=");
}
/**
* Apply an "equal" constraint
*/
public AuditCriterion eq(T value) {

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.query.property;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.configuration.metadata.MetadataTools;
/**
* PropertyNameGetter for modified flags
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class ModifiedFlagPropertyName implements PropertyNameGetter {
private final PropertyNameGetter propertyNameGetter;
public ModifiedFlagPropertyName(PropertyNameGetter propertyNameGetter) {
this.propertyNameGetter = propertyNameGetter;
}
public String get(AuditConfiguration auditCfg) {
return MetadataTools.getModifiedFlagPropertyName(
propertyNameGetter.get(auditCfg),
auditCfg.getGlobalCfg().getModifiedFlagSuffix());
}
}

View File

@ -85,8 +85,9 @@ public class AddWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit
}
public AuditWorkUnit merge(CollectionChangeWorkUnit second) {
return this;
}
second.mergeCollectionModifiedData(data);
return this;
}
public AuditWorkUnit merge(FakeBidirectionalRelationWorkUnit second) {
return FakeBidirectionalRelationWorkUnit.merge(second, this, second.getNestedWorkUnit());

View File

@ -25,22 +25,28 @@ package org.hibernate.envers.synchronization.work;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.Hibernate;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.tools.Tools;
import org.hibernate.proxy.HibernateProxy;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class CollectionChangeWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit {
private final Object entity;
private Object entity;
private final String collectionPropertyName;
private final Map<String, Object> data = new HashMap<String, Object>();
public CollectionChangeWorkUnit(SessionImplementor session, String entityName, AuditConfiguration verCfg,
Serializable id, Object entity) {
public CollectionChangeWorkUnit(SessionImplementor session, String entityName, String collectionPropertyName,
AuditConfiguration verCfg, Serializable id, Object entity) {
super(session, entityName, verCfg, id, RevisionType.MOD);
this.entity = entity;
this.collectionPropertyName = collectionPropertyName;
}
public boolean containsWork() {
@ -48,16 +54,32 @@ public class CollectionChangeWorkUnit extends AbstractAuditWorkUnit implements A
}
public Map<String, Object> generateData(Object revisionData) {
Map<String, Object> data = new HashMap<String, Object>();
fillDataWithId(data, revisionData);
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().mapToMapFromEntity(sessionImplementor,
data, entity, null);
resolveProxyIfNeeded();
Map<String, Object> preGenerateData = new HashMap<String, Object>(data);
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
.mapToMapFromEntity(sessionImplementor, data, entity, null);
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
.mapModifiedFlagsToMapFromEntity(sessionImplementor, data, entity, entity);
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
.mapModifiedFlagsToMapForCollectionChange(collectionPropertyName, data);
data.putAll(preGenerateData);
return data;
}
public AuditWorkUnit merge(AddWorkUnit second) {
private void resolveProxyIfNeeded() {
if (entity instanceof HibernateProxy) {
Tools.getTargetFromProxy(sessionImplementor.getFactory(), (HibernateProxy) entity);
}
}
public void mergeCollectionModifiedData(Map<String, Object> data) {
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
.mapModifiedFlagsToMapForCollectionChange(
collectionPropertyName, data);
}
public AuditWorkUnit merge(AddWorkUnit second) {
return second;
}
@ -70,6 +92,7 @@ public class CollectionChangeWorkUnit extends AbstractAuditWorkUnit implements A
}
public AuditWorkUnit merge(CollectionChangeWorkUnit second) {
second.mergeCollectionModifiedData(data);
return this;
}

View File

@ -61,6 +61,9 @@ public class DelWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit
if (verCfg.getGlobalCfg().isStoreDataAtDelete()) {
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().map(sessionImplementor, data,
propertyNames, state, state);
} else {
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().map(sessionImplementor, data,
propertyNames, null, state);
}
return data;

View File

@ -153,11 +153,15 @@ public class FakeBidirectionalRelationWorkUnit extends AbstractAuditWorkUnit imp
// new owner will in fact be null.
rd.getFakeBidirectionalRelationMapper().mapToMapFromEntity(sessionImplementor, data,
revisionType == RevisionType.DEL ? null : owningEntity, null);
rd.getFakeBidirectionalRelationMapper().mapModifiedFlagsToMapFromEntity(sessionImplementor, data,
revisionType == RevisionType.DEL ? null : owningEntity, null);
// Also mapping the index, if the collection is indexed.
// Also mapping the index, if the collection is indexed.
if (rd.getFakeBidirectionalRelationIndexMapper() != null) {
rd.getFakeBidirectionalRelationIndexMapper().mapToMapFromEntity(sessionImplementor, data,
revisionType == RevisionType.DEL ? null : index, null);
rd.getFakeBidirectionalRelationIndexMapper().mapModifiedFlagsToMapFromEntity(sessionImplementor, data,
revisionType == RevisionType.DEL ? null : index, null);
}
}

View File

@ -41,6 +41,7 @@ public abstract class AbstractOneSessionTest extends AbstractEnversTest {
if (auditStrategy != null && !"".equals(auditStrategy)) {
config.setProperty("org.hibernate.envers.audit_strategy", auditStrategy);
}
addProperties(config);
this.initMappings();
@ -50,6 +51,8 @@ public abstract class AbstractOneSessionTest extends AbstractEnversTest {
protected abstract void initMappings() throws MappingException, URISyntaxException ;
protected void addProperties(Configuration configuration) {}
protected String getHibernateConfigurationFileName(){
return "hibernate.test.session-cfg.xml";
}

View File

@ -0,0 +1,102 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.query.AuditQuery;
import org.hibernate.envers.test.AbstractEntityTest;
import java.util.List;
import java.util.Properties;
/**
* Base test for modified flags feature
*
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public abstract class AbstractModifiedFlagsEntityTest extends AbstractEntityTest {
@Override
public void addConfigurationProperties(Properties configuration) {
super.addConfigurationProperties(configuration);
if (forceModifiedFlags()) {
configuration.setProperty(
GlobalConfiguration.GLOBAL_WITH_MODIFIED_FLAG_PROPERTY, "true");
}
}
public boolean forceModifiedFlags() {
return true;
}
protected List queryForPropertyHasChanged(Class<?> clazz, Object id,
String... propertyNames) {
AuditQuery query = createForRevisionsQuery(clazz, id, false);
addHasChangedProperties(query, propertyNames);
return query.getResultList();
}
protected List queryForPropertyHasChangedWithDeleted(Class<?> clazz, Object id,
String... propertyNames) {
AuditQuery query = createForRevisionsQuery(clazz, id, true);
addHasChangedProperties(query, propertyNames);
return query.getResultList();
}
protected List queryForPropertyHasNotChanged(Class<?> clazz, Object id,
String... propertyNames) {
AuditQuery query = createForRevisionsQuery(clazz, id, false);
addHasNotChangedProperties(query, propertyNames);
return query.getResultList();
}
protected List queryForPropertyHasNotChangedWithDeleted(Class<?> clazz, Object id,
String... propertyNames) {
AuditQuery query = createForRevisionsQuery(clazz, id, true);
addHasNotChangedProperties(query, propertyNames);
return query.getResultList();
}
private void addHasChangedProperties(AuditQuery query,
String[] propertyNames) {
for (String propertyName : propertyNames) {
query.add(AuditEntity.property(propertyName).hasChanged());
}
}
private void addHasNotChangedProperties(AuditQuery query,
String[] propertyNames) {
for (String propertyName : propertyNames) {
query.add(AuditEntity.property(propertyName).hasNotChanged());
}
}
private AuditQuery createForRevisionsQuery(Class<?> clazz, Object id, boolean withDeleted) {
return getAuditReader().createQuery()
.forRevisionsOfEntity(clazz, false, withDeleted)
.add(AuditEntity.id().eq(id));
}
}

View File

@ -0,0 +1,51 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.cfg.Configuration;
import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.test.AbstractOneSessionTest;
/**
* Base test for modified flags feature
*
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public abstract class AbstractModifiedFlagsOneSessionTest extends
AbstractOneSessionTest {
@Override
protected void addProperties(Configuration configuration) {
super.addProperties(configuration);
if (forceModifiedFlags()) {
configuration.setProperty(
GlobalConfiguration.GLOBAL_WITH_MODIFIED_FLAG_PROPERTY, "true");
}
}
public boolean forceModifiedFlags() {
return true;
}
}

View File

@ -0,0 +1,85 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.auditReader.AuditedTestEntity;
import org.hibernate.envers.test.integration.auditReader.NotAuditedTestEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
/**
* A test which checks the correct behavior of AuditReader.isEntityClassAudited(Class entityClass).
*
* @author Hernan Chanfreau
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedAPITest extends AbstractModifiedFlagsEntityTest {
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(AuditedTestEntity.class);
cfg.addAnnotatedClass(NotAuditedTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
em.getTransaction().begin();
AuditedTestEntity ent1 = new AuditedTestEntity(1, "str1");
NotAuditedTestEntity ent2 = new NotAuditedTestEntity(1, "str1");
em.persist(ent1);
em.persist(ent2);
em.getTransaction().commit();
em.getTransaction().begin();
ent1 = em.find(AuditedTestEntity.class, 1);
ent2 = em.find(NotAuditedTestEntity.class, 1);
ent1.setStr1("str2");
ent2.setStr1("str2");
em.getTransaction().commit();
}
@Test
public void testHasChangedHasNotChangedCriteria() throws Exception {
List list = getAuditReader().createQuery().forRevisionsOfEntity(AuditedTestEntity.class, true, true)
.add(AuditEntity.property("str1").hasChanged()).getResultList();
assertEquals(2, list.size());
assertEquals("str1", ((AuditedTestEntity) list.get(0)).getStr1());
assertEquals("str2", ((AuditedTestEntity) list.get(1)).getStr1());
list = getAuditReader().createQuery().forRevisionsOfEntity(AuditedTestEntity.class, true, true)
.add(AuditEntity.property("str1").hasNotChanged()).getResultList();
assertTrue(list.isEmpty());
}
}

View File

@ -0,0 +1,125 @@
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.MappingException;
import org.hibernate.envers.query.AuditEntity;
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.junit.Test;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Hern&aacute;n Chanfreau
* @author Michal Skowronek (mskowr at o2 dot pl)
*
*/
public class HasChangedAuditedManyToManyTest extends AbstractModifiedFlagsOneSessionTest{
private long id_car1;
private long id_pers1;
private long id_pers2;
protected void initMappings() throws MappingException, URISyntaxException {
URL url = Thread.currentThread().getContextClassLoader().getResource("mappings/entityNames/manyToManyAudited/mappings.hbm.xml");
config.addFile(new File(url.toURI()));
}
@Test
@Priority(10)
public void initData() {
initializeSession();
Person pers1 = new Person("Hernan", 28);
Person pers2 = new Person("Leandro", 29);
Person pers3 = new Person("Barba", 32);
Person pers4 = new Person("Camomo", 15);
//REV 1
getSession().getTransaction().begin();
List<Person > owners = new ArrayList<Person>();
owners.add(pers1);
owners.add(pers2);
owners.add(pers3);
Car car1 = new Car(5, owners);
getSession().persist(car1);
getSession().getTransaction().commit();
id_pers1 = pers1.getId();
id_car1 = car1.getId();
id_pers2 = pers2.getId();
owners = new ArrayList<Person>();
owners.add(pers2);
owners.add(pers3);
owners.add(pers4);
Car car2 = new Car(27, owners);
//REV 2
getSession().getTransaction().begin();
Person person1 = (Person)getSession().get("Personaje", id_pers1);
person1.setName("Hernan David");
person1.setAge(40);
getSession().persist(car1);
getSession().persist(car2);
getSession().getTransaction().commit();
}
@Test
public void testHasChangedPerson1() throws Exception {
List list = getAuditReader().createQuery().forRevisionsOfEntity(Person.class, "Personaje", false, false)
.add(AuditEntity.id().eq(id_pers1))
.add(AuditEntity.property("cars").hasChanged())
.getResultList();
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = getAuditReader().createQuery().forRevisionsOfEntity(Person.class, "Personaje", false, false)
.add(AuditEntity.id().eq(id_pers1))
.add(AuditEntity.property("cars").hasNotChanged())
.getResultList();
assertEquals(1, list.size());
assertEquals(makeList(2), extractRevisionNumbers(list));
}
@Test
public void testHasChangedPerson2() throws Exception {
List list = getAuditReader().createQuery().forRevisionsOfEntity(Person.class, "Personaje", false, false)
.add(AuditEntity.id().eq(id_pers2))
.add(AuditEntity.property("cars").hasChanged())
.getResultList();
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = getAuditReader().createQuery().forRevisionsOfEntity(Person.class, "Personaje", false, false)
.add(AuditEntity.id().eq(id_pers2))
.add(AuditEntity.property("cars").hasNotChanged())
.getResultList();
assertEquals(0, list.size());
}
@Test
public void testHasChangedCar1() throws Exception {
List list = getAuditReader().createQuery().forRevisionsOfEntity(Car.class, false, false)
.add(AuditEntity.id().eq(id_car1))
.add(AuditEntity.property("owners").hasChanged())
.getResultList();
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = getAuditReader().createQuery().forRevisionsOfEntity(Car.class, false, false)
.add(AuditEntity.id().eq(id_car1))
.add(AuditEntity.property("owners").hasNotChanged())
.getResultList();
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,125 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.onetoone.bidirectional.BiRefEdEntity;
import org.hibernate.envers.test.integration.onetoone.bidirectional.BiRefIngEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedBidirectional2 extends AbstractModifiedFlagsEntityTest {
private Integer ed1_id;
private Integer ed2_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(BiRefEdEntity.class);
cfg.addAnnotatedClass(BiRefIngEntity.class);
}
@Test
@Priority(10)
public void initData() {
BiRefEdEntity ed1 = new BiRefEdEntity(1, "data_ed_1");
BiRefEdEntity ed2 = new BiRefEdEntity(2, "data_ed_2");
BiRefIngEntity ing1 = new BiRefIngEntity(3, "data_ing_1");
BiRefIngEntity ing2 = new BiRefIngEntity(4, "data_ing_2");
// Revision 1
EntityManager em = getEntityManager();
em.getTransaction().begin();
em.persist(ed1);
em.persist(ed2);
em.getTransaction().commit();
// Revision 2
em.getTransaction().begin();
ed1 = em.find(BiRefEdEntity.class, ed1.getId());
ing1.setReference(ed1);
em.persist(ing1);
em.persist(ing2);
em.getTransaction().commit();
// Revision 3
em.getTransaction().begin();
ed1 = em.find(BiRefEdEntity.class, ed1.getId());
ing1 = em.find(BiRefIngEntity.class, ing1.getId());
ing2 = em.find(BiRefIngEntity.class, ing2.getId());
ing1.setReference(null);
ing2.setReference(ed1);
em.getTransaction().commit();
// Revision 4
em.getTransaction().begin();
ed2 = em.find(BiRefEdEntity.class, ed2.getId());
ing1 = em.find(BiRefIngEntity.class, ing1.getId());
ing2 = em.find(BiRefIngEntity.class, ing2.getId());
ing1.setReference(ed2);
ing2.setReference(null);
em.getTransaction().commit();
//
ed1_id = ed1.getId();
ed2_id = ed2.getId();
}
@Test
public void testHasChanged() throws Exception {
List list = queryForPropertyHasChanged(BiRefEdEntity.class, ed1_id,
"referencing");
assertEquals(3, list.size());
assertEquals(makeList(2, 3, 4), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(BiRefEdEntity.class, ed2_id,
"referencing");
assertEquals(1, list.size());
assertEquals(makeList(4), extractRevisionNumbers(list));
}
}

View File

@ -0,0 +1,99 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.inheritance.joined.ChildEntity;
import org.hibernate.envers.test.integration.inheritance.joined.ParentEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedChildAuditing extends AbstractModifiedFlagsEntityTest {
private Integer id1;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(ChildEntity.class);
cfg.addAnnotatedClass(ParentEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
id1 = 1;
// Rev 1
em.getTransaction().begin();
ChildEntity ce = new ChildEntity(id1, "x", 1l);
em.persist(ce);
em.getTransaction().commit();
// Rev 2
em.getTransaction().begin();
ce = em.find(ChildEntity.class, id1);
ce.setData("y");
ce.setNumber(2l);
em.getTransaction().commit();
}
@Test
public void testChildHasChanged() throws Exception {
List list = queryForPropertyHasChanged(ChildEntity.class, id1, "data");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(ChildEntity.class, id1, "number");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(ChildEntity.class, id1, "data");
assertEquals(0, list.size());
list = queryForPropertyHasNotChanged(ChildEntity.class, id1, "number");
assertEquals(0, list.size());
}
@Test
public void testParentHasChanged() throws Exception {
List list = queryForPropertyHasChanged(ParentEntity.class, id1, "data");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(ParentEntity.class, id1, "data");
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,113 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.inheritance.joined.childrelation.ChildIngEntity;
import org.hibernate.envers.test.integration.inheritance.joined.childrelation.ParentNotIngEntity;
import org.hibernate.envers.test.integration.inheritance.joined.childrelation.ReferencedEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedChildReferencing extends AbstractModifiedFlagsEntityTest {
private Integer re_id1;
private Integer re_id2;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(ChildIngEntity.class);
cfg.addAnnotatedClass(ParentNotIngEntity.class);
cfg.addAnnotatedClass(ReferencedEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
re_id1 = 1;
re_id2 = 10;
Integer c_id = 100;
// Rev 1
em.getTransaction().begin();
ReferencedEntity re1 = new ReferencedEntity(re_id1);
em.persist(re1);
ReferencedEntity re2 = new ReferencedEntity(re_id2);
em.persist(re2);
em.getTransaction().commit();
// Rev 2
em.getTransaction().begin();
re1 = em.find(ReferencedEntity.class, re_id1);
ChildIngEntity cie = new ChildIngEntity(c_id, "y", 1l);
cie.setReferenced(re1);
em.persist(cie);
c_id = cie.getId();
em.getTransaction().commit();
// Rev 3
em.getTransaction().begin();
re2 = em.find(ReferencedEntity.class, re_id2);
cie = em.find(ChildIngEntity.class, c_id);
cie.setReferenced(re2);
em.getTransaction().commit();
}
@Test
public void testReferencedEntityHasChanged() throws Exception {
List list = queryForPropertyHasChanged(ReferencedEntity.class, re_id1, "referencing");
assertEquals(2, list.size());
assertEquals(makeList(2, 3), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(ReferencedEntity.class, re_id1, "referencing");
assertEquals(1, list.size()); // initially referencing collection is null
assertEquals(makeList(1), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(ReferencedEntity.class, re_id2, "referencing");
assertEquals(1, list.size());
assertEquals(makeList(3), extractRevisionNumbers(list));
}
}

View File

@ -0,0 +1,125 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.components.Component1;
import org.hibernate.envers.test.entities.components.Component2;
import org.hibernate.envers.test.entities.components.ComponentTestEntity;
import org.hibernate.envers.test.integration.collection.mapkey.ComponentMapKeyEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedComponentMapKey extends AbstractModifiedFlagsEntityTest {
private Integer cmke_id;
private Integer cte1_id;
private Integer cte2_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(ComponentMapKeyEntity.class);
cfg.addAnnotatedClass(ComponentTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
ComponentMapKeyEntity imke = new ComponentMapKeyEntity();
// Revision 1 (intialy 1 mapping)
em.getTransaction().begin();
ComponentTestEntity cte1 = new ComponentTestEntity(new Component1("x1", "y2"), new Component2("a1", "b2"));
ComponentTestEntity cte2 = new ComponentTestEntity(new Component1("x1", "y2"), new Component2("a1", "b2"));
em.persist(cte1);
em.persist(cte2);
imke.getIdmap().put(cte1.getComp1(), cte1);
em.persist(imke);
em.getTransaction().commit();
// Revision 2 (sse1: adding 1 mapping)
em.getTransaction().begin();
cte2 = em.find(ComponentTestEntity.class, cte2.getId());
imke = em.find(ComponentMapKeyEntity.class, imke.getId());
imke.getIdmap().put(cte2.getComp1(), cte2);
em.getTransaction().commit();
//
cmke_id = imke.getId();
cte1_id = cte1.getId();
cte2_id = cte2.getId();
}
@Test
public void testHasChangedMapEntity() throws Exception {
List list = queryForPropertyHasChanged(ComponentMapKeyEntity.class, cmke_id, "idmap");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(ComponentMapKeyEntity.class,
cmke_id, "idmap");
assertEquals(0, list.size());
}
@Test
public void testHasChangedComponentEntity() throws Exception {
List list = queryForPropertyHasChanged(ComponentTestEntity.class,
cte1_id, "comp1");
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(ComponentTestEntity.class, cte1_id,
"comp1");
assertEquals(0, list.size());
list = queryForPropertyHasChanged(ComponentTestEntity.class, cte2_id, "comp1");
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(ComponentTestEntity.class, cte2_id, "comp1");
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,178 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.QueryException;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.components.Component1;
import org.hibernate.envers.test.entities.components.Component2;
import org.hibernate.envers.test.entities.components.ComponentTestEntity;
import org.hibernate.envers.test.tools.TestTools;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedComponents extends AbstractModifiedFlagsEntityTest {
private Integer id1;
private Integer id2;
private Integer id3;
private Integer id4;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(ComponentTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
// Revision 1
EntityManager em = getEntityManager();
em.getTransaction().begin();
ComponentTestEntity cte1 = new ComponentTestEntity(new Component1("a", "b"), new Component2("x", "y"));
ComponentTestEntity cte2 = new ComponentTestEntity(new Component1("a2", "b2"), new Component2("x2", "y2"));
ComponentTestEntity cte3 = new ComponentTestEntity(new Component1("a3", "b3"), new Component2("x3", "y3"));
ComponentTestEntity cte4 = new ComponentTestEntity(null, null);
em.persist(cte1);
em.persist(cte2);
em.persist(cte3);
em.persist(cte4);
em.getTransaction().commit();
// Revision 2
em = getEntityManager();
em.getTransaction().begin();
cte1 = em.find(ComponentTestEntity.class, cte1.getId());
cte2 = em.find(ComponentTestEntity.class, cte2.getId());
cte3 = em.find(ComponentTestEntity.class, cte3.getId());
cte4 = em.find(ComponentTestEntity.class, cte4.getId());
cte1.setComp1(new Component1("a'", "b'"));
cte2.getComp1().setStr1("a2'");
cte3.getComp2().setStr6("y3'");
cte4.setComp1(new Component1());
cte4.getComp1().setStr1("n");
cte4.setComp2(new Component2());
cte4.getComp2().setStr5("m");
em.getTransaction().commit();
// Revision 3
em = getEntityManager();
em.getTransaction().begin();
cte1 = em.find(ComponentTestEntity.class, cte1.getId());
cte2 = em.find(ComponentTestEntity.class, cte2.getId());
cte3 = em.find(ComponentTestEntity.class, cte3.getId());
cte4 = em.find(ComponentTestEntity.class, cte4.getId());
cte1.setComp2(new Component2("x'", "y'"));
cte3.getComp1().setStr2("b3'");
cte4.setComp1(null);
cte4.setComp2(null);
em.getTransaction().commit();
// Revision 4
em = getEntityManager();
em.getTransaction().begin();
cte2 = em.find(ComponentTestEntity.class, cte2.getId());
em.remove(cte2);
em.getTransaction().commit();
id1 = cte1.getId();
id2 = cte2.getId();
id3 = cte3.getId();
id4 = cte4.getId();
}
@Test
public void testModFlagProperties() {
assertEquals(TestTools.makeSet("comp1_MOD"),
TestTools.extractModProperties(getCfg().getClassMapping(
"org.hibernate.envers.test.entities.components.ComponentTestEntity_AUD")));
}
@Test(expected = QueryException.class)
public void testHasChangedNotAudited() throws Exception {
queryForPropertyHasChanged(ComponentTestEntity.class, id1, "comp2");
}
@Test
public void testHasChangedId1() throws Exception {
List list = queryForPropertyHasChanged(ComponentTestEntity.class, id1, "comp1");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(ComponentTestEntity.class, id1, "comp1");
assertEquals(0, list.size());
}
@Test
public void testHasChangedId2() throws Exception {
List list = queryForPropertyHasChangedWithDeleted(ComponentTestEntity.class, id2, "comp1");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 4), extractRevisionNumbers(list));
list = queryForPropertyHasNotChangedWithDeleted(ComponentTestEntity.class, id2, "comp1");
assertEquals(0, list.size());
}
@Test
public void testHasChangedId3() throws Exception {
List list = queryForPropertyHasChangedWithDeleted(ComponentTestEntity.class, id3, "comp1");
assertEquals(2, list.size());
assertEquals(makeList(1, 3), extractRevisionNumbers(list));
list = queryForPropertyHasNotChangedWithDeleted(ComponentTestEntity.class, id3, "comp1");
assertEquals(0, list.size());
}
@Test
public void testHasChangedId4() throws Exception {
List list = queryForPropertyHasChangedWithDeleted(ComponentTestEntity.class, id4, "comp1");
assertEquals(2, list.size());
assertEquals(makeList(2, 3), extractRevisionNumbers(list));
list = queryForPropertyHasNotChangedWithDeleted(ComponentTestEntity.class, id4, "comp1");
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
}
}

View File

@ -0,0 +1,98 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.customtype.Component;
import org.hibernate.envers.test.entities.customtype.CompositeCustomTypeEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedCompositeCustom extends AbstractModifiedFlagsEntityTest {
private Integer ccte_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(CompositeCustomTypeEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
CompositeCustomTypeEntity ccte = new CompositeCustomTypeEntity();
// Revision 1 (persisting 1 entity)
em.getTransaction().begin();
ccte.setComponent(new Component("a", 1));
em.persist(ccte);
em.getTransaction().commit();
// Revision 2 (changing the component)
em.getTransaction().begin();
ccte = em.find(CompositeCustomTypeEntity.class, ccte.getId());
ccte.getComponent().setProp1("b");
em.getTransaction().commit();
// Revision 3 (replacing the component)
em.getTransaction().begin();
ccte = em.find(CompositeCustomTypeEntity.class, ccte.getId());
ccte.setComponent(new Component("c", 3));
em.getTransaction().commit();
//
ccte_id = ccte.getId();
}
@Test
public void testHasChanged() throws Exception {
List list = queryForPropertyHasChanged(CompositeCustomTypeEntity.class,ccte_id, "component");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 3), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(CompositeCustomTypeEntity.class,ccte_id, "component");
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,260 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.onetomany.detached.DoubleListJoinColumnBidirectionalRefEdEntity1;
import org.hibernate.envers.test.entities.onetomany.detached.DoubleListJoinColumnBidirectionalRefEdEntity2;
import org.hibernate.envers.test.entities.onetomany.detached.DoubleListJoinColumnBidirectionalRefIngEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* Test for a double "fake" bidirectional mapping where one side uses @OneToMany+@JoinColumn
* (and thus owns the relation), and the other uses a @ManyToOne(insertable=false, updatable=false).
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedDoubleJoinColumnBidirectionalList extends AbstractModifiedFlagsEntityTest {
private Integer ed1_1_id;
private Integer ed2_1_id;
private Integer ed1_2_id;
private Integer ed2_2_id;
private Integer ing1_id;
private Integer ing2_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(DoubleListJoinColumnBidirectionalRefIngEntity.class);
cfg.addAnnotatedClass(DoubleListJoinColumnBidirectionalRefEdEntity1.class);
cfg.addAnnotatedClass(DoubleListJoinColumnBidirectionalRefEdEntity2.class);
}
@Test
@Priority(10)
public void createData() {
EntityManager em = getEntityManager();
DoubleListJoinColumnBidirectionalRefEdEntity1 ed1_1 = new DoubleListJoinColumnBidirectionalRefEdEntity1("ed1_1", null);
DoubleListJoinColumnBidirectionalRefEdEntity1 ed1_2 = new DoubleListJoinColumnBidirectionalRefEdEntity1("ed1_2", null);
DoubleListJoinColumnBidirectionalRefEdEntity2 ed2_1 = new DoubleListJoinColumnBidirectionalRefEdEntity2("ed2_1", null);
DoubleListJoinColumnBidirectionalRefEdEntity2 ed2_2 = new DoubleListJoinColumnBidirectionalRefEdEntity2("ed2_2", null);
DoubleListJoinColumnBidirectionalRefIngEntity ing1 = new DoubleListJoinColumnBidirectionalRefIngEntity("coll1");
DoubleListJoinColumnBidirectionalRefIngEntity ing2 = new DoubleListJoinColumnBidirectionalRefIngEntity("coll2");
// Revision 1 (ing1: ed1_1, ed2_1, ing2: ed1_2, ed2_2)
em.getTransaction().begin();
ing1.getReferences1().add(ed1_1);
ing1.getReferences2().add(ed2_1);
ing2.getReferences1().add(ed1_2);
ing2.getReferences2().add(ed2_2);
em.persist(ed1_1);
em.persist(ed1_2);
em.persist(ed2_1);
em.persist(ed2_2);
em.persist(ing1);
em.persist(ing2);
em.getTransaction().commit();
// Revision 2 (ing1: ed1_1, ed1_2, ed2_1, ed2_2)
em.getTransaction().begin();
ing1 = em.find(DoubleListJoinColumnBidirectionalRefIngEntity.class, ing1.getId());
ing2 = em.find(DoubleListJoinColumnBidirectionalRefIngEntity.class, ing2.getId());
ed1_1 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_1.getId());
ed1_2 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_2.getId());
ed2_1 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_1.getId());
ed2_2 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_2.getId());
ing2.getReferences1().clear();
ing2.getReferences2().clear();
ing1.getReferences1().add(ed1_2);
ing1.getReferences2().add(ed2_2);
em.getTransaction().commit();
em.clear();
// Revision 3 (ing1: ed1_1, ed1_2, ed2_1, ed2_2)
em.getTransaction().begin();
ing1 = em.find(DoubleListJoinColumnBidirectionalRefIngEntity.class, ing1.getId());
ing2 = em.find(DoubleListJoinColumnBidirectionalRefIngEntity.class, ing2.getId());
ed1_1 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_1.getId());
ed1_2 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_2.getId());
ed2_1 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_1.getId());
ed2_2 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_2.getId());
ed1_1.setData("ed1_1 bis");
ed2_2.setData("ed2_2 bis");
em.getTransaction().commit();
em.clear();
// Revision 4 (ing1: ed2_2, ing2: ed2_1, ed1_1, ed1_2)
em.getTransaction().begin();
ing1 = em.find(DoubleListJoinColumnBidirectionalRefIngEntity.class, ing1.getId());
ing2 = em.find(DoubleListJoinColumnBidirectionalRefIngEntity.class, ing2.getId());
ed1_1 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_1.getId());
ed1_2 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_2.getId());
ed2_1 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_1.getId());
ed2_2 = em.find(DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_2.getId());
ing1.getReferences1().clear();
ing2.getReferences1().add(ed1_1);
ing2.getReferences1().add(ed1_2);
ing1.getReferences2().remove(ed2_1);
ing2.getReferences2().add(ed2_1);
em.getTransaction().commit();
em.clear();
//
ing1_id = ing1.getId();
ing2_id = ing2.getId();
ed1_1_id = ed1_1.getId();
ed1_2_id = ed1_2.getId();
ed2_1_id = ed2_1.getId();
ed2_2_id = ed2_2.getId();
}
@Test
public void testOwnerHasChanged() throws Exception {
List list = queryForPropertyHasChanged(
DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_1_id,
"owner");
assertEquals(2, list.size());
assertEquals(makeList(1, 4), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(
DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_1_id,
"owner");
assertEquals(1, list.size());
assertEquals(makeList(3), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(
DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_2_id,
"owner");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 4), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(
DoubleListJoinColumnBidirectionalRefEdEntity1.class, ed1_2_id,
"owner");
assertEquals(0, list.size());
}
@Test
public void testOwnerSecEntityHasChanged() throws Exception {
List list = queryForPropertyHasChanged(
DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_1_id,
"owner");
assertEquals(2, list.size());
assertEquals(makeList(1, 4), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(
DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_1_id,
"owner");
assertEquals(0, list.size());
list = queryForPropertyHasChanged(
DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_2_id,
"owner");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(
DoubleListJoinColumnBidirectionalRefEdEntity2.class, ed2_2_id,
"owner");
assertEquals(1, list.size());
assertEquals(makeList(3), extractRevisionNumbers(list));
}
@Test
public void testReferences1HasChanged() throws Exception {
List list = queryForPropertyHasChanged(
DoubleListJoinColumnBidirectionalRefIngEntity.class, ing1_id,
"references1");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 4), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(
DoubleListJoinColumnBidirectionalRefIngEntity.class, ing2_id,
"references1");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 4), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(
DoubleListJoinColumnBidirectionalRefIngEntity.class, ing1_id,
"references1");
assertEquals(0, list.size());
list = queryForPropertyHasNotChanged(
DoubleListJoinColumnBidirectionalRefIngEntity.class, ing2_id,
"references1");
assertEquals(0, list.size());
}
@Test
public void testReferences2HasChanged() throws Exception {
List list = queryForPropertyHasChanged(
DoubleListJoinColumnBidirectionalRefIngEntity.class, ing1_id,
"references2");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 4), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(
DoubleListJoinColumnBidirectionalRefIngEntity.class, ing2_id,
"references2");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 4), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(
DoubleListJoinColumnBidirectionalRefIngEntity.class, ing1_id,
"references2");
assertEquals(0, list.size());
list = queryForPropertyHasNotChanged(
DoubleListJoinColumnBidirectionalRefIngEntity.class, ing2_id,
"references2");
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,114 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.collection.EnumSetEntity;
import org.hibernate.envers.test.entities.collection.EnumSetEntity.E1;
import org.hibernate.envers.test.entities.collection.EnumSetEntity.E2;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedEnumSet extends AbstractModifiedFlagsEntityTest {
private Integer sse1_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(EnumSetEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
EnumSetEntity sse1 = new EnumSetEntity();
// Revision 1 (sse1: initialy 1 element)
em.getTransaction().begin();
sse1.getEnums1().add(E1.X);
sse1.getEnums2().add(E2.A);
em.persist(sse1);
em.getTransaction().commit();
// Revision 2 (sse1: adding 1 element/removing a non-existing element)
em.getTransaction().begin();
sse1 = em.find(EnumSetEntity.class, sse1.getId());
sse1.getEnums1().add(E1.Y);
sse1.getEnums2().remove(E2.B);
em.getTransaction().commit();
// Revision 3 (sse1: removing 1 element/adding an exisiting element)
em.getTransaction().begin();
sse1 = em.find(EnumSetEntity.class, sse1.getId());
sse1.getEnums1().remove(E1.X);
sse1.getEnums2().add(E2.A);
em.getTransaction().commit();
//
sse1_id = sse1.getId();
}
@Test
public void testHasChanged() throws Exception {
List list = queryForPropertyHasChanged(EnumSetEntity.class, sse1_id,
"enums1");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 3), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(EnumSetEntity.class, sse1_id,
"enums2");
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(EnumSetEntity.class, sse1_id,
"enums1");
assertEquals(0, list.size());
list = queryForPropertyHasNotChanged(EnumSetEntity.class, sse1_id,
"enums2");
assertEquals(2, list.size());
assertEquals(makeList(2, 3), extractRevisionNumbers(list));
}
}

View File

@ -0,0 +1,274 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.QueryException;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.entities.components.Component1;
import org.hibernate.envers.test.entities.components.Component2;
import org.hibernate.envers.test.integration.modifiedflags.entities.PartialModifiedFlagsEntity;
import org.hibernate.envers.test.integration.modifiedflags.entities.WithModifiedFlagReferencingEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.Arrays;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedForDefaultNotUsing extends AbstractModifiedFlagsEntityTest {
private static final int entityId = 1;
private static final int refEntityId = 1;
@Override
public boolean forceModifiedFlags() {
return false;
}
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(PartialModifiedFlagsEntity.class);
cfg.addAnnotatedClass(WithModifiedFlagReferencingEntity.class);
cfg.addAnnotatedClass(StrTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
PartialModifiedFlagsEntity entity =
new PartialModifiedFlagsEntity(entityId);
// Revision 1
EntityManager em = getEntityManager();
em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();
// Revision 2
em.getTransaction().begin();
entity.setData("data1");
entity = em.merge(entity);
em.getTransaction().commit();
// Revision 3
em.getTransaction().begin();
entity.setComp1(new Component1("str1", "str2"));
entity = em.merge(entity);
em.getTransaction().commit();
// Revision 4
em.getTransaction().begin();
entity.setComp2(new Component2("str1", "str2"));
entity = em.merge(entity);
em.getTransaction().commit();
// Revision 5
em.getTransaction().begin();
WithModifiedFlagReferencingEntity withModifiedFlagReferencingEntity = new WithModifiedFlagReferencingEntity(refEntityId, "first");
withModifiedFlagReferencingEntity.setReference(entity);
em.persist(withModifiedFlagReferencingEntity);
em.getTransaction().commit();
// Revision 6
em.getTransaction().begin();
withModifiedFlagReferencingEntity = em.find(WithModifiedFlagReferencingEntity.class, refEntityId);
withModifiedFlagReferencingEntity.setReference(null);
withModifiedFlagReferencingEntity.setSecondReference(entity);
em.merge(withModifiedFlagReferencingEntity);
em.getTransaction().commit();
// Revision 7
em.getTransaction().begin();
entity.getStringSet().add("firstElement");
entity.getStringSet().add("secondElement");
entity = em.merge(entity);
em.getTransaction().commit();
// Revision 8
em.getTransaction().begin();
entity.getStringSet().remove("secondElement");
entity.getStringMap().put("someKey", "someValue");
entity = em.merge(entity);
em.getTransaction().commit();
// Revision 9 - main entity doesn't change
em.getTransaction().begin();
StrTestEntity strTestEntity = new StrTestEntity("first");
em.persist(strTestEntity);
em.getTransaction().commit();
// Revision 10
em.getTransaction().begin();
entity.getEntitiesSet().add(strTestEntity);
entity = em.merge(entity);
em.getTransaction().commit();
// Revision 11
em.getTransaction().begin();
entity.getEntitiesSet().remove(strTestEntity);
entity.getEntitiesMap().put("someKey", strTestEntity);
em.merge(entity);
em.getTransaction().commit();
// Revision 12 - main entity doesn't change
em.getTransaction().begin();
strTestEntity.setStr("second");
em.merge(strTestEntity);
em.getTransaction().commit();
}
@Test
public void testRevisionsCounts() {
assertEquals(Arrays.asList((Number) 1, 2, 3, 4, 5, 6, 7, 8, 10, 11),
getAuditReader()
.getRevisions(PartialModifiedFlagsEntity.class,
entityId));
}
@Test
public void testHasChangedData() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "data");
assertEquals(1, list.size());
assertEquals(makeList(2), extractRevisionNumbers(list));
}
@Test
public void testHasChangedComp1() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "comp1");
assertEquals(1, list.size());
assertEquals(makeList(3), extractRevisionNumbers(list));
}
@Test(expected = QueryException.class)
public void testHasChangedComp2() throws Exception {
queryForPropertyHasChanged(PartialModifiedFlagsEntity.class,
entityId, "comp2");
}
@Test
public void testHasChangedReferencing() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "referencing");
assertEquals(2, list.size());
assertEquals(makeList(5, 6), extractRevisionNumbers(list));
}
@Test(expected = QueryException.class)
public void testHasChangedReferencing2() throws Exception {
queryForPropertyHasChanged(PartialModifiedFlagsEntity.class,
entityId, "referencing2");
}
@Test
public void testHasChangedStringSet() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "stringSet");
assertEquals(3, list.size());
assertEquals(makeList(1, 7, 8), extractRevisionNumbers(list));
}
@Test
public void testHasChangedStringMap() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "stringMap");
assertEquals(2, list.size());
assertEquals(makeList(1, 8), extractRevisionNumbers(list));
}
@Test
public void testHasChangedStringSetAndMap() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "stringSet", "stringMap");
assertEquals(2, list.size());
assertEquals(makeList(1, 8), extractRevisionNumbers(list));
}
@Test
public void testHasChangedEntitiesSet() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "entitiesSet");
assertEquals(3, list.size());
assertEquals(makeList(1, 10, 11), extractRevisionNumbers(list));
}
@Test
public void testHasChangedEntitiesMap() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "entitiesMap");
assertEquals(2, list.size());
assertEquals(makeList(1, 11), extractRevisionNumbers(list));
}
@Test
public void testHasChangedEntitiesSetAndMap() throws Exception {
List list = queryForPropertyHasChanged(
PartialModifiedFlagsEntity.class,
entityId, "entitiesSet", "entitiesMap");
assertEquals(2, list.size());
assertEquals(makeList(1, 11), extractRevisionNumbers(list));
}
}

View File

@ -0,0 +1,100 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.integration.collection.mapkey.IdMapKeyEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedIdMapKey extends AbstractModifiedFlagsEntityTest {
private Integer imke_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(IdMapKeyEntity.class);
cfg.addAnnotatedClass(StrTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
IdMapKeyEntity imke = new IdMapKeyEntity();
// Revision 1 (intialy 1 mapping)
em.getTransaction().begin();
StrTestEntity ste1 = new StrTestEntity("x");
StrTestEntity ste2 = new StrTestEntity("y");
em.persist(ste1);
em.persist(ste2);
imke.getIdmap().put(ste1.getId(), ste1);
em.persist(imke);
em.getTransaction().commit();
// Revision 2 (sse1: adding 1 mapping)
em.getTransaction().begin();
ste2 = em.find(StrTestEntity.class, ste2.getId());
imke = em.find(IdMapKeyEntity.class, imke.getId());
imke.getIdmap().put(ste2.getId(), ste2);
em.getTransaction().commit();
//
imke_id = imke.getId();
}
@Test
public void testHasChanged() throws Exception {
List list = queryForPropertyHasChanged(IdMapKeyEntity.class, imke_id,
"idmap");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(IdMapKeyEntity.class, imke_id,
"idmap");
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,104 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.entities.components.relations.ManyToOneComponent;
import org.hibernate.envers.test.entities.components.relations.ManyToOneComponentTestEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedManyToOneInComponent extends AbstractModifiedFlagsEntityTest {
private Integer mtocte_id1;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(ManyToOneComponentTestEntity.class);
cfg.addAnnotatedClass(StrTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
// Revision 1
EntityManager em = getEntityManager();
em.getTransaction().begin();
StrTestEntity ste1 = new StrTestEntity();
ste1.setStr("str1");
StrTestEntity ste2 = new StrTestEntity();
ste2.setStr("str2");
em.persist(ste1);
em.persist(ste2);
em.getTransaction().commit();
// Revision 2
em = getEntityManager();
em.getTransaction().begin();
ManyToOneComponentTestEntity mtocte1 = new ManyToOneComponentTestEntity(new ManyToOneComponent(ste1, "data1"));
em.persist(mtocte1);
em.getTransaction().commit();
// Revision 3
em = getEntityManager();
em.getTransaction().begin();
mtocte1 = em.find(ManyToOneComponentTestEntity.class, mtocte1.getId());
mtocte1.getComp1().setEntity(ste2);
em.getTransaction().commit();
mtocte_id1 = mtocte1.getId();
}
@Test
public void testHasChangedId1() throws Exception {
List list = queryForPropertyHasChanged(ManyToOneComponentTestEntity.class,
mtocte_id1, "comp1");
assertEquals(2, list.size());
assertEquals(makeList(2, 3), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(ManyToOneComponentTestEntity.class,
mtocte_id1, "comp1");
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,106 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.inheritance.joined.notownedrelation.Address;
import org.hibernate.envers.test.integration.inheritance.joined.notownedrelation.Contact;
import org.hibernate.envers.test.integration.inheritance.joined.notownedrelation.PersonalContact;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedNotOwnedBidirectional extends AbstractModifiedFlagsEntityTest {
private Long pc_id;
private Long a1_id;
private Long a2_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(Address.class);
cfg.addAnnotatedClass(Contact.class);
cfg.addAnnotatedClass(PersonalContact.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
pc_id = 1l;
a1_id = 10l;
a2_id = 100l;
// Rev 1
em.getTransaction().begin();
PersonalContact pc = new PersonalContact(pc_id, "e", "f");
Address a1 = new Address(a1_id, "a1");
a1.setContact(pc);
em.persist(pc);
em.persist(a1);
em.getTransaction().commit();
// Rev 2
em.getTransaction().begin();
pc = em.find(PersonalContact.class, pc_id);
Address a2 = new Address(a2_id, "a2");
a2.setContact(pc);
em.persist(a2);
em.getTransaction().commit();
}
@Test
public void testReferencedEntityHasChanged() throws Exception {
List list = queryForPropertyHasChanged(PersonalContact.class, pc_id,
"addresses");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(Address.class, a1_id, "contact");
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(Address.class, a2_id, "contact");
assertEquals(1, list.size());
assertEquals(makeList(2), extractRevisionNumbers(list));
}
}

View File

@ -0,0 +1,110 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.basic.BasicTestEntity1;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedNullProperties extends AbstractModifiedFlagsEntityTest {
private Integer id1;
private Integer id2;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(BasicTestEntity1.class);
}
private Integer addNewEntity(String str, long lng) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
BasicTestEntity1 bte1 = new BasicTestEntity1(str, lng);
em.persist(bte1);
em.getTransaction().commit();
return bte1.getId();
}
private void modifyEntity(Integer id, String str, long lng) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
BasicTestEntity1 bte1 = em.find(BasicTestEntity1.class, id);
bte1.setLong1(lng);
bte1.setStr1(str);
em.getTransaction().commit();
}
@Test
@Priority(10)
public void initData() {
id1 = addNewEntity("x", 1); // rev 1
id2 = addNewEntity(null, 20); // rev 2
modifyEntity(id1, null, 1); // rev 3
modifyEntity(id2, "y2", 20); // rev 4
}
@Test
public void testHasChanged() throws Exception {
List list = queryForPropertyHasChangedWithDeleted(BasicTestEntity1.class,
id1, "str1");
assertEquals(2, list.size());
assertEquals(makeList(1, 3), extractRevisionNumbers(list));
list = queryForPropertyHasChangedWithDeleted(BasicTestEntity1.class,
id1, "long1");
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = queryForPropertyHasChangedWithDeleted(BasicTestEntity1.class,
id2, "str1");
// str1 property was null before insert and after insert so in a way it didn't change - is it a good way to go?
assertEquals(1, list.size());
assertEquals(makeList(4), extractRevisionNumbers(list));
list = queryForPropertyHasChangedWithDeleted(BasicTestEntity1.class,
id2, "long1");
assertEquals(1, list.size());
assertEquals(makeList(2), extractRevisionNumbers(list));
list = getAuditReader().createQuery().forRevisionsOfEntity(BasicTestEntity1.class, false, true)
.add(AuditEntity.property("str1").hasChanged())
.add(AuditEntity.property("long1").hasChanged())
.getResultList();
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
}
}

View File

@ -0,0 +1,105 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.entities.components.relations.OneToManyComponent;
import org.hibernate.envers.test.entities.components.relations.OneToManyComponentTestEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedOneToManyInComponent extends AbstractModifiedFlagsEntityTest {
private Integer otmcte_id1;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(OneToManyComponentTestEntity.class);
cfg.addAnnotatedClass(StrTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
// Revision 1
EntityManager em = getEntityManager();
em.getTransaction().begin();
StrTestEntity ste1 = new StrTestEntity();
ste1.setStr("str1");
StrTestEntity ste2 = new StrTestEntity();
ste2.setStr("str2");
em.persist(ste1);
em.persist(ste2);
em.getTransaction().commit();
// Revision 2
em = getEntityManager();
em.getTransaction().begin();
OneToManyComponentTestEntity otmcte1 = new OneToManyComponentTestEntity(new OneToManyComponent("data1"));
otmcte1.getComp1().getEntities().add(ste1);
em.persist(otmcte1);
em.getTransaction().commit();
// Revision 3
em = getEntityManager();
em.getTransaction().begin();
otmcte1 = em.find(OneToManyComponentTestEntity.class, otmcte1.getId());
otmcte1.getComp1().getEntities().add(ste2);
em.getTransaction().commit();
otmcte_id1 = otmcte1.getId();
}
@Test
public void testHasChangedId1() throws Exception {
List list =
queryForPropertyHasChanged(OneToManyComponentTestEntity.class,
otmcte_id1, "comp1");
assertEquals(2, list.size());
assertEquals(makeList(2, 3), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(OneToManyComponentTestEntity.class,
otmcte_id1, "comp1");
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,127 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.collection.StringMapEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedStringMap extends AbstractModifiedFlagsEntityTest {
private Integer sme1_id;
private Integer sme2_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(StringMapEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
StringMapEntity sme1 = new StringMapEntity();
StringMapEntity sme2 = new StringMapEntity();
// Revision 1 (sme1: initialy empty, sme2: initialy 1 mapping)
em.getTransaction().begin();
sme2.getStrings().put("1", "a");
em.persist(sme1);
em.persist(sme2);
em.getTransaction().commit();
// Revision 2 (sme1: adding 2 mappings, sme2: no changes)
em.getTransaction().begin();
sme1 = em.find(StringMapEntity.class, sme1.getId());
sme2 = em.find(StringMapEntity.class, sme2.getId());
sme1.getStrings().put("1", "a");
sme1.getStrings().put("2", "b");
em.getTransaction().commit();
// Revision 3 (sme1: removing an existing mapping, sme2: replacing a value)
em.getTransaction().begin();
sme1 = em.find(StringMapEntity.class, sme1.getId());
sme2 = em.find(StringMapEntity.class, sme2.getId());
sme1.getStrings().remove("1");
sme2.getStrings().put("1", "b");
em.getTransaction().commit();
// No revision (sme1: removing a non-existing mapping, sme2: replacing with the same value)
em.getTransaction().begin();
sme1 = em.find(StringMapEntity.class, sme1.getId());
sme2 = em.find(StringMapEntity.class, sme2.getId());
sme1.getStrings().remove("3");
sme2.getStrings().put("1", "b");
em.getTransaction().commit();
//
sme1_id = sme1.getId();
sme2_id = sme2.getId();
}
@Test
public void testHasChanged() throws Exception {
List list = queryForPropertyHasChanged(StringMapEntity.class, sme1_id,
"strings");
assertEquals(3, list.size());
assertEquals(makeList(1, 2, 3), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(StringMapEntity.class, sme2_id,
"strings");
assertEquals(2, list.size());
assertEquals(makeList(1, 3), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(StringMapEntity.class, sme1_id,
"strings");
assertEquals(0, list.size());
list = queryForPropertyHasNotChanged(StringMapEntity.class, sme2_id,
"strings");
assertEquals(0, list.size()); // in rev 2 there was no version generated for sme2_id
}
}

View File

@ -0,0 +1,119 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.collection.StringSetEntity;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedStringSet extends AbstractModifiedFlagsEntityTest {
private Integer sse1_id;
private Integer sse2_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(StringSetEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
StringSetEntity sse1 = new StringSetEntity();
StringSetEntity sse2 = new StringSetEntity();
// Revision 1 (sse1: initialy empty, sse2: initialy 2 elements)
em.getTransaction().begin();
sse2.getStrings().add("sse2_string1");
sse2.getStrings().add("sse2_string2");
em.persist(sse1);
em.persist(sse2);
em.getTransaction().commit();
// Revision 2 (sse1: adding 2 elements, sse2: adding an existing element)
em.getTransaction().begin();
sse1 = em.find(StringSetEntity.class, sse1.getId());
sse2 = em.find(StringSetEntity.class, sse2.getId());
sse1.getStrings().add("sse1_string1");
sse1.getStrings().add("sse1_string2");
sse2.getStrings().add("sse2_string1");
em.getTransaction().commit();
// Revision 3 (sse1: removing a non-existing element, sse2: removing one element)
em.getTransaction().begin();
sse1 = em.find(StringSetEntity.class, sse1.getId());
sse2 = em.find(StringSetEntity.class, sse2.getId());
sse1.getStrings().remove("sse1_string3");
sse2.getStrings().remove("sse2_string1");
em.getTransaction().commit();
//
sse1_id = sse1.getId();
sse2_id = sse2.getId();
}
@Test
public void testHasChanged() throws Exception {
List list = queryForPropertyHasChanged(StringSetEntity.class, sse1_id,
"strings");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
list = queryForPropertyHasChanged(StringSetEntity.class, sse2_id,
"strings");
assertEquals(2, list.size());
assertEquals(makeList(1, 3), extractRevisionNumbers(list));
list = queryForPropertyHasNotChanged(StringSetEntity.class, sse1_id,
"strings");
assertEquals(0, list.size());
list = queryForPropertyHasNotChanged(StringSetEntity.class, sse2_id,
"strings");
assertEquals(0, list.size());
}
}

View File

@ -0,0 +1,91 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.QueryException;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.basic.BasicTestEntity2;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class HasChangedUnversionedProperties extends AbstractModifiedFlagsEntityTest {
private Integer id1;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(BasicTestEntity2.class);
}
private Integer addNewEntity(String str1, String str2) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
BasicTestEntity2 bte2 = new BasicTestEntity2(str1, str2);
em.persist(bte2);
em.getTransaction().commit();
return bte2.getId();
}
private void modifyEntity(Integer id, String str1, String str2) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
BasicTestEntity2 bte2 = em.find(BasicTestEntity2.class, id);
bte2.setStr1(str1);
bte2.setStr2(str2);
em.getTransaction().commit();
}
@Test
@Priority(10)
public void initData() {
id1 = addNewEntity("x", "a"); // rev 1
modifyEntity(id1, "x", "a"); // no rev
modifyEntity(id1, "y", "b"); // rev 2
modifyEntity(id1, "y", "c"); // no rev
}
@Test
public void testHasChangedQuery() throws Exception {
List list = queryForPropertyHasChanged(BasicTestEntity2.class,
id1, "str1");
assertEquals(2, list.size());
assertEquals(makeList(1, 2), extractRevisionNumbers(list));
}
@Test(expected = QueryException.class)
public void testExceptionOnHasChangedQuery() throws Exception {
queryForPropertyHasChangedWithDeleted(BasicTestEntity2.class,
id1, "str2");
}
}

View File

@ -0,0 +1,104 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.basic.BasicTestEntity1;
import org.hibernate.envers.test.tools.TestTools;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.Properties;
import static junit.framework.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class ModifiedFlagSuffix extends AbstractModifiedFlagsEntityTest {
private Integer id1;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(BasicTestEntity1.class);
}
@Override
public void addConfigurationProperties(Properties configuration) {
super.addConfigurationProperties(configuration);
configuration
.setProperty(GlobalConfiguration.MODIFIED_FLAG_SUFFIX_PROPERTY,
"_CHANGED");
}
private Integer addNewEntity(String str, long lng) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
BasicTestEntity1 bte1 = new BasicTestEntity1(str, lng);
em.persist(bte1);
em.getTransaction().commit();
return bte1.getId();
}
@Test
@Priority(10)
public void initData() {
id1 = addNewEntity("x", 1); // rev 1
}
@Test
public void testModFlagProperties() {
assertEquals(TestTools.makeSet("str1_CHANGED", "long1_CHANGED"),
TestTools.extractModProperties(getCfg().getClassMapping(
"org.hibernate.envers.test.integration.basic.BasicTestEntity1_AUD"),
"_CHANGED"));
}
@Test
public void testHasChanged() throws Exception {
List list = queryForPropertyHasChangedWithDeleted(BasicTestEntity1.class,
id1, "str1");
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = queryForPropertyHasChangedWithDeleted(BasicTestEntity1.class,
id1, "long1");
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
list = getAuditReader().createQuery().forRevisionsOfEntity(BasicTestEntity1.class, false, true)
.add(AuditEntity.property("str1").hasChanged())
.add(AuditEntity.property("long1").hasChanged())
.getResultList();
assertEquals(1, list.size());
assertEquals(makeList(1), extractRevisionNumbers(list));
}
}

View File

@ -0,0 +1,189 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags.entities;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.entities.components.Component1;
import org.hibernate.envers.test.entities.components.Component2;
import javax.persistence.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
@Entity
@Audited(withModifiedFlag = false)
public class PartialModifiedFlagsEntity {
@Id
private Integer id;
@Audited(withModifiedFlag = true)
private String data;
@Audited(withModifiedFlag = true)
@Embedded
private Component1 comp1;
@Audited(withModifiedFlag = false)
@Embedded
private Component2 comp2;
@Audited(withModifiedFlag = true)
@OneToOne(mappedBy="reference")
private WithModifiedFlagReferencingEntity referencing;
@Audited(withModifiedFlag = false)
@OneToOne(mappedBy="secondReference")
private WithModifiedFlagReferencingEntity referencing2;
@Audited(withModifiedFlag = true)
@ElementCollection
private Set<String> stringSet = new HashSet<String>();
@Audited(withModifiedFlag = true)
@ManyToMany
@CollectionTable(name = "ENTITIESSET")
private Set<StrTestEntity> entitiesSet = new HashSet<StrTestEntity>();
@Audited(withModifiedFlag = true)
@ElementCollection
private Map<String, String> stringMap = new HashMap<String, String>();
@Audited(withModifiedFlag = true)
@ManyToMany
@CollectionTable(name = "ENTITIESMAP")
private Map<String, StrTestEntity> entitiesMap =
new HashMap<String, StrTestEntity>();
public PartialModifiedFlagsEntity() {
}
public PartialModifiedFlagsEntity(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public WithModifiedFlagReferencingEntity getReferencing() {
return referencing;
}
public void setReferencing(WithModifiedFlagReferencingEntity referencing) {
this.referencing = referencing;
}
public WithModifiedFlagReferencingEntity getReferencing2() {
return referencing2;
}
public void setReferencing2(WithModifiedFlagReferencingEntity referencing) {
this.referencing2 = referencing;
}
public Component1 getComp1() {
return comp1;
}
public void setComp1(Component1 comp1) {
this.comp1 = comp1;
}
public Component2 getComp2() {
return comp2;
}
public void setComp2(Component2 comp2) {
this.comp2 = comp2;
}
public Set<String> getStringSet() {
return stringSet;
}
public void setStringSet(Set<String> stringSet) {
this.stringSet = stringSet;
}
public Set<StrTestEntity> getEntitiesSet() {
return entitiesSet;
}
public void setEntitiesSet(Set<StrTestEntity> entitiesSet) {
this.entitiesSet = entitiesSet;
}
public Map<String, String> getStringMap() {
return stringMap;
}
public void setStringMap(Map<String, String> stringMap) {
this.stringMap = stringMap;
}
public Map<String, StrTestEntity> getEntitiesMap() {
return entitiesMap;
}
public void setEntitiesMap(Map<String, StrTestEntity> entitiesMap) {
this.entitiesMap = entitiesMap;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PartialModifiedFlagsEntity)) return false;
PartialModifiedFlagsEntity that = (PartialModifiedFlagsEntity) o;
if (data != null ? !data.equals(that.data) : that.data != null) return false;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
}
public int hashCode() {
int result;
result = (id != null ? id.hashCode() : 0);
result = 31 * result + (data != null ? data.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,107 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.modifiedflags.entities;
import org.hibernate.envers.Audited;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Entity
@Audited(withModifiedFlag = true)
public class WithModifiedFlagReferencingEntity {
@Id
private Integer id;
private String data;
@OneToOne
private PartialModifiedFlagsEntity reference;
@OneToOne
private PartialModifiedFlagsEntity secondReference;
public WithModifiedFlagReferencingEntity() {
}
public WithModifiedFlagReferencingEntity(Integer id, String data) {
this.id = id;
this.data = data;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public PartialModifiedFlagsEntity getReference() {
return reference;
}
public void setReference(PartialModifiedFlagsEntity reference) {
this.reference = reference;
}
public PartialModifiedFlagsEntity getSecondReference() {
return secondReference;
}
public void setSecondReference(PartialModifiedFlagsEntity reference) {
this.secondReference = reference;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof WithModifiedFlagReferencingEntity)) return false;
WithModifiedFlagReferencingEntity that = (WithModifiedFlagReferencingEntity) o;
if (data != null ? !data.equals(that.data) : that.data != null) return false;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
}
public int hashCode() {
int result;
result = (id != null ? id.hashCode() : 0);
result = 31 * result + (data != null ? data.hashCode() : 0);
return result;
}
}

View File

@ -22,9 +22,16 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.tools;
import org.hibernate.envers.DefaultRevisionEntity;
import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -71,4 +78,34 @@ public class TestTools {
return true;
}
public static List<Integer> extractRevisionNumbers(List queryResults) {
List<Integer> result = new ArrayList<Integer>();
for (Object queryResult : queryResults) {
result.add(((DefaultRevisionEntity) ((Object[]) queryResult)[1])
.getId());
}
return result;
}
public static Set<String> extractModProperties(
PersistentClass persistentClass) {
return extractModProperties(persistentClass,
GlobalConfiguration.DEFAULT_MODIFIED_FLAG_SUFFIX);
}
public static Set<String> extractModProperties(
PersistentClass persistentClass, String suffix) {
Set<String> result = new HashSet<String>();
Iterator iterator = persistentClass.getPropertyIterator();
while (iterator.hasNext()) {
Property property = (Property) iterator.next();
String propertyName = property.getName();
if (propertyName.endsWith(suffix)) {
result.add(propertyName);
}
}
return result;
}
}