HHH-6613 - Support for audited @ElementCollection
This commit is contained in:
parent
8515ce197a
commit
51a7df596e
|
@ -1306,7 +1306,8 @@ query.add(AuditEntity.relatedId("address").eq(relatedEntityId));]]></programlist
|
|||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
collections of components
|
||||
Bag style collection which identifier column has been defined using
|
||||
<interfacename>@CollectionId</interfacename> annotation (JIRA ticket HHH-3950).
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
|
|
@ -140,13 +140,13 @@ public final class AuditMetadataGenerator {
|
|||
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(),
|
||||
verEntCfg.getRevisionTypePropType(), true, false);
|
||||
revTypeProperty.addAttribute("type", "org.hibernate.envers.entities.RevisionTypeType");
|
||||
|
||||
// Adding the end revision, if appropriate
|
||||
addEndRevision(any_mapping);
|
||||
addEndRevision(any_mapping_end);
|
||||
}
|
||||
|
||||
private void addEndRevision(Element any_mapping ) {
|
||||
|
@ -377,7 +377,7 @@ public final class AuditMetadataGenerator {
|
|||
class_mapping.add((Element) idMapper.getXmlMapping().clone());
|
||||
|
||||
// Adding the "revision type" property
|
||||
addRevisionType(class_mapping);
|
||||
addRevisionType(class_mapping, class_mapping);
|
||||
|
||||
return Triple.make(class_mapping, propertyMapper, null);
|
||||
}
|
||||
|
|
|
@ -38,13 +38,18 @@ import org.dom4j.Element;
|
|||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.envers.ModificationStore;
|
||||
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.entities.EntityConfiguration;
|
||||
import org.hibernate.envers.entities.IdMappingData;
|
||||
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.SinglePropertyMapper;
|
||||
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.ToOneIdMapper;
|
||||
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.MiddleMapKeyPropertyComponentMapper;
|
||||
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.Tools;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.IndexedCollection;
|
||||
import org.hibernate.mapping.ManyToOne;
|
||||
import org.hibernate.mapping.OneToMany;
|
||||
|
@ -83,6 +90,7 @@ import org.hibernate.mapping.Property;
|
|||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.type.BagType;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.ListType;
|
||||
import org.hibernate.type.ManyToOneType;
|
||||
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.
|
||||
RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator(mainGenerator.getGlobalCfg(),
|
||||
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(),
|
||||
referencingIdData, referencedEntityName, referencedIdData);
|
||||
referencingIdData, referencedEntityName, referencedIdData, isEmbeddableElementType());
|
||||
|
||||
// Creating common mapper data.
|
||||
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.
|
||||
QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(),
|
||||
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData,
|
||||
auditMiddleEntityName);
|
||||
auditMiddleEntityName, isEmbeddableElementType());
|
||||
|
||||
// Adding the XML mapping for the referencing entity, if the relation isn't inverse.
|
||||
if (middleEntityXml != null) {
|
||||
|
@ -463,6 +471,41 @@ public final class CollectionMetadataGenerator {
|
|||
|
||||
return new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData),
|
||||
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 {
|
||||
// Last but one parameter: collection components are always insertable
|
||||
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
|
||||
|
@ -483,33 +526,36 @@ public final class CollectionMetadataGenerator {
|
|||
private void addMapper(CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData,
|
||||
MiddleComponentData indexComponentData) {
|
||||
Type type = propertyValue.getType();
|
||||
boolean embeddableElementType = isEmbeddableElementType();
|
||||
if (type instanceof SortedSetType) {
|
||||
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||
new SortedSetCollectionMapper(commonCollectionMapperData,
|
||||
TreeSet.class, SortedSetProxy.class, elementComponentData, propertyValue.getComparator()));
|
||||
TreeSet.class, SortedSetProxy.class, elementComponentData, propertyValue.getComparator(),
|
||||
embeddableElementType));
|
||||
} else if (type instanceof SetType) {
|
||||
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||
new BasicCollectionMapper<Set>(commonCollectionMapperData,
|
||||
HashSet.class, SetProxy.class, elementComponentData));
|
||||
HashSet.class, SetProxy.class, elementComponentData, embeddableElementType));
|
||||
} else if (type instanceof SortedMapType) {
|
||||
// Indexed collection, so <code>indexComponentData</code> is not null.
|
||||
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||
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) {
|
||||
// Indexed collection, so <code>indexComponentData</code> is not null.
|
||||
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||
new MapCollectionMapper<Map>(commonCollectionMapperData,
|
||||
HashMap.class, MapProxy.class, elementComponentData, indexComponentData));
|
||||
HashMap.class, MapProxy.class, elementComponentData, indexComponentData, embeddableElementType));
|
||||
} else if (type instanceof BagType) {
|
||||
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||
new BasicCollectionMapper<List>(commonCollectionMapperData,
|
||||
ArrayList.class, ListProxy.class, elementComponentData));
|
||||
ArrayList.class, ListProxy.class, elementComponentData, embeddableElementType));
|
||||
} else if (type instanceof ListType) {
|
||||
// Indexed collection, so <code>indexComponentData</code> is not null.
|
||||
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||
new ListCollectionMapper(commonCollectionMapperData,
|
||||
elementComponentData, indexComponentData));
|
||||
elementComponentData, indexComponentData, embeddableElementType));
|
||||
} else {
|
||||
mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
|
||||
}
|
||||
|
@ -546,12 +592,19 @@ public final class CollectionMetadataGenerator {
|
|||
mainGenerator.addRevisionInfoRelation(middleEntityXmlId);
|
||||
|
||||
// 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.
|
||||
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) {
|
||||
PersistentClass referencedClass = null;
|
||||
if (collectionValue.getElement() instanceof OneToMany) {
|
||||
|
|
|
@ -49,15 +49,17 @@ public final class QueryGeneratorBuilder {
|
|||
private final MiddleIdData referencingIdData;
|
||||
private final String auditMiddleEntityName;
|
||||
private final List<MiddleIdData> idDatas;
|
||||
private final boolean revisionTypeInId;
|
||||
|
||||
QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
MiddleIdData referencingIdData, String auditMiddleEntityName) {
|
||||
AuditStrategy auditStrategy, MiddleIdData referencingIdData, String auditMiddleEntityName,
|
||||
boolean revisionTypeInId) {
|
||||
this.globalCfg = globalCfg;
|
||||
this.verEntCfg = verEntCfg;
|
||||
this.auditStrategy = auditStrategy;
|
||||
this.referencingIdData = referencingIdData;
|
||||
this.auditMiddleEntityName = auditMiddleEntityName;
|
||||
this.revisionTypeInId = revisionTypeInId;
|
||||
|
||||
idDatas = new ArrayList<MiddleIdData>();
|
||||
}
|
||||
|
@ -69,14 +71,14 @@ public final class QueryGeneratorBuilder {
|
|||
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
||||
if (idDatas.size() == 0) {
|
||||
return new OneEntityQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
componentDatas);
|
||||
revisionTypeInId, componentDatas);
|
||||
} else if (idDatas.size() == 1) {
|
||||
if (idDatas.get(0).isAudited()) {
|
||||
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get(0), componentDatas);
|
||||
idDatas.get(0), revisionTypeInId, componentDatas);
|
||||
} else {
|
||||
return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get(0), componentDatas);
|
||||
idDatas.get(0), revisionTypeInId, componentDatas);
|
||||
}
|
||||
} else if (idDatas.size() == 2) {
|
||||
// All entities must be audited.
|
||||
|
@ -85,7 +87,7 @@ public final class QueryGeneratorBuilder {
|
|||
}
|
||||
|
||||
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get(0), idDatas.get(1), componentDatas);
|
||||
idDatas.get(0), idDatas.get(1), revisionTypeInId, componentDatas);
|
||||
} else {
|
||||
throw new IllegalStateException("Illegal number of related entities.");
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ public class AuditedPropertiesReader {
|
|||
// Marking component properties as placed directly in class (not inside another component).
|
||||
componentData.setBeanName(null);
|
||||
|
||||
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( propertyValue );
|
||||
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource( reflectionManager, propertyValue );
|
||||
AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
|
||||
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
|
||||
propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName)
|
||||
|
@ -338,7 +338,7 @@ public class AuditedPropertiesReader {
|
|||
allClassAudited);
|
||||
|
||||
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
|
||||
propertyValue
|
||||
reflectionManager, propertyValue
|
||||
);
|
||||
|
||||
ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
|
||||
|
@ -541,11 +541,11 @@ public class AuditedPropertiesReader {
|
|||
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 Component component;
|
||||
|
||||
private ComponentPropertiesSource(Component component) {
|
||||
public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
|
||||
try {
|
||||
this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass());
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
package org.hibernate.envers.configuration.metadata.reader;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hibernate.envers.tools.Tools.newHashMap;
|
||||
|
||||
|
@ -53,5 +54,9 @@ public class ComponentAuditingData extends PropertyAuditingData implements Audit
|
|||
|
||||
public boolean contains(String propertyName) {
|
||||
return properties.containsKey(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getPropertyNames() {
|
||||
return properties.keySet();
|
||||
}
|
||||
}
|
|
@ -25,11 +25,9 @@ package org.hibernate.envers.entities;
|
|||
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
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.exception.AuditException;
|
||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.tools.reflection.ReflectionTools;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.LazyInitializer;
|
||||
|
@ -149,4 +147,12 @@ public class EntityInstantiator {
|
|||
addTo.add(createInstanceFromVersionsEntity(entityName, versionsEntity, revision));
|
||||
}
|
||||
}
|
||||
|
||||
public AuditConfiguration getAuditConfiguration() {
|
||||
return verCfg;
|
||||
}
|
||||
|
||||
public AuditReaderImplementor getAuditReaderImplementor() {
|
||||
return versionsReader;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,11 +130,13 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
|
|||
}
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
Serializable id) {
|
||||
return delegate.mapCollectionChanges(referencingPropertyName, newColl, oldColl, id);
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
return delegate.mapCollectionChanges(session, referencingPropertyName, newColl, oldColl, id);
|
||||
}
|
||||
|
||||
public Map<PropertyData, PropertyMapper> getProperties() {
|
||||
return delegate.getProperties();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.entities.mapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.envers.entities.PropertyData;
|
||||
|
||||
/**
|
||||
|
@ -30,4 +33,5 @@ import org.hibernate.envers.entities.PropertyData;
|
|||
public interface CompositeMapperBuilder extends SimpleMapperBuilder {
|
||||
public CompositeMapperBuilder addComponent(PropertyData propertyData, String componentClassName);
|
||||
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
|
||||
public Map<PropertyData, PropertyMapper> getProperties();
|
||||
}
|
||||
|
|
|
@ -171,14 +171,14 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
|
|||
}
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
Serializable id) {
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
|
||||
String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
Pair<PropertyMapper, String> pair = getMapperAndDelegatePropName(referencingPropertyName);
|
||||
PropertyMapper mapper = pair.getFirst();
|
||||
if (mapper != null) {
|
||||
return mapper.mapCollectionChanges(pair.getSecond(), newColl, oldColl, id);
|
||||
return mapper.mapCollectionChanges(session, pair.getSecond(), newColl, oldColl, id);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -59,14 +59,15 @@ public interface PropertyMapper {
|
|||
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 newColl New collection, after updates.
|
||||
* @param oldColl Old collection, before updates.
|
||||
* @param id Id of the object owning the collection.
|
||||
* @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,
|
||||
Serializable oldColl, Serializable id);
|
||||
|
||||
|
|
|
@ -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,
|
||||
Serializable oldColl,
|
||||
Serializable id) {
|
||||
Serializable oldColl, Serializable id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.envers.entities.mapper;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -78,15 +79,14 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
|
|||
main.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
Serializable id) {
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
|
||||
referencingPropertyName, newColl, oldColl, id);
|
||||
session, referencingPropertyName, newColl, oldColl, id);
|
||||
|
||||
List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges(
|
||||
referencingPropertyName, newColl, oldColl, id);
|
||||
session, referencingPropertyName, newColl, oldColl, id);
|
||||
|
||||
if (parentCollectionChanges == null) {
|
||||
return mainCollectionChanges;
|
||||
|
@ -109,4 +109,11 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
|
|||
public void add(PropertyData 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.entities.mapper.relation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
@ -54,13 +55,16 @@ import org.hibernate.property.Setter;
|
|||
public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
||||
protected final CommonCollectionMapperData commonCollectionMapperData;
|
||||
protected final Class<? extends T> collectionClass;
|
||||
protected final boolean revisionTypeInId;
|
||||
|
||||
private final Constructor<? extends T> proxyConstructor;
|
||||
|
||||
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.collectionClass = collectionClass;
|
||||
this.revisionTypeInId = revisionTypeInId;
|
||||
|
||||
try {
|
||||
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.
|
||||
* @param idData Map to which composite-id data should be added.
|
||||
* @param data Where to map the data.
|
||||
* @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,
|
||||
RevisionType revisionType, Serializable id) {
|
||||
private void addCollectionChanges(SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges,
|
||||
Set<Object> changed, RevisionType revisionType, Serializable id) {
|
||||
for (Object changedObj : changed) {
|
||||
Map<String, Object> entityData = 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);
|
||||
|
||||
// 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"})
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
|
||||
String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
if (!commonCollectionMapperData.getCollectionReferencingPropertyData().getName()
|
||||
.equals(referencingPropertyName)) {
|
||||
if (!commonCollectionMapperData.getCollectionReferencingPropertyData().getName().equals(referencingPropertyName)) {
|
||||
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).
|
||||
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>();
|
||||
if (oldColl != null) { deleted.addAll(oldCollection); }
|
||||
// The same as above - re-hashing new collection.
|
||||
if (newColl != null) { deleted.removeAll(new HashSet(newCollection)); }
|
||||
|
||||
addCollectionChanges(collectionChanges, deleted, RevisionType.DEL, id);
|
||||
addCollectionChanges(session, collectionChanges, deleted, RevisionType.DEL, id);
|
||||
|
||||
return collectionChanges;
|
||||
}
|
||||
|
@ -146,7 +151,7 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
|||
} else if (isFromNullToEmptyOrFromEmptyToNull((PersistentCollection) newObj, (Serializable) oldObj)) {
|
||||
data.put(propertyData.getModifiedFlagPropertyName(), true);
|
||||
} else {
|
||||
List<PersistentCollectionChangeData> changes = mapCollectionChanges(
|
||||
List<PersistentCollectionChangeData> changes = mapCollectionChanges(session,
|
||||
commonCollectionMapperData.getCollectionReferencingPropertyData().getName(),
|
||||
(PersistentCollection) newObj, (Serializable) oldObj, null);
|
||||
data.put(propertyData.getModifiedFlagPropertyName(), !changes.isEmpty());
|
||||
|
|
|
@ -42,9 +42,9 @@ public abstract class AbstractToOneMapper implements PropertyMapper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
|
||||
PersistentCollection newColl, Serializable oldColl,
|
||||
Serializable id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Collection;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PropertyMapper;
|
||||
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,
|
||||
Class<? extends T> collectionClass, Class<? extends T> proxyClass,
|
||||
MiddleComponentData elementComponentData) {
|
||||
super(commonCollectionMapperData, collectionClass, proxyClass);
|
||||
MiddleComponentData elementComponentData, boolean revisionTypeInId) {
|
||||
super(commonCollectionMapperData, collectionClass, proxyClass, revisionTypeInId);
|
||||
this.elementComponentData = elementComponentData;
|
||||
}
|
||||
|
||||
|
@ -67,7 +68,7 @@ public class BasicCollectionMapper<T extends Collection> extends AbstractCollect
|
|||
}
|
||||
}
|
||||
|
||||
protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
|
||||
elementComponentData.getComponentMapper().mapToMapFromObject(data, changed);
|
||||
protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
|
||||
elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, changed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PropertyMapper;
|
||||
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;
|
||||
|
||||
public ListCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
|
||||
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData) {
|
||||
super(commonCollectionMapperData, List.class, ListProxy.class);
|
||||
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
|
||||
boolean revisionTypeInId) {
|
||||
super(commonCollectionMapperData, List.class, ListProxy.class, revisionTypeInId);
|
||||
this.elementComponentData = elementComponentData;
|
||||
this.indexComponentData = indexComponentData;
|
||||
}
|
||||
|
@ -76,9 +78,9 @@ public final class ListCollectionMapper extends AbstractCollectionMapper<List> i
|
|||
}
|
||||
|
||||
@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;
|
||||
elementComponentData.getComponentMapper().mapToMapFromObject(data, indexValuePair.getSecond());
|
||||
indexComponentData.getComponentMapper().mapToMapFromObject(data, indexValuePair.getFirst());
|
||||
elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, indexValuePair.getSecond());
|
||||
indexComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, indexValuePair.getFirst());
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import java.util.Collection;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PropertyMapper;
|
||||
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,
|
||||
Class<? extends T> collectionClass, Class<? extends T> proxyClass,
|
||||
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData) {
|
||||
super(commonCollectionMapperData, collectionClass, proxyClass);
|
||||
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
|
||||
boolean revisionTypeInId) {
|
||||
super(commonCollectionMapperData, collectionClass, proxyClass, revisionTypeInId);
|
||||
this.elementComponentData = elementComponentData;
|
||||
this.indexComponentData = indexComponentData;
|
||||
}
|
||||
|
@ -71,8 +73,8 @@ public class MapCollectionMapper<T extends Map> extends AbstractCollectionMapper
|
|||
}
|
||||
}
|
||||
|
||||
protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
|
||||
elementComponentData.getComponentMapper().mapToMapFromObject(data, ((Map.Entry) changed).getValue());
|
||||
indexComponentData.getComponentMapper().mapToMapFromObject(data, ((Map.Entry) changed).getKey());
|
||||
protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
|
||||
elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, ((Map.Entry) changed).getValue());
|
||||
indexComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, ((Map.Entry) changed).getKey());
|
||||
}
|
||||
}
|
|
@ -39,8 +39,9 @@ public final class SortedMapCollectionMapper extends MapCollectionMapper<SortedM
|
|||
|
||||
public SortedMapCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
|
||||
Class<? extends SortedMap> collectionClass, Class<? extends SortedMap> proxyClass,
|
||||
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData, Comparator comparator) {
|
||||
super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, indexComponentData);
|
||||
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData, Comparator comparator,
|
||||
boolean revisionTypeInId) {
|
||||
super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, indexComponentData, revisionTypeInId);
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,8 +39,9 @@ public final class SortedSetCollectionMapper extends BasicCollectionMapper<Sorte
|
|||
|
||||
public SortedSetCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
|
||||
Class<? extends SortedSet> collectionClass, Class<? extends SortedSet> proxyClass,
|
||||
MiddleComponentData elementComponentData, Comparator comparator) {
|
||||
super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData);
|
||||
MiddleComponentData elementComponentData, Comparator comparator,
|
||||
boolean revisionTypeInId) {
|
||||
super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, revisionTypeInId);
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.tools.Tools;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
|
@ -105,4 +106,8 @@ public class ToOneIdMapper extends AbstractToOneMapper {
|
|||
|
||||
setPropertyValue(obj, value);
|
||||
}
|
||||
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
|
||||
delegate.addIdsEqualToQuery( parameters, prefix1, delegate, prefix2 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,12 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
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.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).
|
||||
* @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 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
|
||||
* 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.
|
||||
* @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 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.
|
||||
*/
|
||||
void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2);
|
||||
void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
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.tools.query.Parameters;
|
||||
|
||||
|
@ -36,9 +37,9 @@ public final class MiddleDummyComponentMapper implements MiddleComponentMapper {
|
|||
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) {
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.envers.entities.mapper.relation.component;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.entities.EntityInstantiator;
|
||||
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()));
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
|
||||
// Doing nothing.
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
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.tools.query.Parameters;
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
|
||||
// Doing nothing.
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
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.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
|
@ -43,11 +44,11 @@ public final class MiddleRelatedComponentMapper implements MiddleComponentMapper
|
|||
return entityInstantiator.createInstanceFromVersionsEntity(relatedIdData.getEntityName(), data, revision);
|
||||
}
|
||||
|
||||
public void mapToMapFromObject(Map<String, Object> data, Object obj) {
|
||||
relatedIdData.getPrefixedMapper().mapToMapFromEntity(data, obj);
|
||||
public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
|
||||
relatedIdData.getPrefixedMapper().mapToMapFromEntity(idData, obj);
|
||||
}
|
||||
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
|
||||
relatedIdData.getPrefixedMapper().addIdsEqualToQuery(parameters, prefix1, prefix2);
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
|
||||
relatedIdData.getPrefixedMapper().addIdsEqualToQuery(parameters, idPrefix1, idPrefix2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.envers.entities.mapper.relation.component;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.entities.EntityInstantiator;
|
||||
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);
|
||||
}
|
||||
|
||||
public void mapToMapFromObject(Map<String, Object> data, Object obj) {
|
||||
data.put(propertyName, obj);
|
||||
public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
|
||||
idData.put(propertyName, obj);
|
||||
}
|
||||
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
|
||||
parameters.addWhere(prefix1 + "." + propertyName, false, "=", prefix2 + "." + propertyName, false);
|
||||
public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
|
||||
parameters.addWhere(idPrefix1 + "." + propertyName, false, "=", idPrefix2 + "." + propertyName, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
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.tools.query.Parameters;
|
||||
|
||||
|
@ -45,11 +46,11 @@ public final class MiddleStraightComponentMapper implements MiddleComponentMappe
|
|||
return data.get(propertyName);
|
||||
}
|
||||
|
||||
public void mapToMapFromObject(Map<String, Object> data, Object obj) {
|
||||
data.put(propertyName, obj);
|
||||
}
|
||||
public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object 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!");
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -45,15 +45,15 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
|
|||
* Selects data from an audit entity.
|
||||
* @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 MiddleIdData referencingIdData;
|
||||
|
||||
public OneAuditEntityQueryGenerator(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
MiddleIdData referencingIdData,
|
||||
String referencedEntityName, MiddleIdData referencedIdData) {
|
||||
this.referencingIdData = referencingIdData;
|
||||
String referencedEntityName, MiddleIdData referencedIdData,
|
||||
boolean revisionTypeInId) {
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
// 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();
|
||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
||||
queryString = sb.toString();
|
||||
}
|
||||
|
||||
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) {
|
||||
Query query = versionsReader.getSession().createQuery(queryString);
|
||||
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;
|
||||
}
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,16 +44,16 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
|
|||
* Selects data from a relation middle-table only.
|
||||
* @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 MiddleIdData referencingIdData;
|
||||
|
||||
public OneEntityQueryGenerator(AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
boolean revisionTypeInId,
|
||||
MiddleComponentData... componentDatas) {
|
||||
this.referencingIdData = referencingIdData;
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
|
||||
/*
|
||||
* The query that we need to create:
|
||||
|
@ -90,25 +90,19 @@ public final class OneEntityQueryGenerator implements RelationQueryGenerator {
|
|||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
|
||||
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", DEL_REVISION_TYPE_PARAMETER);
|
||||
rootParameters.addWhereWithNamedParam(getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
||||
queryString = sb.toString();
|
||||
}
|
||||
|
||||
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) {
|
||||
Query query = versionsReader.getSession().createQuery(queryString);
|
||||
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;
|
||||
}
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* @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 MiddleIdData referencingIdData;
|
||||
|
||||
public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
|
@ -60,8 +59,9 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
MiddleIdData indexIdData,
|
||||
boolean revisionTypeInId,
|
||||
MiddleComponentData... componentDatas) {
|
||||
this.referencingIdData = referencingIdData;
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
|
||||
/*
|
||||
* The query that we need to create:
|
||||
|
@ -157,28 +157,23 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
|
||||
|
||||
// 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
|
||||
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
|
||||
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();
|
||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
||||
queryString = sb.toString();
|
||||
}
|
||||
|
||||
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) {
|
||||
Query query = versionsReader.getSession().createQuery(queryString);
|
||||
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;
|
||||
}
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* @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 MiddleIdData referencingIdData;
|
||||
|
||||
public TwoEntityOneAuditedQueryGenerator(AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
boolean revisionTypeInId,
|
||||
MiddleComponentData... componentDatas) {
|
||||
this.referencingIdData = referencingIdData;
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
|
||||
/*
|
||||
* The query that we need to create:
|
||||
|
@ -99,24 +99,18 @@ public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGen
|
|||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
|
||||
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", DEL_REVISION_TYPE_PARAMETER);
|
||||
rootParameters.addWhereWithNamedParam(getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
||||
queryString = sb.toString();
|
||||
}
|
||||
|
||||
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) {
|
||||
Query query = versionsReader.getSession().createQuery(queryString);
|
||||
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;
|
||||
}
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* @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 MiddleIdData referencingIdData;
|
||||
|
||||
public TwoEntityQueryGenerator(GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
|
@ -57,8 +56,9 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
|
|||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
boolean revisionTypeInId,
|
||||
MiddleComponentData... componentDatas) {
|
||||
this.referencingIdData = referencingIdData;
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
|
||||
/*
|
||||
* The query that we need to create:
|
||||
|
@ -118,26 +118,21 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
|
|||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
|
||||
|
||||
// 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
|
||||
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();
|
||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
||||
queryString = sb.toString();
|
||||
}
|
||||
|
||||
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) {
|
||||
Query query = versionsReader.getSession().createQuery(queryString);
|
||||
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;
|
||||
}
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
|||
.getEntCfg()
|
||||
.get( collectionEntityName )
|
||||
.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
|
||||
// entities.
|
||||
|
|
|
@ -1,99 +1,104 @@
|
|||
package org.hibernate.envers.strategy;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
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
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public interface AuditStrategy {
|
||||
/**
|
||||
* Perform the persistence of audited data for regular entities.
|
||||
*
|
||||
* @param session Session, which can be used to persist the data.
|
||||
* @param entityName Name of the entity, in which the audited change happens
|
||||
* @param auditCfg Audit configuration
|
||||
* @param id Id of the entity.
|
||||
* @param data Audit data to persist
|
||||
* @param revision Current revision data
|
||||
*/
|
||||
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.
|
||||
* @param auditCfg Audit configuration
|
||||
* @param persistentCollectionChangeData Collection change data to be persisted.
|
||||
* @param revision Current revision data
|
||||
*/
|
||||
void performCollectionChange(Session session, AuditConfiguration auditCfg,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision);
|
||||
|
||||
|
||||
/**
|
||||
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a two-entity relation.
|
||||
* 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>
|
||||
* </li>
|
||||
* <li>for {@link ValidityAuditStrategy} the revision-end column is used:
|
||||
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param globalCfg the {@link GlobalConfiguration}
|
||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||
* @param revisionProperty property of the revision column
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
||||
* @param addAlias {@code boolean} indicator if a left alias is needed
|
||||
* @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})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @param alias1 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
||||
* @param alias2 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
||||
*/
|
||||
void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
||||
String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData,
|
||||
String revisionPropertyPath, String originalIdPropertyName, String alias1, String alias2);
|
||||
|
||||
/**
|
||||
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a middle-entity
|
||||
* association. 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>
|
||||
* </li>
|
||||
* <li>for {@link ValidityAuditStrategy} the revision-end column is used:
|
||||
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||
* @param revisionProperty property of the revision column
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
||||
* @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 versionsMiddleEntityName name of the middle-entity
|
||||
* @param eeOriginalIdPropertyPath name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @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, MiddleComponentData... componentDatas);
|
||||
|
||||
}
|
||||
package org.hibernate.envers.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
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
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public interface AuditStrategy {
|
||||
/**
|
||||
* Perform the persistence of audited data for regular entities.
|
||||
*
|
||||
* @param session Session, which can be used to persist the data.
|
||||
* @param entityName Name of the entity, in which the audited change happens
|
||||
* @param auditCfg Audit configuration
|
||||
* @param id Id of the entity.
|
||||
* @param data Audit data to persist
|
||||
* @param revision Current revision data
|
||||
*/
|
||||
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.
|
||||
* @param entityName Name of the entity, in which the audited change happens.
|
||||
* @param propertyName The name of the property holding the {@link PersistentCollection}.
|
||||
* @param auditCfg Audit configuration
|
||||
* @param persistentCollectionChangeData Collection change data to be persisted.
|
||||
* @param revision Current revision data
|
||||
*/
|
||||
void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision);
|
||||
|
||||
|
||||
/**
|
||||
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a two-entity relation.
|
||||
* 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>
|
||||
* </li>
|
||||
* <li>for {@link ValidityAuditStrategy} the revision-end column is used:
|
||||
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param globalCfg the {@link GlobalConfiguration}
|
||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||
* @param revisionProperty property of the revision column
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
||||
* @param addAlias {@code boolean} indicator if a left alias is needed
|
||||
* @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})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @param alias1 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
||||
* @param alias2 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
||||
*/
|
||||
void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
||||
String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData,
|
||||
String revisionPropertyPath, String originalIdPropertyName, String alias1, String alias2);
|
||||
|
||||
/**
|
||||
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a middle-entity
|
||||
* association. 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>
|
||||
* </li>
|
||||
* <li>for {@link ValidityAuditStrategy} the revision-end column is used:
|
||||
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||
* @param revisionProperty property of the revision column
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
||||
* @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 versionsMiddleEntityName name of the middle-entity
|
||||
* @param eeOriginalIdPropertyPath name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
||||
* @param alias1 an alias used for subqueries (only used for {@link DefaultAuditStrategy})
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,90 +1,90 @@
|
|||
package org.hibernate.envers.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.synchronization.SessionCacheCleaner;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
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.REVISION_PARAMETER;
|
||||
|
||||
/**
|
||||
* Default strategy is to simply persist the audit data.
|
||||
*
|
||||
* @author Adam Warski
|
||||
* @author Stephanie Pau
|
||||
*/
|
||||
public class DefaultAuditStrategy implements AuditStrategy {
|
||||
private final SessionCacheCleaner sessionCacheCleaner;
|
||||
|
||||
public DefaultAuditStrategy() {
|
||||
sessionCacheCleaner = new SessionCacheCleaner();
|
||||
}
|
||||
|
||||
public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
|
||||
Object revision) {
|
||||
session.save(auditCfg.getAuditEntCfg().getAuditEntityName(entityName), data);
|
||||
sessionCacheCleaner.scheduleAuditDataRemoval(session, data);
|
||||
}
|
||||
|
||||
public void performCollectionChange(Session session, AuditConfiguration auditCfg,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
|
||||
session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
|
||||
sessionCacheCleaner.scheduleAuditDataRemoval(session, persistentCollectionChangeData.getData());
|
||||
}
|
||||
|
||||
|
||||
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData idData, String revisionPropertyPath,
|
||||
String originalIdPropertyName, String alias1, String alias2) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
|
||||
// create a subquery builder
|
||||
// SELECT max(e.revision) FROM versionsReferencedEntity e2
|
||||
QueryBuilder maxERevQb = rootQueryBuilder.newSubQueryBuilder(idData.getAuditEntityName(), alias2);
|
||||
maxERevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
|
||||
// e2.revision <= :revision
|
||||
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER);
|
||||
// e2.id_ref_ed = e.id_ref_ed
|
||||
idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters,
|
||||
alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName);
|
||||
|
||||
// add subquery to rootParameters
|
||||
String subqueryOperator = globalCfg.getCorrelatedSubqueryOperator();
|
||||
rootParameters.addWhere(revisionProperty, addAlias, subqueryOperator, maxERevQb);
|
||||
}
|
||||
|
||||
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String versionsMiddleEntityName,
|
||||
String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, MiddleComponentData... componentDatas) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
|
||||
// SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
QueryBuilder maxEeRevQb = rootQueryBuilder.newSubQueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS_DEF_AUD_STR);
|
||||
maxEeRevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters();
|
||||
// ee2.revision <= :revision
|
||||
maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER);
|
||||
// ee2.originalId.* = ee.originalId.*
|
||||
String ee2OriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS_DEF_AUD_STR + "." + originalIdPropertyName;
|
||||
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
for (MiddleComponentData componentData : componentDatas) {
|
||||
componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
}
|
||||
|
||||
// add subquery to rootParameters
|
||||
rootParameters.addWhere(revisionProperty, addAlias, "=", maxEeRevQb);
|
||||
}
|
||||
|
||||
}
|
||||
package org.hibernate.envers.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.synchronization.SessionCacheCleaner;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
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.REVISION_PARAMETER;
|
||||
|
||||
/**
|
||||
* Default strategy is to simply persist the audit data.
|
||||
*
|
||||
* @author Adam Warski
|
||||
* @author Stephanie Pau
|
||||
*/
|
||||
public class DefaultAuditStrategy implements AuditStrategy {
|
||||
private final SessionCacheCleaner sessionCacheCleaner;
|
||||
|
||||
public DefaultAuditStrategy() {
|
||||
sessionCacheCleaner = new SessionCacheCleaner();
|
||||
}
|
||||
|
||||
public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
|
||||
Object revision) {
|
||||
session.save(auditCfg.getAuditEntCfg().getAuditEntityName(entityName), data);
|
||||
sessionCacheCleaner.scheduleAuditDataRemoval(session, data);
|
||||
}
|
||||
|
||||
public void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
|
||||
session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
|
||||
sessionCacheCleaner.scheduleAuditDataRemoval(session, persistentCollectionChangeData.getData());
|
||||
}
|
||||
|
||||
|
||||
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData idData, String revisionPropertyPath,
|
||||
String originalIdPropertyName, String alias1, String alias2) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
|
||||
// create a subquery builder
|
||||
// SELECT max(e.revision) FROM versionsReferencedEntity e2
|
||||
QueryBuilder maxERevQb = rootQueryBuilder.newSubQueryBuilder(idData.getAuditEntityName(), alias2);
|
||||
maxERevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
|
||||
// e2.revision <= :revision
|
||||
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER);
|
||||
// e2.id_ref_ed = e.id_ref_ed
|
||||
idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters,
|
||||
alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName);
|
||||
|
||||
// add subquery to rootParameters
|
||||
String subqueryOperator = globalCfg.getCorrelatedSubqueryOperator();
|
||||
rootParameters.addWhere(revisionProperty, addAlias, subqueryOperator, maxERevQb);
|
||||
}
|
||||
|
||||
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String versionsMiddleEntityName,
|
||||
String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
|
||||
// SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
QueryBuilder maxEeRevQb = rootQueryBuilder.newSubQueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS_DEF_AUD_STR);
|
||||
maxEeRevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters();
|
||||
// ee2.revision <= :revision
|
||||
maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER);
|
||||
// ee2.originalId.* = ee.originalId.*
|
||||
String ee2OriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS_DEF_AUD_STR + "." + originalIdPropertyName;
|
||||
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
for (MiddleComponentData componentData : componentDatas) {
|
||||
componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, alias1, ee2OriginalIdPropertyPath, MIDDLE_ENTITY_ALIAS_DEF_AUD_STR);
|
||||
}
|
||||
|
||||
// add subquery to rootParameters
|
||||
rootParameters.addWhere(revisionProperty, addAlias, "=", maxEeRevQb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.Set;
|
|||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
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.property.Getter;
|
||||
import org.hibernate.sql.Update;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -234,21 +237,38 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
|||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public void performCollectionChange(Session session, AuditConfiguration auditCfg,
|
||||
public void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
|
||||
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 Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
|
||||
originalIdPropName);
|
||||
final Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(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()) {
|
||||
if (!auditCfg.getAuditEntCfg().getRevisionFieldName().equals(originalIdEntry.getKey())) {
|
||||
if (!revisionFieldName.equals(originalIdEntry.getKey()) && !revisionTypePropName.equals(originalIdEntry.getKey())) {
|
||||
qb.getRootParameters().addWhereWithParam(originalIdPropName + "." + originalIdEntry.getKey(),
|
||||
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());
|
||||
|
||||
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,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
||||
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, MiddleComponentData... componentDatas) {
|
||||
String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class PersistentCollectionChangeWorkUnit extends AbstractAuditWorkUnit im
|
|||
this.referencingPropertyName = referencingPropertyName;
|
||||
|
||||
collectionChanges = auditCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
|
||||
.mapCollectionChanges(referencingPropertyName, collection, snapshot, id);
|
||||
.mapCollectionChanges(sessionImplementor, referencingPropertyName, collection, snapshot, id);
|
||||
}
|
||||
|
||||
public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor, String entityName,
|
||||
|
@ -83,7 +83,7 @@ public class PersistentCollectionChangeWorkUnit extends AbstractAuditWorkUnit im
|
|||
((Map<String, Object>) persistentCollectionChangeData.getData().get(entitiesCfg.getOriginalIdPropName()))
|
||||
.put(entitiesCfg.getRevisionFieldName(), revisionData);
|
||||
|
||||
auditStrategy.performCollectionChange(session, verCfg, persistentCollectionChangeData, revisionData);
|
||||
auditStrategy.performCollectionChange(session, getEntityName(), referencingPropertyName, verCfg, persistentCollectionChangeData, revisionData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
|
@ -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 + ')';
|
||||
}
|
||||
}
|
|
@ -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 + "]";
|
||||
}
|
||||
}
|
|
@ -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 + "]";
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.test.entities.components.relations;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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 ) );
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 ) );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue