HHH-6613 - Support for audited @ElementCollection

This commit is contained in:
Lukasz Antoniak 2013-02-28 13:22:14 +01:00
parent 8515ce197a
commit 51a7df596e
57 changed files with 2493 additions and 378 deletions

View File

@ -1306,7 +1306,8 @@ query.add(AuditEntity.relatedId("address").eq(relatedEntityId));]]></programlist
<orderedlist> <orderedlist>
<listitem> <listitem>
<para> <para>
collections of components Bag style collection which identifier column has been defined using
<interfacename>@CollectionId</interfacename> annotation (JIRA ticket HHH-3950).
</para> </para>
</listitem> </listitem>
</orderedlist> </orderedlist>

View File

@ -140,13 +140,13 @@ public final class AuditMetadataGenerator {
any_mapping.add(cloneAndSetupRevisionInfoRelationMapping()); any_mapping.add(cloneAndSetupRevisionInfoRelationMapping());
} }
void addRevisionType(Element any_mapping) { void addRevisionType(Element any_mapping, Element any_mapping_end) {
Element revTypeProperty = MetadataTools.addProperty(any_mapping, verEntCfg.getRevisionTypePropName(), Element revTypeProperty = MetadataTools.addProperty(any_mapping, verEntCfg.getRevisionTypePropName(),
verEntCfg.getRevisionTypePropType(), true, false); verEntCfg.getRevisionTypePropType(), true, false);
revTypeProperty.addAttribute("type", "org.hibernate.envers.entities.RevisionTypeType"); revTypeProperty.addAttribute("type", "org.hibernate.envers.entities.RevisionTypeType");
// Adding the end revision, if appropriate // Adding the end revision, if appropriate
addEndRevision(any_mapping); addEndRevision(any_mapping_end);
} }
private void addEndRevision(Element any_mapping ) { private void addEndRevision(Element any_mapping ) {
@ -377,7 +377,7 @@ public final class AuditMetadataGenerator {
class_mapping.add((Element) idMapper.getXmlMapping().clone()); class_mapping.add((Element) idMapper.getXmlMapping().clone());
// Adding the "revision type" property // Adding the "revision type" property
addRevisionType(class_mapping); addRevisionType(class_mapping, class_mapping);
return Triple.make(class_mapping, propertyMapper, null); return Triple.make(class_mapping, propertyMapper, null);
} }

View File

@ -38,13 +38,18 @@ import org.dom4j.Element;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.envers.ModificationStore; import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.RelationTargetAuditMode; import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.metadata.reader.AuditedPropertiesReader;
import org.hibernate.envers.configuration.metadata.reader.ComponentAuditedPropertiesReader;
import org.hibernate.envers.configuration.metadata.reader.ComponentAuditingData;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData; import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.entities.EntityConfiguration; import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.entities.IdMappingData; import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.PropertyData; import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder; import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
import org.hibernate.envers.entities.mapper.MultiPropertyMapper;
import org.hibernate.envers.entities.mapper.PropertyMapper; import org.hibernate.envers.entities.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.SinglePropertyMapper; import org.hibernate.envers.entities.mapper.SinglePropertyMapper;
import org.hibernate.envers.entities.mapper.id.IdMapper; import org.hibernate.envers.entities.mapper.id.IdMapper;
@ -58,6 +63,7 @@ import org.hibernate.envers.entities.mapper.relation.SortedMapCollectionMapper;
import org.hibernate.envers.entities.mapper.relation.SortedSetCollectionMapper; import org.hibernate.envers.entities.mapper.relation.SortedSetCollectionMapper;
import org.hibernate.envers.entities.mapper.relation.ToOneIdMapper; import org.hibernate.envers.entities.mapper.relation.ToOneIdMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleDummyComponentMapper; import org.hibernate.envers.entities.mapper.relation.component.MiddleDummyComponentMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleEmbeddableComponentMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleMapKeyIdComponentMapper; import org.hibernate.envers.entities.mapper.relation.component.MiddleMapKeyIdComponentMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleMapKeyPropertyComponentMapper; import org.hibernate.envers.entities.mapper.relation.component.MiddleMapKeyPropertyComponentMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleRelatedComponentMapper; import org.hibernate.envers.entities.mapper.relation.component.MiddleRelatedComponentMapper;
@ -75,6 +81,7 @@ import org.hibernate.envers.tools.MappingTools;
import org.hibernate.envers.tools.StringTools; import org.hibernate.envers.tools.StringTools;
import org.hibernate.envers.tools.Tools; import org.hibernate.envers.tools.Tools;
import org.hibernate.mapping.Collection; import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.IndexedCollection; import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.ManyToOne; import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.OneToMany; import org.hibernate.mapping.OneToMany;
@ -83,6 +90,7 @@ import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value; import org.hibernate.mapping.Value;
import org.hibernate.type.BagType; import org.hibernate.type.BagType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.ListType; import org.hibernate.type.ListType;
import org.hibernate.type.ManyToOneType; import org.hibernate.type.ManyToOneType;
import org.hibernate.type.MapType; import org.hibernate.type.MapType;
@ -203,7 +211,7 @@ public final class CollectionMetadataGenerator {
// Generating the query generator - it should read directly from the related entity. // Generating the query generator - it should read directly from the related entity.
RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator(mainGenerator.getGlobalCfg(), RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator(mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(),
referencingIdData, referencedEntityName, referencedIdData); referencingIdData, referencedEntityName, referencedIdData, isEmbeddableElementType());
// Creating common mapper data. // Creating common mapper data.
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData( CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
@ -351,7 +359,7 @@ public final class CollectionMetadataGenerator {
// a query generator to read the raw data collection from the middle table. // a query generator to read the raw data collection from the middle table.
QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(), QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData, mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData,
auditMiddleEntityName); auditMiddleEntityName, isEmbeddableElementType());
// Adding the XML mapping for the referencing entity, if the relation isn't inverse. // Adding the XML mapping for the referencing entity, if the relation isn't inverse.
if (middleEntityXml != null) { if (middleEntityXml != null) {
@ -463,6 +471,41 @@ public final class CollectionMetadataGenerator {
return new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData), return new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData),
queryGeneratorBuilder.getCurrentIndex()); queryGeneratorBuilder.getCurrentIndex());
} else if ( type instanceof ComponentType ) {
// Collection of embeddable elements.
final Component component = (Component) value;
final MiddleEmbeddableComponentMapper componentMapper = new MiddleEmbeddableComponentMapper( new MultiPropertyMapper(), component.getComponentClassName() );
final Element parentXmlMapping = xmlMapping.getParent();
final ComponentAuditingData auditData = new ComponentAuditingData();
final ReflectionManager reflectionManager = mainGenerator.getCfg().getReflectionManager();
new ComponentAuditedPropertiesReader(
ModificationStore.FULL,
new AuditedPropertiesReader.ComponentPropertiesSource( reflectionManager, component ),
auditData, mainGenerator.getGlobalCfg(), reflectionManager, ""
).read();
// Emulating first pass.
for ( String auditedPropertyName : auditData.getPropertyNames() ) {
PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData( auditedPropertyName );
mainGenerator.addValue(
parentXmlMapping, component.getProperty( auditedPropertyName ).getValue(), componentMapper,
prefix, xmlMappingData, nestedAuditingData, true, true, true
);
}
// Emulating second pass so that the relations can be mapped too.
for ( String auditedPropertyName : auditData.getPropertyNames() ) {
PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData( auditedPropertyName );
mainGenerator.addValue(
parentXmlMapping, component.getProperty( auditedPropertyName ).getValue(),
componentMapper, referencingEntityName, xmlMappingData, nestedAuditingData,
true, false, true
);
}
return new MiddleComponentData( componentMapper, 0 );
} else { } else {
// Last but one parameter: collection components are always insertable // Last but one parameter: collection components are always insertable
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping, boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
@ -483,33 +526,36 @@ public final class CollectionMetadataGenerator {
private void addMapper(CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData, private void addMapper(CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) { MiddleComponentData indexComponentData) {
Type type = propertyValue.getType(); Type type = propertyValue.getType();
boolean embeddableElementType = isEmbeddableElementType();
if (type instanceof SortedSetType) { if (type instanceof SortedSetType) {
currentMapper.addComposite(propertyAuditingData.getPropertyData(), currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new SortedSetCollectionMapper(commonCollectionMapperData, new SortedSetCollectionMapper(commonCollectionMapperData,
TreeSet.class, SortedSetProxy.class, elementComponentData, propertyValue.getComparator())); TreeSet.class, SortedSetProxy.class, elementComponentData, propertyValue.getComparator(),
embeddableElementType));
} else if (type instanceof SetType) { } else if (type instanceof SetType) {
currentMapper.addComposite(propertyAuditingData.getPropertyData(), currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<Set>(commonCollectionMapperData, new BasicCollectionMapper<Set>(commonCollectionMapperData,
HashSet.class, SetProxy.class, elementComponentData)); HashSet.class, SetProxy.class, elementComponentData, embeddableElementType));
} else if (type instanceof SortedMapType) { } else if (type instanceof SortedMapType) {
// Indexed collection, so <code>indexComponentData</code> is not null. // Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(), currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new SortedMapCollectionMapper(commonCollectionMapperData, new SortedMapCollectionMapper(commonCollectionMapperData,
TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData, propertyValue.getComparator())); TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData, propertyValue.getComparator(),
embeddableElementType));
} else if (type instanceof MapType) { } else if (type instanceof MapType) {
// Indexed collection, so <code>indexComponentData</code> is not null. // Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(), currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new MapCollectionMapper<Map>(commonCollectionMapperData, new MapCollectionMapper<Map>(commonCollectionMapperData,
HashMap.class, MapProxy.class, elementComponentData, indexComponentData)); HashMap.class, MapProxy.class, elementComponentData, indexComponentData, embeddableElementType));
} else if (type instanceof BagType) { } else if (type instanceof BagType) {
currentMapper.addComposite(propertyAuditingData.getPropertyData(), currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<List>(commonCollectionMapperData, new BasicCollectionMapper<List>(commonCollectionMapperData,
ArrayList.class, ListProxy.class, elementComponentData)); ArrayList.class, ListProxy.class, elementComponentData, embeddableElementType));
} else if (type instanceof ListType) { } else if (type instanceof ListType) {
// Indexed collection, so <code>indexComponentData</code> is not null. // Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(), currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new ListCollectionMapper(commonCollectionMapperData, new ListCollectionMapper(commonCollectionMapperData,
elementComponentData, indexComponentData)); elementComponentData, indexComponentData, embeddableElementType));
} else { } else {
mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName); mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
} }
@ -546,12 +592,19 @@ public final class CollectionMetadataGenerator {
mainGenerator.addRevisionInfoRelation(middleEntityXmlId); mainGenerator.addRevisionInfoRelation(middleEntityXmlId);
// Adding the revision type property to the entity xml. // Adding the revision type property to the entity xml.
mainGenerator.addRevisionType(middleEntityXml); mainGenerator.addRevisionType(isEmbeddableElementType() ? middleEntityXmlId : middleEntityXml, middleEntityXml);
// All other properties should also be part of the primary key of the middle entity. // All other properties should also be part of the primary key of the middle entity.
return middleEntityXmlId; return middleEntityXmlId;
} }
/**
* Checks if the collection element is of {@link ComponentType} type.
*/
private boolean isEmbeddableElementType() {
return propertyValue.getElement().getType() instanceof ComponentType;
}
private String getMappedBy(Collection collectionValue) { private String getMappedBy(Collection collectionValue) {
PersistentClass referencedClass = null; PersistentClass referencedClass = null;
if (collectionValue.getElement() instanceof OneToMany) { if (collectionValue.getElement() instanceof OneToMany) {

View File

@ -49,15 +49,17 @@ public final class QueryGeneratorBuilder {
private final MiddleIdData referencingIdData; private final MiddleIdData referencingIdData;
private final String auditMiddleEntityName; private final String auditMiddleEntityName;
private final List<MiddleIdData> idDatas; private final List<MiddleIdData> idDatas;
private final boolean revisionTypeInId;
QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg, QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy, AuditStrategy auditStrategy, MiddleIdData referencingIdData, String auditMiddleEntityName,
MiddleIdData referencingIdData, String auditMiddleEntityName) { boolean revisionTypeInId) {
this.globalCfg = globalCfg; this.globalCfg = globalCfg;
this.verEntCfg = verEntCfg; this.verEntCfg = verEntCfg;
this.auditStrategy = auditStrategy; this.auditStrategy = auditStrategy;
this.referencingIdData = referencingIdData; this.referencingIdData = referencingIdData;
this.auditMiddleEntityName = auditMiddleEntityName; this.auditMiddleEntityName = auditMiddleEntityName;
this.revisionTypeInId = revisionTypeInId;
idDatas = new ArrayList<MiddleIdData>(); idDatas = new ArrayList<MiddleIdData>();
} }
@ -69,14 +71,14 @@ public final class QueryGeneratorBuilder {
RelationQueryGenerator build(MiddleComponentData... componentDatas) { RelationQueryGenerator build(MiddleComponentData... componentDatas) {
if (idDatas.size() == 0) { if (idDatas.size() == 0) {
return new OneEntityQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData, return new OneEntityQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
componentDatas); revisionTypeInId, componentDatas);
} else if (idDatas.size() == 1) { } else if (idDatas.size() == 1) {
if (idDatas.get(0).isAudited()) { if (idDatas.get(0).isAudited()) {
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData, return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
idDatas.get(0), componentDatas); idDatas.get(0), revisionTypeInId, componentDatas);
} else { } else {
return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData, return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
idDatas.get(0), componentDatas); idDatas.get(0), revisionTypeInId, componentDatas);
} }
} else if (idDatas.size() == 2) { } else if (idDatas.size() == 2) {
// All entities must be audited. // All entities must be audited.
@ -85,7 +87,7 @@ public final class QueryGeneratorBuilder {
} }
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData, return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
idDatas.get(0), idDatas.get(1), componentDatas); idDatas.get(0), idDatas.get(1), revisionTypeInId, componentDatas);
} else { } else {
throw new IllegalStateException("Illegal number of related entities."); throw new IllegalStateException("Illegal number of related entities.");
} }

View File

@ -319,7 +319,7 @@ public class AuditedPropertiesReader {
// Marking component properties as placed directly in class (not inside another component). // Marking component properties as placed directly in class (not inside another component).
componentData.setBeanName(null); componentData.setBeanName(null);
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( propertyValue ); PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( reflectionManager, propertyValue );
AuditedPropertiesReader audPropReader = new AuditedPropertiesReader( AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager, ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName) propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName)
@ -338,7 +338,7 @@ public class AuditedPropertiesReader {
allClassAudited); allClassAudited);
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
propertyValue reflectionManager, propertyValue
); );
ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader( ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
@ -541,11 +541,11 @@ public class AuditedPropertiesReader {
public Class<? extends Annotation> annotationType() { return this.getClass(); } public Class<? extends Annotation> annotationType() { return this.getClass(); }
}; };
private class ComponentPropertiesSource implements PersistentPropertiesSource { public static class ComponentPropertiesSource implements PersistentPropertiesSource {
private final XClass xclass; private final XClass xclass;
private final Component component; private final Component component;
private ComponentPropertiesSource(Component component) { public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
try { try {
this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass()); this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass());
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {

View File

@ -24,6 +24,7 @@
*/ */
package org.hibernate.envers.configuration.metadata.reader; package org.hibernate.envers.configuration.metadata.reader;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static org.hibernate.envers.tools.Tools.newHashMap; import static org.hibernate.envers.tools.Tools.newHashMap;
@ -53,5 +54,9 @@ public class ComponentAuditingData extends PropertyAuditingData implements Audit
public boolean contains(String propertyName) { public boolean contains(String propertyName) {
return properties.containsKey(propertyName); return properties.containsKey(propertyName);
} }
public Set<String> getPropertyNames() {
return properties.keySet();
}
} }

View File

@ -25,11 +25,9 @@ package org.hibernate.envers.entities;
import org.hibernate.envers.configuration.AuditConfiguration; import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.mapper.id.IdMapper; import org.hibernate.envers.entities.mapper.id.IdMapper;
import org.hibernate.envers.entities.mapper.id.MultipleIdMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.ToOneDelegateSessionImplementor; import org.hibernate.envers.entities.mapper.relation.lazy.ToOneDelegateSessionImplementor;
import org.hibernate.envers.exception.AuditException; import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.reader.AuditReaderImplementor; import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.LazyInitializer;
@ -149,4 +147,12 @@ public class EntityInstantiator {
addTo.add(createInstanceFromVersionsEntity(entityName, versionsEntity, revision)); addTo.add(createInstanceFromVersionsEntity(entityName, versionsEntity, revision));
} }
} }
public AuditConfiguration getAuditConfiguration() {
return verCfg;
}
public AuditReaderImplementor getAuditReaderImplementor() {
return versionsReader;
}
} }

View File

@ -130,11 +130,13 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
} }
} }
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl, PersistentCollection newColl,
Serializable oldColl, Serializable oldColl, Serializable id) {
Serializable id) { return delegate.mapCollectionChanges(session, referencingPropertyName, newColl, oldColl, id);
return delegate.mapCollectionChanges(referencingPropertyName, newColl, oldColl, id);
} }
public Map<PropertyData, PropertyMapper> getProperties() {
return delegate.getProperties();
}
} }

View File

@ -22,6 +22,9 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.entities.mapper; package org.hibernate.envers.entities.mapper;
import java.util.Map;
import org.hibernate.envers.entities.PropertyData; import org.hibernate.envers.entities.PropertyData;
/** /**
@ -30,4 +33,5 @@ import org.hibernate.envers.entities.PropertyData;
public interface CompositeMapperBuilder extends SimpleMapperBuilder { public interface CompositeMapperBuilder extends SimpleMapperBuilder {
public CompositeMapperBuilder addComponent(PropertyData propertyData, String componentClassName); public CompositeMapperBuilder addComponent(PropertyData propertyData, String componentClassName);
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper); public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
public Map<PropertyData, PropertyMapper> getProperties();
} }

View File

@ -171,14 +171,14 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
} }
} }
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
PersistentCollection newColl, String referencingPropertyName,
Serializable oldColl, PersistentCollection newColl,
Serializable id) { Serializable oldColl, Serializable id) {
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(referencingPropertyName); Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(referencingPropertyName);
PropertyMapper mapper = pair.getFirst(); PropertyMapper mapper = pair.getFirst();
if (mapper != null) { if (mapper != null) {
return mapper.mapCollectionChanges(pair.getSecond(), newColl, oldColl, id); return mapper.mapCollectionChanges(session, pair.getSecond(), newColl, oldColl, id);
} else { } else {
return null; return null;
} }

View File

@ -59,14 +59,15 @@ public interface PropertyMapper {
AuditReaderImplementor versionsReader, Number revision); AuditReaderImplementor versionsReader, Number revision);
/** /**
* Maps collection changes * Maps collection changes.
* @param session The current session.
* @param referencingPropertyName Name of the field, which holds the collection in the entity. * @param referencingPropertyName Name of the field, which holds the collection in the entity.
* @param newColl New collection, after updates. * @param newColl New collection, after updates.
* @param oldColl Old collection, before updates. * @param oldColl Old collection, before updates.
* @param id Id of the object owning the collection. * @param id Id of the object owning the collection.
* @return List of changes that need to be performed on the persistent store. * @return List of changes that need to be performed on the persistent store.
*/ */
List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName, List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl, PersistentCollection newColl,
Serializable oldColl, Serializable id); Serializable oldColl, Serializable id);

View File

@ -115,10 +115,10 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
} }
} }
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor sessionImplementor,
String referencingPropertyName,
PersistentCollection newColl, PersistentCollection newColl,
Serializable oldColl, Serializable oldColl, Serializable id) {
Serializable id) {
return null; return null;
} }

View File

@ -23,6 +23,7 @@
*/ */
package org.hibernate.envers.entities.mapper; package org.hibernate.envers.entities.mapper;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -78,15 +79,14 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
main.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision); main.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
} }
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl, PersistentCollection newColl,
Serializable oldColl, Serializable oldColl, Serializable id) {
Serializable id) {
List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges( List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
referencingPropertyName, newColl, oldColl, id); session, referencingPropertyName, newColl, oldColl, id);
List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges( List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges(
referencingPropertyName, newColl, oldColl, id); session, referencingPropertyName, newColl, oldColl, id);
if (parentCollectionChanges == null) { if (parentCollectionChanges == null) {
return mainCollectionChanges; return mainCollectionChanges;
@ -109,4 +109,11 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
public void add(PropertyData propertyData) { public void add(PropertyData propertyData) {
main.add(propertyData); main.add(propertyData);
} }
public Map<PropertyData, PropertyMapper> getProperties() {
final Map<PropertyData, PropertyMapper> joinedProperties = new HashMap<PropertyData, PropertyMapper>();
joinedProperties.putAll(parentMapper.getProperties());
joinedProperties.putAll(main.getProperties());
return joinedProperties;
}
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.entities.mapper.relation; package org.hibernate.envers.entities.mapper.relation;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -54,13 +55,16 @@ import org.hibernate.property.Setter;
public abstract class AbstractCollectionMapper<T> implements PropertyMapper { public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
protected final CommonCollectionMapperData commonCollectionMapperData; protected final CommonCollectionMapperData commonCollectionMapperData;
protected final Class<? extends T> collectionClass; protected final Class<? extends T> collectionClass;
protected final boolean revisionTypeInId;
private final Constructor<? extends T> proxyConstructor; private final Constructor<? extends T> proxyConstructor;
protected AbstractCollectionMapper(CommonCollectionMapperData commonCollectionMapperData, protected AbstractCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass) { Class<? extends T> collectionClass, Class<? extends T> proxyClass,
boolean revisionTypeInId) {
this.commonCollectionMapperData = commonCollectionMapperData; this.commonCollectionMapperData = commonCollectionMapperData;
this.collectionClass = collectionClass; this.collectionClass = collectionClass;
this.revisionTypeInId = revisionTypeInId;
try { try {
proxyConstructor = proxyClass.getConstructor(Initializor.class); proxyConstructor = proxyClass.getConstructor(Initializor.class);
@ -74,13 +78,14 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
/** /**
* Maps the changed collection element to the given map. * Maps the changed collection element to the given map.
* @param idData Map to which composite-id data should be added.
* @param data Where to map the data. * @param data Where to map the data.
* @param changed The changed collection element to map. * @param changed The changed collection element to map.
*/ */
protected abstract void mapToMapFromObject(Map<String, Object> data, Object changed); protected abstract void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed);
private void addCollectionChanges(List<PersistentCollectionChangeData> collectionChanges, Set<Object> changed, private void addCollectionChanges(SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges,
RevisionType revisionType, Serializable id) { Set<Object> changed, RevisionType revisionType, Serializable id) {
for (Object changedObj : changed) { for (Object changedObj : changed) {
Map<String, Object> entityData = new HashMap<String, Object>(); Map<String, Object> entityData = new HashMap<String, Object>();
Map<String, Object> originalId = new HashMap<String, Object>(); Map<String, Object> originalId = new HashMap<String, Object>();
@ -92,18 +97,18 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId(originalId, id); commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId(originalId, id);
// Mapping collection element and index (if present). // Mapping collection element and index (if present).
mapToMapFromObject(originalId, changedObj); mapToMapFromObject(session, originalId, entityData, changedObj);
entityData.put(commonCollectionMapperData.getVerEntCfg().getRevisionTypePropName(), revisionType); (revisionTypeInId ? originalId : entityData).put(commonCollectionMapperData.getVerEntCfg().getRevisionTypePropName(), revisionType);
} }
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
String referencingPropertyName,
PersistentCollection newColl, PersistentCollection newColl,
Serializable oldColl, Serializable id) { Serializable oldColl, Serializable id) {
if (!commonCollectionMapperData.getCollectionReferencingPropertyData().getName() if (!commonCollectionMapperData.getCollectionReferencingPropertyData().getName().equals(referencingPropertyName)) {
.equals(referencingPropertyName)) {
return null; return null;
} }
@ -119,14 +124,14 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
// removeAll in AbstractSet has an implementation that is hashcode-change sensitive (as opposed to addAll). // removeAll in AbstractSet has an implementation that is hashcode-change sensitive (as opposed to addAll).
if (oldColl != null) { added.removeAll(new HashSet(oldCollection)); } if (oldColl != null) { added.removeAll(new HashSet(oldCollection)); }
addCollectionChanges(collectionChanges, added, RevisionType.ADD, id); addCollectionChanges(session, collectionChanges, added, RevisionType.ADD, id);
Set<Object> deleted = new HashSet<Object>(); Set<Object> deleted = new HashSet<Object>();
if (oldColl != null) { deleted.addAll(oldCollection); } if (oldColl != null) { deleted.addAll(oldCollection); }
// The same as above - re-hashing new collection. // The same as above - re-hashing new collection.
if (newColl != null) { deleted.removeAll(new HashSet(newCollection)); } if (newColl != null) { deleted.removeAll(new HashSet(newCollection)); }
addCollectionChanges(collectionChanges, deleted, RevisionType.DEL, id); addCollectionChanges(session, collectionChanges, deleted, RevisionType.DEL, id);
return collectionChanges; return collectionChanges;
} }
@ -146,7 +151,7 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
} else if (isFromNullToEmptyOrFromEmptyToNull((PersistentCollection) newObj, (Serializable) oldObj)) { } else if (isFromNullToEmptyOrFromEmptyToNull((PersistentCollection) newObj, (Serializable) oldObj)) {
data.put(propertyData.getModifiedFlagPropertyName(), true); data.put(propertyData.getModifiedFlagPropertyName(), true);
} else { } else {
List<PersistentCollectionChangeData> changes = mapCollectionChanges( List<PersistentCollectionChangeData> changes = mapCollectionChanges(session,
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(), commonCollectionMapperData.getCollectionReferencingPropertyData().getName(),
(PersistentCollection) newObj, (Serializable) oldObj, null); (PersistentCollection) newObj, (Serializable) oldObj, null);
data.put(propertyData.getModifiedFlagPropertyName(), !changes.isEmpty()); data.put(propertyData.getModifiedFlagPropertyName(), !changes.isEmpty());

View File

@ -42,9 +42,9 @@ public abstract class AbstractToOneMapper implements PropertyMapper {
} }
@Override @Override
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName, public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl, PersistentCollection newColl, Serializable oldColl,
Serializable oldColl, Serializable id) { Serializable id) {
return null; return null;
} }

View File

@ -28,6 +28,7 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditConfiguration; import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.mapper.PropertyMapper; import org.hibernate.envers.entities.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.BasicCollectionInitializor; import org.hibernate.envers.entities.mapper.relation.lazy.initializor.BasicCollectionInitializor;
@ -42,8 +43,8 @@ public class BasicCollectionMapper<T extends Collection> extends AbstractCollect
public BasicCollectionMapper(CommonCollectionMapperData commonCollectionMapperData, public BasicCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass, Class<? extends T> collectionClass, Class<? extends T> proxyClass,
MiddleComponentData elementComponentData) { MiddleComponentData elementComponentData, boolean revisionTypeInId) {
super(commonCollectionMapperData, collectionClass, proxyClass); super(commonCollectionMapperData, collectionClass, proxyClass, revisionTypeInId);
this.elementComponentData = elementComponentData; this.elementComponentData = elementComponentData;
} }
@ -67,7 +68,7 @@ public class BasicCollectionMapper<T extends Collection> extends AbstractCollect
} }
} }
protected void mapToMapFromObject(Map<String, Object> data, Object changed) { protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
elementComponentData.getComponentMapper().mapToMapFromObject(data, changed); elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, changed);
} }
} }

View File

@ -28,6 +28,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditConfiguration; import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.mapper.PropertyMapper; import org.hibernate.envers.entities.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor; import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
@ -45,8 +46,9 @@ public final class ListCollectionMapper extends AbstractCollectionMapper<List> i
private final MiddleComponentData indexComponentData; private final MiddleComponentData indexComponentData;
public ListCollectionMapper(CommonCollectionMapperData commonCollectionMapperData, public ListCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData) { MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
super(commonCollectionMapperData, List.class, ListProxy.class); boolean revisionTypeInId) {
super(commonCollectionMapperData, List.class, ListProxy.class, revisionTypeInId);
this.elementComponentData = elementComponentData; this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData; this.indexComponentData = indexComponentData;
} }
@ -76,9 +78,9 @@ public final class ListCollectionMapper extends AbstractCollectionMapper<List> i
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
protected void mapToMapFromObject(Map<String, Object> data, Object changed) { protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
Pair<Integer, Object> indexValuePair = (Pair<Integer, Object>) changed; Pair<Integer, Object> indexValuePair = (Pair<Integer, Object>) changed;
elementComponentData.getComponentMapper().mapToMapFromObject(data, indexValuePair.getSecond()); elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, indexValuePair.getSecond());
indexComponentData.getComponentMapper().mapToMapFromObject(data, indexValuePair.getFirst()); indexComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, indexValuePair.getFirst());
} }
} }

View File

@ -28,6 +28,7 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditConfiguration; import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.mapper.PropertyMapper; import org.hibernate.envers.entities.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor; import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
@ -43,8 +44,9 @@ public class MapCollectionMapper<T extends Map> extends AbstractCollectionMapper
public MapCollectionMapper(CommonCollectionMapperData commonCollectionMapperData, public MapCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass, Class<? extends T> collectionClass, Class<? extends T> proxyClass,
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData) { MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
super(commonCollectionMapperData, collectionClass, proxyClass); boolean revisionTypeInId) {
super(commonCollectionMapperData, collectionClass, proxyClass, revisionTypeInId);
this.elementComponentData = elementComponentData; this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData; this.indexComponentData = indexComponentData;
} }
@ -71,8 +73,8 @@ public class MapCollectionMapper<T extends Map> extends AbstractCollectionMapper
} }
} }
protected void mapToMapFromObject(Map<String, Object> data, Object changed) { protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
elementComponentData.getComponentMapper().mapToMapFromObject(data, ((Map.Entry) changed).getValue()); elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, ((Map.Entry) changed).getValue());
indexComponentData.getComponentMapper().mapToMapFromObject(data, ((Map.Entry) changed).getKey()); indexComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, ((Map.Entry) changed).getKey());
} }
} }

View File

@ -39,8 +39,9 @@ public final class SortedMapCollectionMapper extends MapCollectionMapper<SortedM
public SortedMapCollectionMapper(CommonCollectionMapperData commonCollectionMapperData, public SortedMapCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends SortedMap> collectionClass, Class<? extends SortedMap> proxyClass, Class<? extends SortedMap> collectionClass, Class<? extends SortedMap> proxyClass,
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData, Comparator comparator) { MiddleComponentData elementComponentData, MiddleComponentData indexComponentData, Comparator comparator,
super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, indexComponentData); boolean revisionTypeInId) {
super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, indexComponentData, revisionTypeInId);
this.comparator = comparator; this.comparator = comparator;
} }

View File

@ -39,8 +39,9 @@ public final class SortedSetCollectionMapper extends BasicCollectionMapper<Sorte
public SortedSetCollectionMapper(CommonCollectionMapperData commonCollectionMapperData, public SortedSetCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends SortedSet> collectionClass, Class<? extends SortedSet> proxyClass, Class<? extends SortedSet> collectionClass, Class<? extends SortedSet> proxyClass,
MiddleComponentData elementComponentData, Comparator comparator) { MiddleComponentData elementComponentData, Comparator comparator,
super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData); boolean revisionTypeInId) {
super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, revisionTypeInId);
this.comparator = comparator; this.comparator = comparator;
} }

View File

@ -34,6 +34,7 @@ import org.hibernate.envers.entities.mapper.id.IdMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.ToOneDelegateSessionImplementor; import org.hibernate.envers.entities.mapper.relation.lazy.ToOneDelegateSessionImplementor;
import org.hibernate.envers.reader.AuditReaderImplementor; import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.envers.tools.Tools; import org.hibernate.envers.tools.Tools;
import org.hibernate.envers.tools.query.Parameters;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
@ -105,4 +106,8 @@ public class ToOneIdMapper extends AbstractToOneMapper {
setPropertyValue(obj, value); setPropertyValue(obj, value);
} }
public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
delegate.addIdsEqualToQuery( parameters, prefix1, delegate, prefix2 );
}
} }

View File

@ -22,8 +22,12 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.entities.mapper.relation.component; package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map;
import java.util.Map;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator; import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters; import org.hibernate.envers.tools.query.Parameters;
@ -45,18 +49,22 @@ public interface MiddleComponentMapper {
/** /**
* Maps from an object to the object's map representation (for an entity - only its id). * Maps from an object to the object's map representation (for an entity - only its id).
* @param session The current session.
* @param idData Map to which composite-id data should be added.
* @param data Map to which data should be added. * @param data Map to which data should be added.
* @param obj Object to map from. * @param obj Object to map from.
*/ */
void mapToMapFromObject(Map<String, Object> data, Object obj); void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj);
/** /**
* Adds query statements, which contains restrictions, which express the property that part of the middle * Adds query statements, which contains restrictions, which express the property that part of the middle
* entity with alias prefix1, is equal to part of the middle entity with alias prefix2 (the entity is the same). * entity with alias prefix1, is equal to part of the middle entity with alias prefix2 (the entity is the same).
* The part is the component's representation in the middle entity. * The part is the component's representation in the middle entity.
* @param parameters Parameters, to which to add the statements. * @param parameters Parameters, to which to add the statements.
* @param idPrefix1 First alias of the entity + prefix + id to add to the properties.
* @param prefix1 First alias of the entity + prefix to add to the properties. * @param prefix1 First alias of the entity + prefix to add to the properties.
* @param idPrefix2 Second alias of the entity + prefix + id to add to the properties.
* @param prefix2 Second alias of the entity + prefix to add to the properties. * @param prefix2 Second alias of the entity + prefix to add to the properties.
*/ */
void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2); void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2);
} }

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component; package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map; import java.util.Map;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator; import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters; import org.hibernate.envers.tools.query.Parameters;
@ -36,9 +37,9 @@ public final class MiddleDummyComponentMapper implements MiddleComponentMapper {
return null; return null;
} }
public void mapToMapFromObject(Map<String, Object> data, Object obj) { public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
} }
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) { public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
} }
} }

View File

@ -0,0 +1,115 @@
/*
* 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.entities.mapper.relation.component;
import java.util.Map;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
import org.hibernate.envers.entities.mapper.MultiPropertyMapper;
import org.hibernate.envers.entities.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.ToOneIdMapper;
import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.tools.query.Parameters;
import org.hibernate.internal.util.ReflectHelper;
/**
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
public class MiddleEmbeddableComponentMapper implements MiddleComponentMapper, CompositeMapperBuilder {
private final MultiPropertyMapper delegate;
private final Class componentClass;
public MiddleEmbeddableComponentMapper(MultiPropertyMapper delegate, String componentClassName) {
this.delegate = delegate;
try {
componentClass = Thread.currentThread().getContextClassLoader().loadClass( componentClassName );
}
catch ( Exception e ) {
throw new AuditException( e );
}
}
@Override
public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<String, Object> data, Object dataObject, Number revision) {
try {
final Object componentInstance = dataObject != null ? dataObject : ReflectHelper.getDefaultConstructor( componentClass ).newInstance();
delegate.mapToEntityFromMap(
entityInstantiator.getAuditConfiguration(), componentInstance, data, null,
entityInstantiator.getAuditReaderImplementor(), revision
);
return componentInstance;
}
catch ( Exception e ) {
throw new AuditException( e );
}
}
@Override
public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
delegate.mapToMapFromEntity( session, data, obj, obj );
}
@Override
public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
addMiddleEqualToQuery( delegate, parameters, idPrefix1, prefix1, idPrefix2, prefix2 );
}
protected void addMiddleEqualToQuery(CompositeMapperBuilder compositeMapper, Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
for ( final Map.Entry<PropertyData, PropertyMapper> entry : compositeMapper.getProperties().entrySet() ) {
final String propertyName = entry.getKey().getName();
final PropertyMapper nestedMapper = entry.getValue();
if ( nestedMapper instanceof CompositeMapperBuilder ) {
addMiddleEqualToQuery( (CompositeMapperBuilder) nestedMapper, parameters, idPrefix1, prefix1, idPrefix2, prefix2 );
}
else if ( nestedMapper instanceof ToOneIdMapper ) {
( (ToOneIdMapper) nestedMapper ).addMiddleEqualToQuery( parameters, idPrefix1, prefix1, idPrefix2, prefix2 );
}
else {
parameters.addWhere( prefix1 + '.' + propertyName, false, "=", prefix2 + '.' + propertyName, false );
}
}
}
@Override
public CompositeMapperBuilder addComponent(PropertyData propertyData, String componentClassName) {
return delegate.addComponent( propertyData, componentClassName );
}
@Override
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper) {
delegate.addComposite( propertyData, propertyMapper );
}
@Override
public void add(PropertyData propertyData) {
delegate.add( propertyData );
}
public Map<PropertyData, PropertyMapper> getProperties() {
return delegate.getProperties();
}
}

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component; package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map; import java.util.Map;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditEntitiesConfiguration; import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
import org.hibernate.envers.entities.EntityInstantiator; import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.entities.mapper.id.IdMapper; import org.hibernate.envers.entities.mapper.id.IdMapper;
@ -49,11 +50,11 @@ public final class MiddleMapKeyIdComponentMapper implements MiddleComponentMappe
return relatedIdMapper.mapToIdFromMap((Map) data.get(verEntCfg.getOriginalIdPropName())); return relatedIdMapper.mapToIdFromMap((Map) data.get(verEntCfg.getOriginalIdPropName()));
} }
public void mapToMapFromObject(Map<String, Object> data, Object obj) { public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
// Doing nothing. // Doing nothing.
} }
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) { public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
// Doing nothing. // Doing nothing.
} }
} }

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component; package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map; import java.util.Map;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator; import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters; import org.hibernate.envers.tools.query.Parameters;
import org.hibernate.envers.tools.reflection.ReflectionTools; import org.hibernate.envers.tools.reflection.ReflectionTools;
@ -49,11 +50,11 @@ public class MiddleMapKeyPropertyComponentMapper implements MiddleComponentMappe
return ReflectionTools.getGetter(dataObject.getClass(), propertyName, accessType).get(dataObject); return ReflectionTools.getGetter(dataObject.getClass(), propertyName, accessType).get(dataObject);
} }
public void mapToMapFromObject(Map<String, Object> data, Object obj) { public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
// Doing nothing. // Doing nothing.
} }
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) { public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
// Doing nothing. // Doing nothing.
} }
} }

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component; package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map; import java.util.Map;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator; import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.entities.mapper.relation.MiddleIdData; import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
import org.hibernate.envers.tools.query.Parameters; import org.hibernate.envers.tools.query.Parameters;
@ -43,11 +44,11 @@ public final class MiddleRelatedComponentMapper implements MiddleComponentMapper
return entityInstantiator.createInstanceFromVersionsEntity(relatedIdData.getEntityName(), data, revision); return entityInstantiator.createInstanceFromVersionsEntity(relatedIdData.getEntityName(), data, revision);
} }
public void mapToMapFromObject(Map<String, Object> data, Object obj) { public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
relatedIdData.getPrefixedMapper().mapToMapFromEntity(data, obj); relatedIdData.getPrefixedMapper().mapToMapFromEntity(idData, obj);
} }
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) { public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
relatedIdData.getPrefixedMapper().addIdsEqualToQuery(parameters, prefix1, prefix2); relatedIdData.getPrefixedMapper().addIdsEqualToQuery(parameters, idPrefix1, idPrefix2);
} }
} }

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component; package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map; import java.util.Map;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditEntitiesConfiguration; import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
import org.hibernate.envers.entities.EntityInstantiator; import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters; import org.hibernate.envers.tools.query.Parameters;
@ -46,11 +47,11 @@ public final class MiddleSimpleComponentMapper implements MiddleComponentMapper
return ((Map<String, Object>) data.get(verEntCfg.getOriginalIdPropName())).get(propertyName); return ((Map<String, Object>) data.get(verEntCfg.getOriginalIdPropName())).get(propertyName);
} }
public void mapToMapFromObject(Map<String, Object> data, Object obj) { public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
data.put(propertyName, obj); idData.put(propertyName, obj);
} }
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) { public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
parameters.addWhere(prefix1 + "." + propertyName, false, "=", prefix2 + "." + propertyName, false); parameters.addWhere(idPrefix1 + "." + propertyName, false, "=", idPrefix2 + "." + propertyName, false);
} }
} }

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component; package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map; import java.util.Map;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator; import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters; import org.hibernate.envers.tools.query.Parameters;
@ -45,11 +46,11 @@ public final class MiddleStraightComponentMapper implements MiddleComponentMappe
return data.get(propertyName); return data.get(propertyName);
} }
public void mapToMapFromObject(Map<String, Object> data, Object obj) { public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
data.put(propertyName, obj); idData.put(propertyName, obj);
} }
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) { public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
throw new UnsupportedOperationException("Cannot use this mapper with a middle table!"); throw new UnsupportedOperationException("Cannot use this mapper with a middle table!");
} }
} }

View File

@ -0,0 +1,70 @@
/*
* 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.entities.mapper.relation.query;
import org.hibernate.Query;
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
import org.hibernate.envers.reader.AuditReaderImplementor;
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.REVISION_PARAMETER;
/**
* Base class for implementers of {@code RelationQueryGenerator} contract.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public abstract class AbstractRelationQueryGenerator implements RelationQueryGenerator {
protected final AuditEntitiesConfiguration verEntCfg;
protected final MiddleIdData referencingIdData;
protected final boolean revisionTypeInId;
protected AbstractRelationQueryGenerator(AuditEntitiesConfiguration verEntCfg, MiddleIdData referencingIdData,
boolean revisionTypeInId) {
this.verEntCfg = verEntCfg;
this.referencingIdData = referencingIdData;
this.revisionTypeInId = revisionTypeInId;
}
protected abstract String getQueryString();
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) {
Query query = versionsReader.getSession().createQuery( getQueryString() );
query.setParameter( REVISION_PARAMETER, revision );
query.setParameter( DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL );
for ( QueryParameterData paramData : referencingIdData.getPrefixedMapper().mapToQueryParametersFromId( primaryKey ) ) {
paramData.setParameterValue( query );
}
return query;
}
protected String getRevisionTypePath() {
return revisionTypeInId
? verEntCfg.getOriginalIdPropName() + "." + verEntCfg.getRevisionTypePropName()
: verEntCfg.getRevisionTypePropName();
}
}

View File

@ -45,15 +45,15 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
* Selects data from an audit entity. * Selects data from an audit entity.
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class OneAuditEntityQueryGenerator implements RelationQueryGenerator { public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGenerator {
private final String queryString; private final String queryString;
private final MiddleIdData referencingIdData;
public OneAuditEntityQueryGenerator(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg, public OneAuditEntityQueryGenerator(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy, AuditStrategy auditStrategy,
MiddleIdData referencingIdData, MiddleIdData referencingIdData,
String referencedEntityName, MiddleIdData referencedIdData) { String referencedEntityName, MiddleIdData referencedIdData,
this.referencingIdData = referencingIdData; boolean revisionTypeInId) {
super( verEntCfg, referencingIdData, revisionTypeInId );
/* /*
* The query that we need to create: * The query that we need to create:
@ -93,21 +93,15 @@ public final class OneAuditEntityQueryGenerator implements RelationQueryGenerato
revisionPropertyPath, originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR); revisionPropertyPath, originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR);
// e.revision_type != DEL // e.revision_type != DEL
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), false, "!=", DEL_REVISION_TYPE_PARAMETER); rootParameters.addWhereWithNamedParam(getRevisionTypePath(), false, "!=", DEL_REVISION_TYPE_PARAMETER);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap()); qb.build(sb, Collections.<String, Object>emptyMap());
queryString = sb.toString(); queryString = sb.toString();
} }
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) { @Override
Query query = versionsReader.getSession().createQuery(queryString); protected String getQueryString() {
query.setParameter(REVISION_PARAMETER, revision); return queryString;
query.setParameter(DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL); }
for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
paramData.setParameterValue(query);
}
return query;
}
} }

View File

@ -44,16 +44,16 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
* Selects data from a relation middle-table only. * Selects data from a relation middle-table only.
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class OneEntityQueryGenerator implements RelationQueryGenerator { public final class OneEntityQueryGenerator extends AbstractRelationQueryGenerator {
private final String queryString; private final String queryString;
private final MiddleIdData referencingIdData;
public OneEntityQueryGenerator(AuditEntitiesConfiguration verEntCfg, public OneEntityQueryGenerator(AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy, AuditStrategy auditStrategy,
String versionsMiddleEntityName, String versionsMiddleEntityName,
MiddleIdData referencingIdData, MiddleIdData referencingIdData,
boolean revisionTypeInId,
MiddleComponentData... componentDatas) { MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData; super( verEntCfg, referencingIdData, revisionTypeInId );
/* /*
* The query that we need to create: * The query that we need to create:
@ -90,25 +90,19 @@ public final class OneEntityQueryGenerator implements RelationQueryGenerator {
// (with ee association at revision :revision) // (with ee association at revision :revision)
// --> based on auditStrategy (see above) // --> based on auditStrategy (see above)
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath, auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName, verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas); eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
// ee.revision_type != DEL // ee.revision_type != DEL
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", DEL_REVISION_TYPE_PARAMETER); rootParameters.addWhereWithNamedParam(getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap()); qb.build(sb, Collections.<String, Object>emptyMap());
queryString = sb.toString(); queryString = sb.toString();
} }
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) { @Override
Query query = versionsReader.getSession().createQuery(queryString); protected String getQueryString() {
query.setParameter(REVISION_PARAMETER, revision); return queryString;
query.setParameter(DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL); }
for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
paramData.setParameterValue(query);
}
return query;
}
} }

View File

@ -49,9 +49,8 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
* Selects data from a relation middle-table and a two related versions entity. * Selects data from a relation middle-table and a two related versions entity.
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class ThreeEntityQueryGenerator implements RelationQueryGenerator { public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenerator {
private final String queryString; private final String queryString;
private final MiddleIdData referencingIdData;
public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg, public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg,
AuditEntitiesConfiguration verEntCfg, AuditEntitiesConfiguration verEntCfg,
@ -60,8 +59,9 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
MiddleIdData referencingIdData, MiddleIdData referencingIdData,
MiddleIdData referencedIdData, MiddleIdData referencedIdData,
MiddleIdData indexIdData, MiddleIdData indexIdData,
boolean revisionTypeInId,
MiddleComponentData... componentDatas) { MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData; super( verEntCfg, referencingIdData, revisionTypeInId );
/* /*
* The query that we need to create: * The query that we need to create:
@ -157,28 +157,23 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
// --> based on auditStrategy (see above) // --> based on auditStrategy (see above)
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath, auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName, verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas); eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
// ee.revision_type != DEL // ee.revision_type != DEL
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", DEL_REVISION_TYPE_PARAMETER); String revisionTypePropName = getRevisionTypePath();
rootParameters.addWhereWithNamedParam(revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER);
// e.revision_type != DEL // e.revision_type != DEL
rootParameters.addWhereWithNamedParam(REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionTypePropName(), false, "!=", DEL_REVISION_TYPE_PARAMETER); rootParameters.addWhereWithNamedParam(REFERENCED_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER);
// f.revision_type != DEL // f.revision_type != DEL
rootParameters.addWhereWithNamedParam(INDEX_ENTITY_ALIAS + "." + verEntCfg.getRevisionTypePropName(), false, "!=", DEL_REVISION_TYPE_PARAMETER); rootParameters.addWhereWithNamedParam(INDEX_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap()); qb.build(sb, Collections.<String, Object>emptyMap());
queryString = sb.toString(); queryString = sb.toString();
} }
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) { @Override
Query query = versionsReader.getSession().createQuery(queryString); protected String getQueryString() {
query.setParameter(REVISION_PARAMETER, revision); return queryString;
query.setParameter(DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL); }
for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
paramData.setParameterValue(query);
}
return query;
}
} }

View File

@ -45,16 +45,16 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
* Selects data from a relation middle-table and a related non-audited entity. * Selects data from a relation middle-table and a related non-audited entity.
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGenerator { public final class TwoEntityOneAuditedQueryGenerator extends AbstractRelationQueryGenerator {
private final String queryString; private final String queryString;
private final MiddleIdData referencingIdData;
public TwoEntityOneAuditedQueryGenerator(AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy, public TwoEntityOneAuditedQueryGenerator(AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
String versionsMiddleEntityName, String versionsMiddleEntityName,
MiddleIdData referencingIdData, MiddleIdData referencingIdData,
MiddleIdData referencedIdData, MiddleIdData referencedIdData,
boolean revisionTypeInId,
MiddleComponentData... componentDatas) { MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData; super( verEntCfg, referencingIdData, revisionTypeInId );
/* /*
* The query that we need to create: * The query that we need to create:
@ -99,24 +99,18 @@ public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGen
// --> based on auditStrategy (see above) // --> based on auditStrategy (see above)
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath, auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName, verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName,
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas); eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
// ee.revision_type != DEL // ee.revision_type != DEL
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", DEL_REVISION_TYPE_PARAMETER); rootParameters.addWhereWithNamedParam(getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap()); qb.build(sb, Collections.<String, Object>emptyMap());
queryString = sb.toString(); queryString = sb.toString();
} }
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) { @Override
Query query = versionsReader.getSession().createQuery(queryString); protected String getQueryString() {
query.setParameter(REVISION_PARAMETER, revision); return queryString;
query.setParameter(DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL); }
for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
paramData.setParameterValue(query);
}
return query;
}
} }

View File

@ -47,9 +47,8 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
* Selects data from a relation middle-table and a related versions entity. * Selects data from a relation middle-table and a related versions entity.
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public final class TwoEntityQueryGenerator implements RelationQueryGenerator { public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerator {
private final String queryString; private final String queryString;
private final MiddleIdData referencingIdData;
public TwoEntityQueryGenerator(GlobalConfiguration globalCfg, public TwoEntityQueryGenerator(GlobalConfiguration globalCfg,
AuditEntitiesConfiguration verEntCfg, AuditEntitiesConfiguration verEntCfg,
@ -57,8 +56,9 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
String versionsMiddleEntityName, String versionsMiddleEntityName,
MiddleIdData referencingIdData, MiddleIdData referencingIdData,
MiddleIdData referencedIdData, MiddleIdData referencedIdData,
boolean revisionTypeInId,
MiddleComponentData... componentDatas) { MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData; super( verEntCfg, referencingIdData, revisionTypeInId );
/* /*
* The query that we need to create: * The query that we need to create:
@ -118,26 +118,21 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
// --> based on auditStrategy (see above) // --> based on auditStrategy (see above)
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath, auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName, verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas); eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
// ee.revision_type != DEL // ee.revision_type != DEL
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", DEL_REVISION_TYPE_PARAMETER); String revisionTypePropName = getRevisionTypePath();
rootParameters.addWhereWithNamedParam(revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER);
// e.revision_type != DEL // e.revision_type != DEL
rootParameters.addWhereWithNamedParam(REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionTypePropName(), false, "!=", DEL_REVISION_TYPE_PARAMETER); rootParameters.addWhereWithNamedParam(REFERENCED_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap()); qb.build(sb, Collections.<String, Object>emptyMap());
queryString = sb.toString(); queryString = sb.toString();
} }
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) { @Override
Query query = versionsReader.getSession().createQuery(queryString); protected String getQueryString() {
query.setParameter(REVISION_PARAMETER, revision); return queryString;
query.setParameter(DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL); }
for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
paramData.setParameterValue(query);
}
return query;
}
} }

View File

@ -156,7 +156,7 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
.getEntCfg() .getEntCfg()
.get( collectionEntityName ) .get( collectionEntityName )
.getPropertyMapper() .getPropertyMapper()
.mapCollectionChanges( referencingPropertyName, newColl, oldColl, event.getAffectedOwnerIdOrNull() ); .mapCollectionChanges( event.getSession(), referencingPropertyName, newColl, oldColl, event.getAffectedOwnerIdOrNull() );
// Getting the id mapper for the related entity, as the work units generated will corrspond to the related // Getting the id mapper for the related entity, as the work units generated will corrspond to the related
// entities. // entities.

View File

@ -1,99 +1,104 @@
package org.hibernate.envers.strategy; package org.hibernate.envers.strategy;
import java.io.Serializable;
import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.envers.configuration.AuditConfiguration; import org.hibernate.Session;
import org.hibernate.envers.configuration.GlobalConfiguration; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData; import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData; import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.entities.mapper.relation.MiddleIdData; import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
import org.hibernate.envers.tools.query.QueryBuilder; import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
/** import org.hibernate.envers.tools.query.QueryBuilder;
* Behaviours of different audit strategy for populating audit data.
* /**
* @author Stephanie Pau * Behaviours of different audit strategy for populating audit data.
* @author Adam Warski (adam at warski dot org) *
*/ * @author Stephanie Pau
public interface AuditStrategy { * @author Adam Warski (adam at warski dot org)
/** */
* Perform the persistence of audited data for regular entities. public interface AuditStrategy {
* /**
* @param session Session, which can be used to persist the data. * Perform the persistence of audited data for regular entities.
* @param entityName Name of the entity, in which the audited change happens *
* @param auditCfg Audit configuration * @param session Session, which can be used to persist the data.
* @param id Id of the entity. * @param entityName Name of the entity, in which the audited change happens
* @param data Audit data to persist * @param auditCfg Audit configuration
* @param revision Current revision data * @param id Id of the entity.
*/ * @param data Audit data to persist
void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data, * @param revision Current revision data
Object revision); */
void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
/** Object revision);
* Perform the persistence of audited data for collection ("middle") entities.
* /**
* @param session Session, which can be used to persist the data. * Perform the persistence of audited data for collection ("middle") entities.
* @param auditCfg Audit configuration *
* @param persistentCollectionChangeData Collection change data to be persisted. * @param session Session, which can be used to persist the data.
* @param revision Current revision data * @param entityName Name of the entity, in which the audited change happens.
*/ * @param propertyName The name of the property holding the {@link PersistentCollection}.
void performCollectionChange(Session session, AuditConfiguration auditCfg, * @param auditCfg Audit configuration
PersistentCollectionChangeData persistentCollectionChangeData, Object revision); * @param persistentCollectionChangeData Collection change data to be persisted.
* @param revision Current revision data
*/
/** void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a two-entity relation. PersistentCollectionChangeData persistentCollectionChangeData, Object revision);
* This WHERE clause depends on the AuditStrategy, as follows:
* <ul>
* <li>For {@link DefaultAuditStrategy} a subquery is created: /**
* <p><code>e.revision = (SELECT max(...) ...)</code></p> * Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a two-entity relation.
* </li> * This WHERE clause depends on the AuditStrategy, as follows:
* <li>for {@link ValidityAuditStrategy} the revision-end column is used: * <ul>
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p> * <li>For {@link DefaultAuditStrategy} a subquery is created:
* </li> * <p><code>e.revision = (SELECT max(...) ...)</code></p>
* </ul> * </li>
* * <li>for {@link ValidityAuditStrategy} the revision-end column is used:
* @param globalCfg the {@link GlobalConfiguration} * <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated * </li>
* @param revisionProperty property of the revision column * </ul>
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy}) *
* @param addAlias {@code boolean} indicator if a left alias is needed * @param globalCfg the {@link GlobalConfiguration}
* @param idData id-information for the two-entity relation (only used for {@link DefaultAuditStrategy}) * @param rootQueryBuilder the {@link QueryBuilder} that will be updated
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy}) * @param revisionProperty property of the revision column
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy}) * @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
* @param alias1 an alias used for subquery (only used for {@link ValidityAuditStrategy}) * @param addAlias {@code boolean} indicator if a left alias is needed
* @param alias2 an alias used for subquery (only used for {@link ValidityAuditStrategy}) * @param idData id-information for the two-entity relation (only used for {@link DefaultAuditStrategy})
*/ * @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, * @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData, * @param alias1 an alias used for subquery (only used for {@link ValidityAuditStrategy})
String revisionPropertyPath, String originalIdPropertyName, String alias1, String alias2); * @param alias2 an alias used for subquery (only used for {@link ValidityAuditStrategy})
*/
/** void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a middle-entity String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData,
* association. This WHERE clause depends on the AuditStrategy, as follows: String revisionPropertyPath, String originalIdPropertyName, String alias1, String alias2);
* <ul>
* <li>For {@link DefaultAuditStrategy} a subquery is created: /**
* <p><code>e.revision = (SELECT max(...) ...)</code></p> * Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a middle-entity
* </li> * association. This WHERE clause depends on the AuditStrategy, as follows:
* <li>for {@link ValidityAuditStrategy} the revision-end column is used: * <ul>
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p> * <li>For {@link DefaultAuditStrategy} a subquery is created:
* </li> * <p><code>e.revision = (SELECT max(...) ...)</code></p>
* </ul> * </li>
* * <li>for {@link ValidityAuditStrategy} the revision-end column is used:
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated * <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
* @param revisionProperty property of the revision column * </li>
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy}) * </ul>
* @param addAlias {@code boolean} indicator if a left alias is needed *
* @param referencingIdData id-information for the middle-entity association (only used for {@link DefaultAuditStrategy}) * @param rootQueryBuilder the {@link QueryBuilder} that will be updated
* @param versionsMiddleEntityName name of the middle-entity * @param revisionProperty property of the revision column
* @param eeOriginalIdPropertyPath name of the id property (only used for {@link ValidityAuditStrategy}) * @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy}) * @param addAlias {@code boolean} indicator if a left alias is needed
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy}) * @param referencingIdData id-information for the middle-entity association (only used for {@link DefaultAuditStrategy})
* @param componentDatas information about the middle-entity relation * @param versionsMiddleEntityName name of the middle-entity
*/ * @param eeOriginalIdPropertyPath name of the id property (only used for {@link ValidityAuditStrategy})
void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty, * @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, * @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath, * @param alias1 an alias used for subqueries (only used for {@link DefaultAuditStrategy})
String originalIdPropertyName, MiddleComponentData... componentDatas); * @param componentDatas information about the middle-entity relation
*/
} void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas);
}

View File

@ -1,90 +1,90 @@
package org.hibernate.envers.strategy; package org.hibernate.envers.strategy;
import java.io.Serializable; import java.io.Serializable;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.envers.configuration.AuditConfiguration; import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.configuration.GlobalConfiguration; import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData; import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData; import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
import org.hibernate.envers.entities.mapper.relation.MiddleIdData; import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
import org.hibernate.envers.synchronization.SessionCacheCleaner; import org.hibernate.envers.synchronization.SessionCacheCleaner;
import org.hibernate.envers.tools.query.Parameters; import org.hibernate.envers.tools.query.Parameters;
import org.hibernate.envers.tools.query.QueryBuilder; import org.hibernate.envers.tools.query.QueryBuilder;
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS_DEF_AUD_STR; import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS_DEF_AUD_STR;
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.REVISION_PARAMETER; import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.REVISION_PARAMETER;
/** /**
* Default strategy is to simply persist the audit data. * Default strategy is to simply persist the audit data.
* *
* @author Adam Warski * @author Adam Warski
* @author Stephanie Pau * @author Stephanie Pau
*/ */
public class DefaultAuditStrategy implements AuditStrategy { public class DefaultAuditStrategy implements AuditStrategy {
private final SessionCacheCleaner sessionCacheCleaner; private final SessionCacheCleaner sessionCacheCleaner;
public DefaultAuditStrategy() { public DefaultAuditStrategy() {
sessionCacheCleaner = new SessionCacheCleaner(); sessionCacheCleaner = new SessionCacheCleaner();
} }
public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data, public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
Object revision) { Object revision) {
session.save(auditCfg.getAuditEntCfg().getAuditEntityName(entityName), data); session.save(auditCfg.getAuditEntCfg().getAuditEntityName(entityName), data);
sessionCacheCleaner.scheduleAuditDataRemoval(session, data); sessionCacheCleaner.scheduleAuditDataRemoval(session, data);
} }
public void performCollectionChange(Session session, AuditConfiguration auditCfg, public void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) { PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData()); session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
sessionCacheCleaner.scheduleAuditDataRemoval(session, persistentCollectionChangeData.getData()); sessionCacheCleaner.scheduleAuditDataRemoval(session, persistentCollectionChangeData.getData());
} }
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, String revisionProperty, public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, String revisionProperty,
String revisionEndProperty, boolean addAlias, MiddleIdData idData, String revisionPropertyPath, String revisionEndProperty, boolean addAlias, MiddleIdData idData, String revisionPropertyPath,
String originalIdPropertyName, String alias1, String alias2) { String originalIdPropertyName, String alias1, String alias2) {
Parameters rootParameters = rootQueryBuilder.getRootParameters(); Parameters rootParameters = rootQueryBuilder.getRootParameters();
// create a subquery builder // create a subquery builder
// SELECT max(e.revision) FROM versionsReferencedEntity e2 // SELECT max(e.revision) FROM versionsReferencedEntity e2
QueryBuilder maxERevQb = rootQueryBuilder.newSubQueryBuilder(idData.getAuditEntityName(), alias2); QueryBuilder maxERevQb = rootQueryBuilder.newSubQueryBuilder(idData.getAuditEntityName(), alias2);
maxERevQb.addProjection("max", revisionPropertyPath, false); maxERevQb.addProjection("max", revisionPropertyPath, false);
// WHERE // WHERE
Parameters maxERevQbParameters = maxERevQb.getRootParameters(); Parameters maxERevQbParameters = maxERevQb.getRootParameters();
// e2.revision <= :revision // e2.revision <= :revision
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER); maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER);
// e2.id_ref_ed = e.id_ref_ed // e2.id_ref_ed = e.id_ref_ed
idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters, idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters,
alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName); alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName);
// add subquery to rootParameters // add subquery to rootParameters
String subqueryOperator = globalCfg.getCorrelatedSubqueryOperator(); String subqueryOperator = globalCfg.getCorrelatedSubqueryOperator();
rootParameters.addWhere(revisionProperty, addAlias, subqueryOperator, maxERevQb); rootParameters.addWhere(revisionProperty, addAlias, subqueryOperator, maxERevQb);
} }
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty, public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String versionsMiddleEntityName, String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String versionsMiddleEntityName,
String eeOriginalIdPropertyPath, String revisionPropertyPath, String eeOriginalIdPropertyPath, String revisionPropertyPath,
String originalIdPropertyName, MiddleComponentData... componentDatas) { String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas) {
Parameters rootParameters = rootQueryBuilder.getRootParameters(); Parameters rootParameters = rootQueryBuilder.getRootParameters();
// SELECT max(ee2.revision) FROM middleEntity ee2 // SELECT max(ee2.revision) FROM middleEntity ee2
QueryBuilder maxEeRevQb = rootQueryBuilder.newSubQueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS_DEF_AUD_STR); QueryBuilder maxEeRevQb = rootQueryBuilder.newSubQueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS_DEF_AUD_STR);
maxEeRevQb.addProjection("max", revisionPropertyPath, false); maxEeRevQb.addProjection("max", revisionPropertyPath, false);
// WHERE // WHERE
Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters(); Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters();
// ee2.revision <= :revision // ee2.revision <= :revision
maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER); maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER);
// ee2.originalId.* = ee.originalId.* // ee2.originalId.* = ee.originalId.*
String ee2OriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS_DEF_AUD_STR + "." + originalIdPropertyName; String ee2OriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS_DEF_AUD_STR + "." + originalIdPropertyName;
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath); referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
for (MiddleComponentData componentData : componentDatas) { for (MiddleComponentData componentData : componentDatas) {
componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath); componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, alias1, ee2OriginalIdPropertyPath, MIDDLE_ENTITY_ALIAS_DEF_AUD_STR);
} }
// add subquery to rootParameters // add subquery to rootParameters
rootParameters.addWhere(revisionProperty, addAlias, "=", maxEeRevQb); rootParameters.addWhere(revisionProperty, addAlias, "=", maxEeRevQb);
} }
} }

View File

@ -16,6 +16,7 @@ import java.util.Set;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.RevisionType; import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration; import org.hibernate.envers.configuration.AuditConfiguration;
@ -37,6 +38,8 @@ import org.hibernate.persister.entity.Queryable;
import org.hibernate.persister.entity.UnionSubclassEntityPersister; import org.hibernate.persister.entity.UnionSubclassEntityPersister;
import org.hibernate.property.Getter; import org.hibernate.property.Getter;
import org.hibernate.sql.Update; import org.hibernate.sql.Update;
import org.hibernate.type.CollectionType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -234,21 +237,38 @@ public class ValidityAuditStrategy implements AuditStrategy {
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public void performCollectionChange(Session session, AuditConfiguration auditCfg, public void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) { PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
final QueryBuilder qb = new QueryBuilder(persistentCollectionChangeData.getEntityName(), MIDDLE_ENTITY_ALIAS); final QueryBuilder qb = new QueryBuilder(persistentCollectionChangeData.getEntityName(), MIDDLE_ENTITY_ALIAS);
// Adding a parameter for each id component, except the rev number
final String originalIdPropName = auditCfg.getAuditEntCfg().getOriginalIdPropName(); final String originalIdPropName = auditCfg.getAuditEntCfg().getOriginalIdPropName();
final Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get( final Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(originalIdPropName);
originalIdPropName); final String revisionFieldName = auditCfg.getAuditEntCfg().getRevisionFieldName();
final String revisionTypePropName = auditCfg.getAuditEntCfg().getRevisionTypePropName();
// Adding a parameter for each id component, except the rev number and type.
for (Map.Entry<String, Object> originalIdEntry : originalId.entrySet()) { for (Map.Entry<String, Object> originalIdEntry : originalId.entrySet()) {
if (!auditCfg.getAuditEntCfg().getRevisionFieldName().equals(originalIdEntry.getKey())) { if (!revisionFieldName.equals(originalIdEntry.getKey()) && !revisionTypePropName.equals(originalIdEntry.getKey())) {
qb.getRootParameters().addWhereWithParam(originalIdPropName + "." + originalIdEntry.getKey(), qb.getRootParameters().addWhereWithParam(originalIdPropName + "." + originalIdEntry.getKey(),
true, "=", originalIdEntry.getValue()); true, "=", originalIdEntry.getValue());
} }
} }
final SessionFactoryImplementor sessionFactory = ( (SessionImplementor) session ).getFactory();
final Type propertyType = sessionFactory.getEntityPersister( entityName ).getPropertyType( propertyName );
if ( propertyType.isCollectionType() ) {
CollectionType collectionPropertyType = (CollectionType) propertyType;
// Handling collection of components.
if ( collectionPropertyType.getElementType( sessionFactory ) instanceof ComponentType ) {
// Adding restrictions to compare data outside of primary key.
for ( Map.Entry<String, Object> dataEntry : persistentCollectionChangeData.getData().entrySet() ) {
if ( !originalIdPropName.equals( dataEntry.getKey() ) ) {
qb.getRootParameters().addWhereWithParam( dataEntry.getKey(), true, "=", dataEntry.getValue() );
}
}
}
}
addEndRevisionNullRestriction(auditCfg, qb.getRootParameters()); addEndRevisionNullRestriction(auditCfg, qb.getRootParameters());
final List<Object> l = qb.toQuery(session).setLockOptions(LockOptions.UPGRADE).list(); final List<Object> l = qb.toQuery(session).setLockOptions(LockOptions.UPGRADE).list();
@ -280,7 +300,7 @@ public class ValidityAuditStrategy implements AuditStrategy {
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty, public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath, String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
String originalIdPropertyName, MiddleComponentData... componentDatas) { String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas) {
Parameters rootParameters = rootQueryBuilder.getRootParameters(); Parameters rootParameters = rootQueryBuilder.getRootParameters();
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias); addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
} }

View File

@ -53,7 +53,7 @@ public class PersistentCollectionChangeWorkUnit extends AbstractAuditWorkUnit im
this.referencingPropertyName = referencingPropertyName; this.referencingPropertyName = referencingPropertyName;
collectionChanges = auditCfg.getEntCfg().get(getEntityName()).getPropertyMapper() collectionChanges = auditCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
.mapCollectionChanges(referencingPropertyName, collection, snapshot, id); .mapCollectionChanges(sessionImplementor, referencingPropertyName, collection, snapshot, id);
} }
public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor, String entityName, public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor, String entityName,
@ -83,7 +83,7 @@ public class PersistentCollectionChangeWorkUnit extends AbstractAuditWorkUnit im
((Map<String, Object>) persistentCollectionChangeData.getData().get(entitiesCfg.getOriginalIdPropName())) ((Map<String, Object>) persistentCollectionChangeData.getData().get(entitiesCfg.getOriginalIdPropName()))
.put(entitiesCfg.getRevisionFieldName(), revisionData); .put(entitiesCfg.getRevisionFieldName(), revisionData);
auditStrategy.performCollectionChange(session, verCfg, persistentCollectionChangeData, revisionData); auditStrategy.performCollectionChange(session, getEntityName(), referencingPropertyName, verCfg, persistentCollectionChangeData, revisionData);
} }
} }

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.entities;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Proxy;
import org.hibernate.envers.Audited;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@Table(name = "STR_TEST_NP")
@Proxy(lazy = false)
public class StrTestNoProxyEntity implements Serializable {
@Id
@GeneratedValue
private Integer id;
@Audited
private String str;
public StrTestNoProxyEntity() {
}
public StrTestNoProxyEntity(String str, Integer id) {
this.str = str;
this.id = id;
}
public StrTestNoProxyEntity(String str) {
this.str = str;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof StrTestNoProxyEntity ) ) return false;
StrTestNoProxyEntity that = (StrTestNoProxyEntity) o;
if ( id != null ? !id.equals( that.id ) : that.id != null ) return false;
if ( str != null ? !str.equals( that.str ) : that.str != null ) return false;
return true;
}
public int hashCode() {
int result = ( id != null ? id.hashCode() : 0 );
result = 31 * result + ( str != null ? str.hashCode() : 0 );
return result;
}
public String toString() {
return "STNPE(id = " + id + ", str = " + str + ")";
}
}

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.entities.collection;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OrderColumn;
import javax.persistence.Table;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.components.Component3;
/**
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
@Entity
@Table(name = "EmbListEnt1")
@Audited
public class EmbeddableListEntity1 {
@Id
@GeneratedValue
private Integer id;
private String otherData;
@ElementCollection
@OrderColumn
@CollectionTable(name = "EmbListEnt1_list")
private List<Component3> componentList = new ArrayList<Component3>();
public EmbeddableListEntity1() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<Component3> getComponentList() {
return componentList;
}
public void setComponentList(List<Component3> componentList) {
this.componentList = componentList;
}
public String getOtherData() {
return otherData;
}
public void setOtherData(String otherData) {
this.otherData = otherData;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof EmbeddableListEntity1 ) ) return false;
EmbeddableListEntity1 that = (EmbeddableListEntity1) o;
if ( id != null ? !id.equals( that.id ) : that.id != null ) return false;
return true;
}
public int hashCode() {
return ( id != null ? id.hashCode() : 0 );
}
public String toString() {
return "ELE1(id = " + id + ", otherData = " + otherData + ", componentList = " + componentList + ")";
}
}

View File

@ -0,0 +1,94 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.entities.collection;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OrderColumn;
import javax.persistence.Table;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.components.relations.ManyToOneEagerComponent;
/**
* Embeddable list with components encapsulating many-to-one relation (referencing some entity).
*
* @author thiagolrc
*/
@Entity
@Table(name = "EmbListEnt2")
@Audited
public class EmbeddableListEntity2 {
@Id
@GeneratedValue
private Integer id;
@ElementCollection
@OrderColumn
@CollectionTable(name = "EmbListEnt2_list")
private List<ManyToOneEagerComponent> componentList = new ArrayList<ManyToOneEagerComponent>();
public EmbeddableListEntity2() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<ManyToOneEagerComponent> getComponentList() {
return componentList;
}
public void setComponentList(List<ManyToOneEagerComponent> componentList) {
this.componentList = componentList;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof EmbeddableListEntity2 ) ) return false;
EmbeddableListEntity2 that = (EmbeddableListEntity2) o;
if ( id != null ? !id.equals( that.id ) : that.id != null ) return false;
return true;
}
public int hashCode() {
return ( id != null ? id.hashCode() : 0 );
}
public String toString() {
return "ELE2(id = " + id + ", componentList = " + componentList + ")";
}
}

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.entities.collection;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.components.Component3;
/**
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
@Entity
@Table(name = "EmbMapEnt")
public class EmbeddableMapEntity {
@Id
@GeneratedValue
private Integer id;
@Audited
@ElementCollection
@CollectionTable(name = "EmbMapEnt_map")
private Map<String, Component3> componentMap;
public EmbeddableMapEntity() {
componentMap = new HashMap<String, Component3>();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Map<String, Component3> getComponentMap() {
return componentMap;
}
public void setComponentMap(Map<String, Component3> strings) {
this.componentMap = strings;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof EmbeddableMapEntity ) ) return false;
EmbeddableMapEntity that = (EmbeddableMapEntity) o;
if ( id != null ? !id.equals( that.id ) : that.id != null ) return false;
return true;
}
public int hashCode() {
return ( id != null ? id.hashCode() : 0 );
}
public String toString() {
return "EME(id = " + id + ", componentMap = " + componentMap + ")";
}
}

View File

@ -0,0 +1,90 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.entities.collection;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.components.Component3;
/**
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
@Entity
@Table(name = "EmbSetEnt")
@Audited
public class EmbeddableSetEntity {
@Id
@GeneratedValue
private Integer id;
@ElementCollection
@CollectionTable(name = "EmbSetEnt_set")
private Set<Component3> componentSet = new HashSet<Component3>();
public EmbeddableSetEntity() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Set<Component3> getComponentSet() {
return componentSet;
}
public void setComponentSet(Set<Component3> componentSet) {
this.componentSet = componentSet;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof EmbeddableSetEntity ) ) return false;
EmbeddableSetEntity that = (EmbeddableSetEntity) o;
if ( id != null ? !id.equals( that.id ) : that.id != null ) return false;
return true;
}
public int hashCode() {
return ( id != null ? id.hashCode() : 0 );
}
public String toString() {
return "ESE(id = " + id + ", componentSet = " + componentSet + ')';
}
}

View File

@ -0,0 +1,121 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.entities.components;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;
/**
* The {@link #nonAuditedComponent} is ignored in {@link #hashCode()}
* and {@link #equals(Object)} since it's not audited.
*
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
@Embeddable
@Audited
public class Component3 {
private String str1;
@AttributeOverrides({
@AttributeOverride(name = "key", column = @Column(name = "audComp_key")),
@AttributeOverride(name = "value", column = @Column(name = "audComp_value")),
@AttributeOverride(name = "description", column = @Column(name = "audComp_description"))
})
private Component4 auditedComponent;
@NotAudited
@AttributeOverrides({
@AttributeOverride(name = "key", column = @Column(name = "notAudComp_key")),
@AttributeOverride(name = "value", column = @Column(name = "notAudComp_value")),
@AttributeOverride(name = "description", column = @Column(name = "notAudComp_description"))
})
private Component4 nonAuditedComponent;
public Component3() {
}
public Component3(String str1, Component4 auditedComponent, Component4 nonAuditedComponent) {
this.str1 = str1;
this.auditedComponent = auditedComponent;
this.nonAuditedComponent = nonAuditedComponent;
}
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
public Component4 getAuditedComponent() {
return auditedComponent;
}
public void setAuditedComponent(Component4 auditedComponent) {
this.auditedComponent = auditedComponent;
}
public Component4 getNonAuditedComponent() {
return nonAuditedComponent;
}
public void setNonAuditedComponent(Component4 nonAuditedComponent) {
this.nonAuditedComponent = nonAuditedComponent;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( auditedComponent == null ) ? 0 : auditedComponent.hashCode() );
result = prime * result + ( ( str1 == null ) ? 0 : str1.hashCode() );
return result;
}
@Override
public boolean equals(Object obj) {
if ( this == obj ) return true;
if ( !( obj instanceof Component3 ) ) return false;
Component3 other = (Component3) obj;
if ( auditedComponent != null ? !auditedComponent.equals( other.auditedComponent ) : other.auditedComponent != null ) return false;
if ( str1 != null ? !str1.equals( other.str1 ) : other.str1 != null ) return false;
return true;
}
@Override
public String toString() {
return "Component3[str1 = " + str1 + ", auditedComponent = "
+ auditedComponent + ", nonAuditedComponent = "
+ nonAuditedComponent + "]";
}
}

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.entities.components;
import javax.persistence.Embeddable;
import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;
/**
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
@Embeddable
@Audited
public class Component4 {
private String key;
private String value;
@NotAudited
private String description;
public Component4() {
}
public Component4(String key, String value, String description) {
this.key = key;
this.value = value;
this.description = description;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( description == null ) ? 0 : description.hashCode() );
result = prime * result + ( ( key == null ) ? 0 : key.hashCode() );
result = prime * result + ( ( value == null ) ? 0 : value.hashCode() );
return result;
}
@Override
public boolean equals(Object obj) {
if ( this == obj ) return true;
if ( !( obj instanceof Component4 ) ) return false;
Component4 other = (Component4) obj;
if ( description != null ? !description.equals( other.description ) : other.description != null ) return false;
if ( key != null ? !key.equals( other.key ) : other.key != null ) return false;
if ( value != null ? !value.equals( other.value ) : other.value != null ) return false;
return true;
}
@Override
public String toString() {
return "Component4[key = " + key + ", value = " + value + ", description = " + description + "]";
}
}

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.envers.test.entities.components.relations; package org.hibernate.envers.test.entities.components.relations;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;

View File

@ -0,0 +1,94 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.entities.components.relations;
import javax.persistence.Embeddable;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.StrTestNoProxyEntity;
/**
* Do not mark as {@link Audited}. Should be implicitly treated as audited when part of audited entity.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Embeddable
@Table(name = "ManyToOneEagerComp")
public class ManyToOneEagerComponent {
@ManyToOne(fetch = FetchType.EAGER)
private StrTestNoProxyEntity entity;
private String data;
public ManyToOneEagerComponent(StrTestNoProxyEntity entity, String data) {
this.entity = entity;
this.data = data;
}
public ManyToOneEagerComponent() {
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public StrTestNoProxyEntity getEntity() {
return entity;
}
public void setEntity(StrTestNoProxyEntity entity) {
this.entity = entity;
}
@Override
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof ManyToOneEagerComponent ) ) return false;
ManyToOneEagerComponent that = (ManyToOneEagerComponent) o;
if ( data != null ? !data.equals( that.data ) : that.data != null ) return false;
if ( entity != null ? !entity.equals( that.entity ) : that.entity != null ) return false;
return true;
}
@Override
public int hashCode() {
int result = entity != null ? entity.hashCode() : 0;
result = 31 * result + ( data != null ? data.hashCode() : 0 );
return result;
}
public String toString() {
return "ManyToOneEagerComponent(data = " + data + ")";
}
}

View File

@ -0,0 +1,130 @@
/*
* 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.collection.embeddable;
import java.util.Arrays;
import javax.persistence.EntityManager;
import junit.framework.Assert;
import org.junit.Test;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.TestForIssue;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@TestForIssue( jiraKey = "HHH-6613" )
public class BasicEmbeddableCollection extends BaseEnversJPAFunctionalTestCase {
private int id = -1;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { DarkCharacter.class };
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
// Revision 1 - empty element collection
em.getTransaction().begin();
DarkCharacter darkCharacter = new DarkCharacter( 1, 1 );
em.persist( darkCharacter );
em.getTransaction().commit();
id = darkCharacter.getId();
// Revision 2 - adding collection element
em.getTransaction().begin();
darkCharacter = em.find( DarkCharacter.class, darkCharacter.getId() );
darkCharacter.getNames().add( new Name( "Action", "Hank" ) );
darkCharacter = em.merge( darkCharacter );
em.getTransaction().commit();
// Revision 3 - adding another collection element
em.getTransaction().begin();
darkCharacter = em.find( DarkCharacter.class, darkCharacter.getId() );
darkCharacter.getNames().add( new Name( "Green", "Lantern" ) );
darkCharacter = em.merge( darkCharacter );
em.getTransaction().commit();
// Revision 4 - removing single collection element
em.getTransaction().begin();
darkCharacter = em.find( DarkCharacter.class, darkCharacter.getId() );
darkCharacter.getNames().remove( new Name( "Action", "Hank" ) );
darkCharacter = em.merge( darkCharacter );
em.getTransaction().commit();
// Revision 5 - removing all collection elements
em.getTransaction().begin();
darkCharacter = em.find( DarkCharacter.class, darkCharacter.getId() );
darkCharacter.getNames().clear();
darkCharacter = em.merge( darkCharacter );
em.getTransaction().commit();
em.close();
}
@Test
public void testRevisionsCount() {
Assert.assertEquals( Arrays.asList( 1, 2, 3, 4, 5 ), getAuditReader().getRevisions( DarkCharacter.class, id ) );
}
@Test
public void testHistoryOfCharacter() {
DarkCharacter darkCharacter = new DarkCharacter( id, 1 );
DarkCharacter ver1 = getAuditReader().find( DarkCharacter.class, id, 1 );
Assert.assertEquals( darkCharacter, ver1 );
Assert.assertEquals( 0, ver1.getNames().size() );
darkCharacter.getNames().add( new Name( "Action", "Hank" ) );
DarkCharacter ver2 = getAuditReader().find( DarkCharacter.class, id, 2 );
Assert.assertEquals( darkCharacter, ver2 );
Assert.assertEquals( darkCharacter.getNames(), ver2.getNames() );
darkCharacter.getNames().add( new Name( "Green", "Lantern" ) );
DarkCharacter ver3 = getAuditReader().find( DarkCharacter.class, id, 3 );
Assert.assertEquals( darkCharacter, ver3 );
Assert.assertEquals( darkCharacter.getNames(), ver3.getNames() );
darkCharacter.getNames().remove( new Name( "Action", "Hank" ) );
DarkCharacter ver4 = getAuditReader().find( DarkCharacter.class, id, 4 );
Assert.assertEquals( darkCharacter, ver4 );
Assert.assertEquals( darkCharacter.getNames(), ver4.getNames() );
darkCharacter.getNames().clear();
DarkCharacter ver5 = getAuditReader().find( DarkCharacter.class, id, 5 );
Assert.assertEquals( darkCharacter, ver5 );
Assert.assertEquals( darkCharacter.getNames(), ver5.getNames() );
}
}

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.collection.embeddable;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.envers.Audited;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@Audited
public class DarkCharacter implements Serializable {
@Id
private int id;
@ElementCollection
private Set<Name> names = new HashSet<Name>();
private int kills;
public DarkCharacter() {
}
public DarkCharacter(int id, int kills) {
this.id = id;
this.kills = kills;
}
@Override
public boolean equals(Object o) {
if ( this == o ) return true;
if ( ! ( o instanceof DarkCharacter ) ) return false;
DarkCharacter character = (DarkCharacter) o;
if ( id != character.id ) return false;
if ( kills != character.kills ) return false;
return true;
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + kills;
return result;
}
@Override
public String toString() {
return "DarkCharacter(id = " + id + ", kills = " + kills + ")";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getKills() {
return kills;
}
public void setKills(int kills) {
this.kills = kills;
}
public Set<Name> getNames() {
return names;
}
public void setNames(Set<Name> names) {
this.names = names;
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.collection.embeddable;
import java.util.Arrays;
import java.util.Collections;
import javax.persistence.EntityManager;
import org.junit.Test;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.collection.EmbeddableListEntity1;
import org.hibernate.envers.test.entities.components.Component3;
import org.hibernate.envers.test.entities.components.Component4;
import org.hibernate.testing.TestForIssue;
import static org.junit.Assert.assertEquals;
/**
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
@TestForIssue( jiraKey = "HHH-6613" )
public class EmbeddableList1 extends BaseEnversJPAFunctionalTestCase {
private Integer ele1_id = null;
private final Component4 c4_1 = new Component4( "c41", "c41_value", "c41_description" );
private final Component4 c4_2 = new Component4( "c42", "c42_value2", "c42_description" );
private final Component3 c3_1 = new Component3( "c31", c4_1, c4_2 );
private final Component3 c3_2 = new Component3( "c32", c4_1, c4_2 );
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { EmbeddableListEntity1.class };
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
EmbeddableListEntity1 ele1 = new EmbeddableListEntity1();
// Revision 1 (ele1: initially 1 element in both collections)
em.getTransaction().begin();
ele1.getComponentList().add( c3_1 );
em.persist( ele1 );
em.getTransaction().commit();
// Revision (still 1) (ele1: removing non-existing element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.getComponentList().remove( c3_2 );
em.getTransaction().commit();
// Revision 2 (ele1: adding one element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.getComponentList().add( c3_2 );
em.getTransaction().commit();
// Revision 3 (ele1: adding one existing element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.getComponentList().add( c3_1 );
em.getTransaction().commit();
// Revision 4 (ele1: removing one existing element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.getComponentList().remove( c3_2 );
em.getTransaction().commit();
ele1_id = ele1.getId();
em.close();
}
@Test
public void testRevisionsCounts() {
assertEquals( Arrays.asList( 1, 2, 3, 4 ), getAuditReader().getRevisions( EmbeddableListEntity1.class, ele1_id ) );
}
@Test
public void testHistoryOfEle1() {
EmbeddableListEntity1 rev1 = getAuditReader().find( EmbeddableListEntity1.class, ele1_id, 1 );
EmbeddableListEntity1 rev2 = getAuditReader().find( EmbeddableListEntity1.class, ele1_id, 2 );
EmbeddableListEntity1 rev3 = getAuditReader().find( EmbeddableListEntity1.class, ele1_id, 3 );
EmbeddableListEntity1 rev4 = getAuditReader().find( EmbeddableListEntity1.class, ele1_id, 4 );
assertEquals( Collections.singletonList( c3_1 ), rev1.getComponentList() );
assertEquals( Arrays.asList( c3_1, c3_2 ), rev2.getComponentList() );
assertEquals( Arrays.asList( c3_1, c3_2, c3_1 ), rev3.getComponentList() );
assertEquals( Arrays.asList( c3_1, c3_1 ), rev4.getComponentList() );
}
}

View File

@ -0,0 +1,233 @@
/*
* 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.collection.embeddable;
import java.util.Arrays;
import java.util.Date;
import javax.persistence.EntityManager;
import org.junit.Test;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrTestNoProxyEntity;
import org.hibernate.envers.test.entities.collection.EmbeddableListEntity2;
import org.hibernate.envers.test.entities.components.relations.ManyToOneEagerComponent;
import org.hibernate.testing.TestForIssue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Checks if many-to-one relations inside an embedded component list are being audited.
*
* @author thiagolrc
*/
@TestForIssue( jiraKey = "HHH-6613" )
public class EmbeddableList2 extends BaseEnversJPAFunctionalTestCase {
private Integer ele_id1 = null;
private StrTestNoProxyEntity entity1 = new StrTestNoProxyEntity( "strTestEntity1" );
private StrTestNoProxyEntity entity2 = new StrTestNoProxyEntity( "strTestEntity2" );
private StrTestNoProxyEntity entity3 = new StrTestNoProxyEntity( "strTestEntity3" );
private StrTestNoProxyEntity entity4 = new StrTestNoProxyEntity( "strTestEntity3" );
private StrTestNoProxyEntity entity4Copy = null;
private ManyToOneEagerComponent manyToOneComponent1 = new ManyToOneEagerComponent( entity1, "dataComponent1" );
private ManyToOneEagerComponent manyToOneComponent2 = new ManyToOneEagerComponent( entity2, "dataComponent2" );
private ManyToOneEagerComponent manyToOneComponent4 = new ManyToOneEagerComponent( entity4, "dataComponent4" );
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { EmbeddableListEntity2.class, StrTestNoProxyEntity.class };
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
// Revision 1 (ele1: saving a list with 1 many-to-one component)
em.getTransaction().begin();
EmbeddableListEntity2 ele1 = new EmbeddableListEntity2();
em.persist( entity1 ); //persisting the entities referenced by the components
em.persist( entity2 );
ele1.getComponentList().add( manyToOneComponent1 );
em.persist( ele1 );
em.getTransaction().commit();
ele_id1 = ele1.getId();
// Revision 2 (ele1: changing the component)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity2.class, ele1.getId() );
ele1.getComponentList().clear();
ele1.getComponentList().add( manyToOneComponent2 );
em.getTransaction().commit();
//Revision 3 (ele1: putting back the many-to-one component to the list)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity2.class, ele1.getId() );
ele1.getComponentList().add( manyToOneComponent1 );
em.getTransaction().commit();
// Revision 4 (ele1: changing the component's entity)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity2.class, ele1.getId() );
em.persist( entity3 );
ele1.getComponentList().get( ele1.getComponentList().indexOf( manyToOneComponent2 ) ).setEntity( entity3 );
ele1.getComponentList().get( ele1.getComponentList().indexOf( manyToOneComponent2 ) ).setData( "dataComponent3" );
em.getTransaction().commit();
// Revision 5 (ele1: adding a new many-to-one component)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity2.class, ele1.getId() );
em.persist( entity4 );
entity4Copy = new StrTestNoProxyEntity( entity4.getStr(), entity4.getId() );
ele1.getComponentList().add( manyToOneComponent4 );
em.getTransaction().commit();
// Revision 6 (ele1: changing the component's entity properties)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity2.class, ele1.getId() );
ele1.getComponentList().get( ele1.getComponentList().indexOf( manyToOneComponent4 ) ).getEntity().setStr( "sat4" );
em.getTransaction().commit();
// Revision 7 (ele1: removing component)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity2.class, ele1.getId() );
ele1.getComponentList().remove( ele1.getComponentList().indexOf( manyToOneComponent4 ) );
em.getTransaction().commit();
// Revision 8 (ele1: removing all)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity2.class, ele1.getId() );
em.remove( ele1 );
em.getTransaction().commit();
em.close();
}
@Test
public void testRevisionsCounts() {
assertEquals(
Arrays.asList( 1, 2, 3, 4, 5, 7, 8 ),
getAuditReader().getRevisions( EmbeddableListEntity2.class, ele_id1 )
);
assertEquals(
Arrays.asList( 1 ), getAuditReader().getRevisions( StrTestNoProxyEntity.class, entity1.getId() )
);
assertEquals(
Arrays.asList( 1 ), getAuditReader().getRevisions( StrTestNoProxyEntity.class, entity2.getId() )
);
assertEquals(
Arrays.asList( 4 ), getAuditReader().getRevisions( StrTestNoProxyEntity.class, entity3.getId() )
);
assertEquals(
Arrays.asList( 5, 6 ),
getAuditReader().getRevisions( StrTestNoProxyEntity.class, entity4.getId() )
);
}
@Test
public void testManyToOneComponentList() {
// Revision 1: many-to-one component1 in the list
EmbeddableListEntity2 rev1 = getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 1 );
assertNotNull( "Revision not found", rev1 );
assertTrue( "The component collection was not audited", rev1.getComponentList().size() > 0 );
assertEquals(
"The component primitive property was not audited",
"dataComponent1", rev1.getComponentList().get( 0 ).getData()
);
assertEquals(
"The component manyToOne reference was not audited",
entity1, rev1.getComponentList().get( 0 ).getEntity()
);
}
@Test
public void testHistoryOfEle1() {
// Revision 1: many-to-one component in the list
assertEquals(
Arrays.asList( new ManyToOneEagerComponent( entity1, "dataComponent1" ) ),
getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 1 ).getComponentList()
);
// Revision 2: many-to-one component in the list
assertEquals(
Arrays.asList( new ManyToOneEagerComponent( entity2, "dataComponent2" ) ),
getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 2 ).getComponentList()
);
// Revision 3: two many-to-one components in the list
assertEquals(
Arrays.asList(
new ManyToOneEagerComponent( entity2, "dataComponent2" ),
new ManyToOneEagerComponent( entity1, "dataComponent1" )
),
getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 3 ).getComponentList()
);
// Revision 4: second component edited and first one in the list
assertEquals(
Arrays.asList(
new ManyToOneEagerComponent( entity3, "dataComponent3" ),
new ManyToOneEagerComponent( entity1, "dataComponent1" )
),
getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 4 ).getComponentList()
);
// Revision 5: fourth component added in the list
assertEquals(
Arrays.asList(
new ManyToOneEagerComponent( entity3, "dataComponent3" ),
new ManyToOneEagerComponent( entity1, "dataComponent1" ),
new ManyToOneEagerComponent( entity4Copy, "dataComponent4" )
),
getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 5 ).getComponentList()
);
// Revision 6: changing fourth component property
assertEquals(
Arrays.asList(
new ManyToOneEagerComponent( entity3, "dataComponent3" ),
new ManyToOneEagerComponent( entity1, "dataComponent1" ),
new ManyToOneEagerComponent( entity4, "dataComponent4" )
),
getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 6 ).getComponentList()
);
// Revision 7: removing component number four
assertEquals(
Arrays.asList(
new ManyToOneEagerComponent( entity3, "dataComponent3" ),
new ManyToOneEagerComponent( entity1, "dataComponent1" )
),
getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 7 ).getComponentList()
);
assertNull( getAuditReader().find( EmbeddableListEntity2.class, ele_id1, 8 ) );
}
}

View File

@ -0,0 +1,136 @@
/*
* 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.collection.embeddable;
import java.util.Arrays;
import java.util.Collections;
import javax.persistence.EntityManager;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.collection.EmbeddableMapEntity;
import org.hibernate.envers.test.entities.components.Component3;
import org.hibernate.envers.test.entities.components.Component4;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.testing.TestForIssue;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
@TestForIssue( jiraKey = "HHH-6613" )
public class EmbeddableMap extends BaseEnversJPAFunctionalTestCase {
private Integer eme1_id = null;
private Integer eme2_id = null;
private final Component4 c4_1 = new Component4( "c41", "c41_value", "c41_description" );
private final Component4 c4_2 = new Component4( "c42", "c42_value2", "c42_description" );
private final Component3 c3_1 = new Component3( "c31", c4_1, c4_2 );
private final Component3 c3_2 = new Component3( "c32", c4_1, c4_2 );
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { EmbeddableMapEntity.class };
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
EmbeddableMapEntity eme1 = new EmbeddableMapEntity();
EmbeddableMapEntity eme2 = new EmbeddableMapEntity();
// Revision 1 (eme1: initialy empty, eme2: initialy 1 mapping)
em.getTransaction().begin();
eme2.getComponentMap().put( "1", c3_1 );
em.persist( eme1 );
em.persist( eme2 );
em.getTransaction().commit();
// Revision 2 (eme1: adding 2 mappings, eme2: no changes)
em.getTransaction().begin();
eme1 = em.find( EmbeddableMapEntity.class, eme1.getId() );
eme2 = em.find( EmbeddableMapEntity.class, eme2.getId() );
eme1.getComponentMap().put( "1", c3_1 );
eme1.getComponentMap().put( "2", c3_2 );
em.getTransaction().commit();
// Revision 3 (eme1: removing an existing mapping, eme2: replacing a value)
em.getTransaction().begin();
eme1 = em.find( EmbeddableMapEntity.class, eme1.getId() );
eme2 = em.find( EmbeddableMapEntity.class, eme2.getId() );
eme1.getComponentMap().remove( "1" );
eme2.getComponentMap().put( "1", c3_2 );
em.getTransaction().commit();
// No revision (eme1: removing a non-existing mapping, eme2: replacing with the same value)
em.getTransaction().begin();
eme1 = em.find( EmbeddableMapEntity.class, eme1.getId() );
eme2 = em.find( EmbeddableMapEntity.class, eme2.getId() );
eme1.getComponentMap().remove( "3" );
eme2.getComponentMap().put( "1", c3_2 );
em.getTransaction().commit();
eme1_id = eme1.getId();
eme2_id = eme2.getId();
em.close();
}
@Test
public void testRevisionsCounts() {
Assert.assertEquals( Arrays.asList( 1, 2, 3 ), getAuditReader().getRevisions( EmbeddableMapEntity.class, eme1_id ) );
Assert.assertEquals( Arrays.asList( 1, 3 ), getAuditReader().getRevisions( EmbeddableMapEntity.class, eme2_id ) );
}
@Test
public void testHistoryOfEme1() {
EmbeddableMapEntity rev1 = getAuditReader().find( EmbeddableMapEntity.class, eme1_id, 1 );
EmbeddableMapEntity rev2 = getAuditReader().find( EmbeddableMapEntity.class, eme1_id, 2 );
EmbeddableMapEntity rev3 = getAuditReader().find( EmbeddableMapEntity.class, eme1_id, 3 );
EmbeddableMapEntity rev4 = getAuditReader().find( EmbeddableMapEntity.class, eme1_id, 4 );
Assert.assertEquals( Collections.EMPTY_MAP, rev1.getComponentMap() );
Assert.assertEquals( TestTools.makeMap( "1", c3_1, "2", c3_2 ), rev2.getComponentMap() );
Assert.assertEquals( TestTools.makeMap( "2", c3_2 ), rev3.getComponentMap() );
Assert.assertEquals( TestTools.makeMap( "2", c3_2 ), rev4.getComponentMap() );
}
@Test
public void testHistoryOfEme2() {
EmbeddableMapEntity rev1 = getAuditReader().find( EmbeddableMapEntity.class, eme2_id, 1 );
EmbeddableMapEntity rev2 = getAuditReader().find( EmbeddableMapEntity.class, eme2_id, 2 );
EmbeddableMapEntity rev3 = getAuditReader().find( EmbeddableMapEntity.class, eme2_id, 3 );
EmbeddableMapEntity rev4 = getAuditReader().find( EmbeddableMapEntity.class, eme2_id, 4 );
Assert.assertEquals( TestTools.makeMap( "1", c3_1 ), rev1.getComponentMap() );
Assert.assertEquals( TestTools.makeMap( "1", c3_1 ), rev2.getComponentMap() );
Assert.assertEquals( TestTools.makeMap( "1", c3_2 ), rev3.getComponentMap() );
Assert.assertEquals( TestTools.makeMap( "1", c3_2 ), rev4.getComponentMap() );
}
}

View File

@ -0,0 +1,116 @@
/*
* 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.collection.embeddable;
import java.util.Arrays;
import java.util.Collections;
import javax.persistence.EntityManager;
import org.junit.Test;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.collection.EmbeddableSetEntity;
import org.hibernate.envers.test.entities.components.Component3;
import org.hibernate.envers.test.entities.components.Component4;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.testing.TestForIssue;
import static org.junit.Assert.assertEquals;
/**
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
*/
@TestForIssue( jiraKey = "HHH-6613" )
public class EmbeddableSet extends BaseEnversJPAFunctionalTestCase {
private Integer ese1_id = null;
private final Component4 c4_1 = new Component4( "c41", "c41_value", "c41_description" );
private final Component4 c4_2 = new Component4( "c42", "c42_value2", "c42_description" );
private final Component3 c3_1 = new Component3( "c31", c4_1, c4_2 );
private final Component3 c3_2 = new Component3( "c32", c4_1, c4_2 );
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { EmbeddableSetEntity.class };
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
EmbeddableSetEntity ese1 = new EmbeddableSetEntity();
// Revision 1 (ese1: initially 1 element in both collections)
em.getTransaction().begin();
ese1.getComponentSet().add( c3_1 );
em.persist( ese1 );
em.getTransaction().commit();
// Revision (still 1) (ese1: removing non-existing element)
em.getTransaction().begin();
ese1 = em.find( EmbeddableSetEntity.class, ese1.getId() );
ese1.getComponentSet().remove( c3_2 );
em.getTransaction().commit();
// Revision 2 (ese1: adding one element)
em.getTransaction().begin();
ese1 = em.find( EmbeddableSetEntity.class, ese1.getId() );
ese1.getComponentSet().add( c3_2 );
em.getTransaction().commit();
// Revision 3 (ese1: adding one existing element)
em.getTransaction().begin();
ese1 = em.find( EmbeddableSetEntity.class, ese1.getId() );
ese1.getComponentSet().add( c3_1 );
em.getTransaction().commit();
// Revision 4 (ese1: removing one existing element)
em.getTransaction().begin();
ese1 = em.find( EmbeddableSetEntity.class, ese1.getId() );
ese1.getComponentSet().remove( c3_2 );
em.getTransaction().commit();
ese1_id = ese1.getId();
em.close();
}
@Test
public void testRevisionsCounts() {
assertEquals( Arrays.asList( 1, 2, 3 ), getAuditReader().getRevisions( EmbeddableSetEntity.class, ese1_id ) );
}
@Test
public void testHistoryOfEse1() {
EmbeddableSetEntity rev1 = getAuditReader().find( EmbeddableSetEntity.class, ese1_id, 1 );
EmbeddableSetEntity rev2 = getAuditReader().find( EmbeddableSetEntity.class, ese1_id, 2 );
EmbeddableSetEntity rev3 = getAuditReader().find( EmbeddableSetEntity.class, ese1_id, 3 );
assertEquals( Collections.singleton( c3_1 ), rev1.getComponentSet() );
assertEquals( TestTools.makeSet( c3_1, c3_2 ), rev2.getComponentSet() );
assertEquals( TestTools.makeSet( c3_1 ), rev3.getComponentSet() );
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.collection.embeddable;
import java.io.Serializable;
import javax.persistence.Embeddable;
import org.hibernate.envers.Audited;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Embeddable
@Audited
public class Name implements Serializable {
private String firstName;
private String lastName;
public Name() {
}
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof Name ) ) return false;
Name name = (Name) o;
if ( firstName != null ? !firstName.equals( name.firstName ) : name.firstName != null ) return false;
if ( lastName != null ? !lastName.equals( name.lastName ) : name.lastName != null ) return false;
return true;
}
@Override
public int hashCode() {
int result = firstName != null ? firstName.hashCode() : 0;
result = 31 * result + ( lastName != null ? lastName.hashCode() : 0 );
return result;
}
@Override
public String toString() {
return "Name(firstName = " + firstName + ", lastName = " + lastName + ")";
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}

View File

@ -0,0 +1,102 @@
package org.hibernate.envers.test.integration.modifiedflags;
import java.util.List;
import javax.persistence.EntityManager;
import org.junit.Test;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.collection.EmbeddableListEntity1;
import org.hibernate.envers.test.entities.components.Component3;
import org.hibernate.envers.test.entities.components.Component4;
import org.hibernate.testing.TestForIssue;
import static org.junit.Assert.assertEquals;
import static org.hibernate.envers.test.tools.TestTools.extractRevisionNumbers;
import static org.hibernate.envers.test.tools.TestTools.makeList;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@TestForIssue( jiraKey = "HHH-6613" )
public class HasChangedComponentCollection extends AbstractModifiedFlagsEntityTest {
private Integer ele1_id = null;
private final Component4 c4_1 = new Component4( "c41", "c41_value", "c41_description" );
private final Component4 c4_2 = new Component4( "c42", "c42_value2", "c42_description" );
private final Component3 c3_1 = new Component3( "c31", c4_1, c4_2 );
private final Component3 c3_2 = new Component3( "c32", c4_1, c4_2 );
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { EmbeddableListEntity1.class };
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
// Revision 1 (ele1: initially 1 element in both collections)
em.getTransaction().begin();
EmbeddableListEntity1 ele1 = new EmbeddableListEntity1();
ele1.setOtherData( "data" );
ele1.getComponentList().add( c3_1 );
em.persist( ele1 );
em.getTransaction().commit();
// Revision (still 1) (ele1: removing non-existing element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.getComponentList().remove( c3_2 );
em.getTransaction().commit();
// Revision 2 (ele1: updating singular property and removing non-existing element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.setOtherData( "modified" );
ele1.getComponentList().remove( c3_2 );
ele1 = em.merge( ele1 );
em.getTransaction().commit();
// Revision 3 (ele1: adding one element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.getComponentList().add( c3_2 );
em.getTransaction().commit();
// Revision 4 (ele1: adding one existing element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.getComponentList().add( c3_1 );
em.getTransaction().commit();
// Revision 5 (ele1: removing one existing element)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.getComponentList().remove( c3_2 );
em.getTransaction().commit();
// Revision 6 (ele1: changing singular property only)
em.getTransaction().begin();
ele1 = em.find( EmbeddableListEntity1.class, ele1.getId() );
ele1.setOtherData( "another modification" );
ele1 = em.merge( ele1 );
em.getTransaction().commit();
ele1_id = ele1.getId();
em.close();
}
@Test
public void testHasChangedEle() {
List list = queryForPropertyHasChanged( EmbeddableListEntity1.class, ele1_id, "componentList" );
assertEquals( 4, list.size() );
assertEquals( makeList( 1, 3, 4, 5 ), extractRevisionNumbers( list ) );
list = queryForPropertyHasChanged( EmbeddableListEntity1.class, ele1_id, "otherData" );
assertEquals( 3, list.size() );
assertEquals( makeList( 1, 2, 6 ), extractRevisionNumbers( list ) );
}
}