mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-25 12:55:21 +00:00
HHH-3563: relation support in components
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15802 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
6d56458124
commit
bf8e6fed6f
@ -37,9 +37,9 @@
|
|||||||
import org.dom4j.io.DOMWriter;
|
import org.dom4j.io.DOMWriter;
|
||||||
import org.dom4j.io.OutputFormat;
|
import org.dom4j.io.OutputFormat;
|
||||||
import org.dom4j.io.XMLWriter;
|
import org.dom4j.io.XMLWriter;
|
||||||
import org.hibernate.envers.configuration.metadata.AnnotationsMetadataReader;
|
import org.hibernate.envers.configuration.metadata.reader.AnnotationsMetadataReader;
|
||||||
import org.hibernate.envers.configuration.metadata.EntityXmlMappingData;
|
import org.hibernate.envers.configuration.metadata.EntityXmlMappingData;
|
||||||
import org.hibernate.envers.configuration.metadata.PersistentClassAuditingData;
|
import org.hibernate.envers.configuration.metadata.reader.ClassAuditingData;
|
||||||
import org.hibernate.envers.configuration.metadata.AuditMetadataGenerator;
|
import org.hibernate.envers.configuration.metadata.AuditMetadataGenerator;
|
||||||
import org.hibernate.envers.entities.EntitiesConfigurations;
|
import org.hibernate.envers.entities.EntitiesConfigurations;
|
||||||
import org.hibernate.envers.tools.StringTools;
|
import org.hibernate.envers.tools.StringTools;
|
||||||
@ -64,8 +64,8 @@ public EntitiesConfigurations configure(Configuration cfg, ReflectionManager ref
|
|||||||
// Sorting the persistent class topologically - superclass always before subclass
|
// Sorting the persistent class topologically - superclass always before subclass
|
||||||
Iterator<PersistentClass> classes = GraphTopologicalSort.sort(new PersistentClassGraphDefiner(cfg)).iterator();
|
Iterator<PersistentClass> classes = GraphTopologicalSort.sort(new PersistentClassGraphDefiner(cfg)).iterator();
|
||||||
|
|
||||||
Map<PersistentClass, PersistentClassAuditingData> pcDatas =
|
Map<PersistentClass, ClassAuditingData> pcDatas =
|
||||||
new HashMap<PersistentClass, PersistentClassAuditingData>();
|
new HashMap<PersistentClass, ClassAuditingData>();
|
||||||
Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
|
Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
|
||||||
|
|
||||||
// First pass
|
// First pass
|
||||||
@ -74,7 +74,7 @@ public EntitiesConfigurations configure(Configuration cfg, ReflectionManager ref
|
|||||||
// Collecting information from annotations on the persistent class pc
|
// Collecting information from annotations on the persistent class pc
|
||||||
AnnotationsMetadataReader annotationsMetadataReader =
|
AnnotationsMetadataReader annotationsMetadataReader =
|
||||||
new AnnotationsMetadataReader(globalCfg, reflectionManager, pc);
|
new AnnotationsMetadataReader(globalCfg, reflectionManager, pc);
|
||||||
PersistentClassAuditingData auditData = annotationsMetadataReader.getAuditData();
|
ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
|
||||||
|
|
||||||
if (auditData.isAudited()) {
|
if (auditData.isAudited()) {
|
||||||
pcDatas.put(pc, auditData);
|
pcDatas.put(pc, auditData);
|
||||||
@ -90,7 +90,7 @@ public EntitiesConfigurations configure(Configuration cfg, ReflectionManager ref
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Second pass
|
// Second pass
|
||||||
for (Map.Entry<PersistentClass, PersistentClassAuditingData> pcDatasEntry : pcDatas.entrySet()) {
|
for (Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : pcDatas.entrySet()) {
|
||||||
EntityXmlMappingData xmlMappingData = xmlMappings.get(pcDatasEntry.getKey());
|
EntityXmlMappingData xmlMappingData = xmlMappings.get(pcDatasEntry.getKey());
|
||||||
|
|
||||||
auditMetaGen.generateSecondPass(pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData);
|
auditMetaGen.generateSecondPass(pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData);
|
||||||
|
@ -1,286 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.configuration.metadata;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import javax.persistence.MapKey;
|
|
||||||
import javax.persistence.Version;
|
|
||||||
import javax.persistence.JoinColumn;
|
|
||||||
|
|
||||||
import org.hibernate.envers.SecondaryAuditTable;
|
|
||||||
import org.hibernate.envers.*;
|
|
||||||
import org.hibernate.envers.ModificationStore;
|
|
||||||
import org.hibernate.envers.tools.Tools;
|
|
||||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
|
||||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
|
||||||
import org.hibernate.annotations.common.reflection.XClass;
|
|
||||||
import org.hibernate.annotations.common.reflection.XProperty;
|
|
||||||
import org.hibernate.mapping.PersistentClass;
|
|
||||||
import org.hibernate.mapping.Property;
|
|
||||||
import org.jboss.envers.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper class to read versioning meta-data from annotations on a persistent class.
|
|
||||||
* @author Adam Warski (adam at warski dot org)
|
|
||||||
* @author Sebastian Komander
|
|
||||||
*/
|
|
||||||
public final class AnnotationsMetadataReader {
|
|
||||||
private final GlobalConfiguration globalCfg;
|
|
||||||
private final ReflectionManager reflectionManager;
|
|
||||||
private final PersistentClass pc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This object is filled with information read from annotations and returned by the <code>getVersioningData</code>
|
|
||||||
* method.
|
|
||||||
*/
|
|
||||||
private final PersistentClassAuditingData auditData;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not null if the whole class is annotated with @Audited; the variable then holds the value of this
|
|
||||||
* annotation's "modStore" parameter.
|
|
||||||
*/
|
|
||||||
private ModificationStore defaultStore;
|
|
||||||
|
|
||||||
private Set<String> propertyPersistentProperties;
|
|
||||||
private Set<String> fieldPersistentProperties;
|
|
||||||
|
|
||||||
public AnnotationsMetadataReader(GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
|
||||||
PersistentClass pc) {
|
|
||||||
this.globalCfg = globalCfg;
|
|
||||||
this.reflectionManager = reflectionManager;
|
|
||||||
this.pc = pc;
|
|
||||||
|
|
||||||
auditData = new PersistentClassAuditingData();
|
|
||||||
|
|
||||||
propertyPersistentProperties = Tools.newHashSet();
|
|
||||||
fieldPersistentProperties = Tools.newHashSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ModificationStore translateModStore(org.jboss.envers.ModificationStore store) {
|
|
||||||
switch (store) {
|
|
||||||
case FULL: return ModificationStore.FULL;
|
|
||||||
default: throw new AssertionError("Illegal modification store: " + store + "!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a property is audited and if yes, sets its modification store on the supplied property data.
|
|
||||||
* @param property Property to check.
|
|
||||||
* @param propertyData Property data, on which to set this property's modification store.
|
|
||||||
* @param persistentProperties Persistent properties with the access type of the given property.
|
|
||||||
* @return True, iff this property is audited.
|
|
||||||
*/
|
|
||||||
private boolean ifPropertyAuditedAddStore(XProperty property, PersistentPropertyAuditingData propertyData,
|
|
||||||
Set<String> persistentProperties) {
|
|
||||||
// If this is not a persistent property, with the same access type as currently checked,
|
|
||||||
// it's not audited as well.
|
|
||||||
if (!persistentProperties.contains(property.getName())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if a property is declared as not audited to exclude it
|
|
||||||
// useful if a class is audited but some properties should be excluded
|
|
||||||
NotAudited unVer = property.getAnnotation(NotAudited.class);
|
|
||||||
if (unVer != null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// if the optimistic locking field has to be unversioned and the current property
|
|
||||||
// is the optimistic locking field, don't audit it
|
|
||||||
if (globalCfg.isDoNotAuditOptimisticLockingField()) {
|
|
||||||
Version jpaVer = property.getAnnotation(Version.class);
|
|
||||||
if (jpaVer != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checking if this property is explicitly audited or if all properties are.
|
|
||||||
Audited aud = property.getAnnotation(Audited.class);
|
|
||||||
Versioned ver = property.getAnnotation(Versioned.class);
|
|
||||||
if (aud != null) {
|
|
||||||
propertyData.setStore(aud.modStore());
|
|
||||||
return true;
|
|
||||||
} else if (ver != null) {
|
|
||||||
propertyData.setStore(translateModStore(ver.modStore()));
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (defaultStore != null) {
|
|
||||||
propertyData.setStore(defaultStore);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addPropertyMapKey(XProperty property, PersistentPropertyAuditingData propertyData) {
|
|
||||||
MapKey mapKey = property.getAnnotation(MapKey.class);
|
|
||||||
if (mapKey != null) {
|
|
||||||
propertyData.setMapKey(mapKey.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addPropertyJoinTables(XProperty property, PersistentPropertyAuditingData propertyData) {
|
|
||||||
AuditJoinTable joinTable = property.getAnnotation(AuditJoinTable.class);
|
|
||||||
if (joinTable != null) {
|
|
||||||
propertyData.setJoinTable(joinTable);
|
|
||||||
} else {
|
|
||||||
propertyData.setJoinTable(getDefaultAuditJoinTable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addFromProperties(Iterable<XProperty> properties, String accessType, Set<String> persistenProperties) {
|
|
||||||
for (XProperty property : properties) {
|
|
||||||
PersistentPropertyAuditingData propertyData = new PersistentPropertyAuditingData();
|
|
||||||
|
|
||||||
if (ifPropertyAuditedAddStore(property, propertyData, persistenProperties)) {
|
|
||||||
// Now we know that the property is audited
|
|
||||||
auditData.getProperties().put(property.getName(), propertyData);
|
|
||||||
|
|
||||||
propertyData.setName(property.getName());
|
|
||||||
propertyData.setAccessType(accessType);
|
|
||||||
|
|
||||||
addPropertyJoinTables(property, propertyData);
|
|
||||||
addPropertyMapKey(property, propertyData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addPropertiesFromClass(XClass clazz) {
|
|
||||||
XClass superclazz = clazz.getSuperclass();
|
|
||||||
if (!"java.lang.Object".equals(superclazz.getName())) {
|
|
||||||
addPropertiesFromClass(superclazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldPersistentProperties);
|
|
||||||
addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyPersistentProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readDefaultAudited(XClass clazz) {
|
|
||||||
Audited defaultAudited = clazz.getAnnotation(Audited.class);
|
|
||||||
|
|
||||||
if (defaultAudited != null) {
|
|
||||||
defaultStore = defaultAudited.modStore();
|
|
||||||
auditData.setDefaultAudited(true);
|
|
||||||
} else {
|
|
||||||
Versioned defaultVersioned = clazz.getAnnotation(Versioned.class);
|
|
||||||
if (defaultVersioned != null) {
|
|
||||||
defaultStore = translateModStore(defaultVersioned.modStore());
|
|
||||||
auditData.setDefaultAudited(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readPersistentProperties() {
|
|
||||||
Iterator propertyIter = pc.getPropertyIterator();
|
|
||||||
while (propertyIter.hasNext()) {
|
|
||||||
Property property = (Property) propertyIter.next();
|
|
||||||
if ("field".equals(property.getPropertyAccessorName())) {
|
|
||||||
fieldPersistentProperties.add(property.getName());
|
|
||||||
} else {
|
|
||||||
propertyPersistentProperties.add(property.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addAuditTable(XClass clazz) {
|
|
||||||
AuditTable auditTable = clazz.getAnnotation(AuditTable.class);
|
|
||||||
if (auditTable != null) {
|
|
||||||
auditData.setAuditTable(auditTable);
|
|
||||||
} else {
|
|
||||||
auditData.setAuditTable(getDefaultAuditTable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addAuditSecondaryTables(XClass clazz) {
|
|
||||||
// Getting information on secondary tables
|
|
||||||
SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation(SecondaryAuditTable.class);
|
|
||||||
if (secondaryVersionsTable1 != null) {
|
|
||||||
auditData.getSecondaryTableDictionary().put(secondaryVersionsTable1.secondaryTableName(),
|
|
||||||
secondaryVersionsTable1.secondaryAuditTableName());
|
|
||||||
}
|
|
||||||
|
|
||||||
SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation(SecondaryAuditTables.class);
|
|
||||||
if (secondaryAuditTables != null) {
|
|
||||||
for (SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value()) {
|
|
||||||
auditData.getSecondaryTableDictionary().put(secondaryAuditTable2.secondaryTableName(),
|
|
||||||
secondaryAuditTable2.secondaryAuditTableName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PersistentClassAuditingData getAuditData() {
|
|
||||||
if (pc.getClassName() == null) {
|
|
||||||
return auditData;
|
|
||||||
}
|
|
||||||
|
|
||||||
readPersistentProperties();
|
|
||||||
|
|
||||||
try {
|
|
||||||
XClass clazz = reflectionManager.classForName(pc.getClassName(), this.getClass());
|
|
||||||
|
|
||||||
readDefaultAudited(clazz);
|
|
||||||
addPropertiesFromClass(clazz);
|
|
||||||
addAuditTable(clazz);
|
|
||||||
addAuditSecondaryTables(clazz);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new MappingException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return auditData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private AuditTable defaultAuditTable;
|
|
||||||
private AuditTable getDefaultAuditTable() {
|
|
||||||
if (defaultAuditTable == null) {
|
|
||||||
defaultAuditTable = new AuditTable() {
|
|
||||||
public String value() { return ""; }
|
|
||||||
public String schema() { return ""; }
|
|
||||||
public String catalog() { return ""; }
|
|
||||||
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultAuditTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private AuditJoinTable defaultAuditJoinTable;
|
|
||||||
private AuditJoinTable getDefaultAuditJoinTable() {
|
|
||||||
if (defaultAuditJoinTable == null) {
|
|
||||||
defaultAuditJoinTable = new AuditJoinTable() {
|
|
||||||
public String name() { return ""; }
|
|
||||||
public String schema() { return ""; }
|
|
||||||
public String catalog() { return ""; }
|
|
||||||
public JoinColumn[] inverseJoinColumns() { return new JoinColumn[0]; }
|
|
||||||
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultAuditJoinTable;
|
|
||||||
}
|
|
||||||
}
|
|
@ -30,6 +30,8 @@
|
|||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||||
|
import org.hibernate.envers.configuration.metadata.reader.ClassAuditingData;
|
||||||
|
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
|
||||||
import org.hibernate.envers.entities.EntityConfiguration;
|
import org.hibernate.envers.entities.EntityConfiguration;
|
||||||
import org.hibernate.envers.entities.IdMappingData;
|
import org.hibernate.envers.entities.IdMappingData;
|
||||||
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
|
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
|
||||||
@ -101,13 +103,13 @@ void addRevisionType(Element any_mapping) {
|
|||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
|
void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
|
||||||
EntityXmlMappingData xmlMappingData, PersistentPropertyAuditingData persistentPropertyAuditingData,
|
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
|
||||||
boolean insertable, boolean firstPass) {
|
boolean insertable, boolean firstPass) {
|
||||||
Type type = value.getType();
|
Type type = value.getType();
|
||||||
|
|
||||||
// only first pass
|
// only first pass
|
||||||
if (firstPass) {
|
if (firstPass) {
|
||||||
if (basicMetadataGenerator.addBasic(parent, persistentPropertyAuditingData, value, currentMapper,
|
if (basicMetadataGenerator.addBasic(parent, propertyAuditingData, value, currentMapper,
|
||||||
insertable, false)) {
|
insertable, false)) {
|
||||||
// The property was mapped by the basic generator.
|
// The property was mapped by the basic generator.
|
||||||
return;
|
return;
|
||||||
@ -116,18 +118,18 @@ void addValue(Element parent, Value value, CompositeMapperBuilder currentMappe
|
|||||||
|
|
||||||
if (type instanceof ComponentType) {
|
if (type instanceof ComponentType) {
|
||||||
// both passes
|
// both passes
|
||||||
componentMetadataGenerator.addComponent(parent, persistentPropertyAuditingData, value, currentMapper,
|
componentMetadataGenerator.addComponent(parent, propertyAuditingData, value, currentMapper,
|
||||||
entityName, xmlMappingData, firstPass);
|
entityName, xmlMappingData, firstPass);
|
||||||
} else if (type instanceof ManyToOneType) {
|
} else if (type instanceof ManyToOneType) {
|
||||||
// only second pass
|
// only second pass
|
||||||
if (!firstPass) {
|
if (!firstPass) {
|
||||||
toOneRelationMetadataGenerator.addToOne(parent, persistentPropertyAuditingData, value, currentMapper,
|
toOneRelationMetadataGenerator.addToOne(parent, propertyAuditingData, value, currentMapper,
|
||||||
entityName, insertable);
|
entityName, insertable);
|
||||||
}
|
}
|
||||||
} else if (type instanceof OneToOneType) {
|
} else if (type instanceof OneToOneType) {
|
||||||
// only second pass
|
// only second pass
|
||||||
if (!firstPass) {
|
if (!firstPass) {
|
||||||
toOneRelationMetadataGenerator.addOneToOneNotOwning(persistentPropertyAuditingData, value,
|
toOneRelationMetadataGenerator.addOneToOneNotOwning(propertyAuditingData, value,
|
||||||
currentMapper, entityName);
|
currentMapper, entityName);
|
||||||
}
|
}
|
||||||
} else if (type instanceof CollectionType) {
|
} else if (type instanceof CollectionType) {
|
||||||
@ -135,35 +137,35 @@ void addValue(Element parent, Value value, CompositeMapperBuilder currentMappe
|
|||||||
if (!firstPass) {
|
if (!firstPass) {
|
||||||
CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(this,
|
CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(this,
|
||||||
(Collection) value, currentMapper, entityName, xmlMappingData,
|
(Collection) value, currentMapper, entityName, xmlMappingData,
|
||||||
persistentPropertyAuditingData);
|
propertyAuditingData);
|
||||||
collectionMetadataGenerator.addCollection();
|
collectionMetadataGenerator.addCollection();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (firstPass) {
|
if (firstPass) {
|
||||||
// If we got here in the first pass, it means the basic mapper didn't map it, and none of the
|
// If we got here in the first pass, it means the basic mapper didn't map it, and none of the
|
||||||
// above branches either.
|
// above branches either.
|
||||||
throwUnsupportedTypeException(type, entityName, persistentPropertyAuditingData.getName());
|
throwUnsupportedTypeException(type, entityName, propertyAuditingData.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
private void addProperties(Element parent, Iterator<Property> properties, CompositeMapperBuilder currentMapper,
|
private void addProperties(Element parent, Iterator<Property> properties, CompositeMapperBuilder currentMapper,
|
||||||
PersistentClassAuditingData auditingData, String entityName, EntityXmlMappingData xmlMappingData,
|
ClassAuditingData auditingData, String entityName, EntityXmlMappingData xmlMappingData,
|
||||||
boolean firstPass) {
|
boolean firstPass) {
|
||||||
while (properties.hasNext()) {
|
while (properties.hasNext()) {
|
||||||
Property property = properties.next();
|
Property property = properties.next();
|
||||||
String propertyName = property.getName();
|
String propertyName = property.getName();
|
||||||
if (auditingData.getPropertyAuditingData(propertyName) != null) {
|
PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData(propertyName);
|
||||||
addValue(parent, property.getValue(), currentMapper, entityName,
|
if (propertyAuditingData != null) {
|
||||||
xmlMappingData, auditingData.getPropertyAuditingData(propertyName),
|
addValue(parent, property.getValue(), currentMapper, entityName, xmlMappingData, propertyAuditingData,
|
||||||
property.isInsertable(), firstPass);
|
property.isInsertable(), firstPass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
private void createJoins(PersistentClass pc, Element parent, PersistentClassAuditingData auditingData) {
|
private void createJoins(PersistentClass pc, Element parent, ClassAuditingData auditingData) {
|
||||||
Iterator<Join> joins = pc.getJoinIterator();
|
Iterator<Join> joins = pc.getJoinIterator();
|
||||||
|
|
||||||
Map<Join, Element> joinElements = new HashMap<Join, Element>();
|
Map<Join, Element> joinElements = new HashMap<Join, Element>();
|
||||||
@ -200,7 +202,7 @@ private void createJoins(PersistentClass pc, Element parent, PersistentClassAudi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
private void addJoins(PersistentClass pc, CompositeMapperBuilder currentMapper, PersistentClassAuditingData auditingData,
|
private void addJoins(PersistentClass pc, CompositeMapperBuilder currentMapper, ClassAuditingData auditingData,
|
||||||
String entityName, EntityXmlMappingData xmlMappingData,boolean firstPass) {
|
String entityName, EntityXmlMappingData xmlMappingData,boolean firstPass) {
|
||||||
Iterator<Join> joins = pc.getJoinIterator();
|
Iterator<Join> joins = pc.getJoinIterator();
|
||||||
|
|
||||||
@ -255,7 +257,7 @@ private Triple<Element, ExtendedPropertyMapper, String> generateInheritanceMappi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
public void generateFirstPass(PersistentClass pc, PersistentClassAuditingData auditingData,
|
public void generateFirstPass(PersistentClass pc, ClassAuditingData auditingData,
|
||||||
EntityXmlMappingData xmlMappingData) {
|
EntityXmlMappingData xmlMappingData) {
|
||||||
String schema = auditingData.getAuditTable().schema();
|
String schema = auditingData.getAuditTable().schema();
|
||||||
if (StringTools.isEmpty(schema)) {
|
if (StringTools.isEmpty(schema)) {
|
||||||
@ -334,7 +336,7 @@ public void generateFirstPass(PersistentClass pc, PersistentClassAuditingData au
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
public void generateSecondPass(PersistentClass pc, PersistentClassAuditingData auditingData,
|
public void generateSecondPass(PersistentClass pc, ClassAuditingData auditingData,
|
||||||
EntityXmlMappingData xmlMappingData) {
|
EntityXmlMappingData xmlMappingData) {
|
||||||
String entityName = pc.getEntityName();
|
String entityName = pc.getEntityName();
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
import org.hibernate.envers.entities.mapper.SimpleMapperBuilder;
|
import org.hibernate.envers.entities.mapper.SimpleMapperBuilder;
|
||||||
|
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
|
||||||
|
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.SimpleValue;
|
import org.hibernate.mapping.SimpleValue;
|
||||||
@ -43,16 +44,16 @@
|
|||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public final class BasicMetadataGenerator {
|
public final class BasicMetadataGenerator {
|
||||||
boolean addBasic(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData,
|
boolean addBasic(Element parent, PropertyAuditingData propertyAuditingData,
|
||||||
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
||||||
Type type = value.getType();
|
Type type = value.getType();
|
||||||
|
|
||||||
if (type instanceof ImmutableType || type instanceof MutableType) {
|
if (type instanceof ImmutableType || type instanceof MutableType) {
|
||||||
addSimpleValue(parent, persistentPropertyAuditingData, value, mapper, insertable, key);
|
addSimpleValue(parent, propertyAuditingData, value, mapper, insertable, key);
|
||||||
} else if (type instanceof CustomType || type instanceof CompositeCustomType) {
|
} else if (type instanceof CustomType || type instanceof CompositeCustomType) {
|
||||||
addCustomValue(parent, persistentPropertyAuditingData, value, mapper, insertable, key);
|
addCustomValue(parent, propertyAuditingData, value, mapper, insertable, key);
|
||||||
} else if ("org.hibernate.type.PrimitiveByteArrayBlobType".equals(type.getClass().getName())) {
|
} else if ("org.hibernate.type.PrimitiveByteArrayBlobType".equals(type.getClass().getName())) {
|
||||||
addSimpleValue(parent, persistentPropertyAuditingData, value, mapper, insertable, key);
|
addSimpleValue(parent, propertyAuditingData, value, mapper, insertable, key);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -61,25 +62,25 @@ boolean addBasic(Element parent, PersistentPropertyAuditingData persistentProper
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
private void addSimpleValue(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData,
|
private void addSimpleValue(Element parent, PropertyAuditingData propertyAuditingData,
|
||||||
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
Element prop_mapping = MetadataTools.addProperty(parent, persistentPropertyAuditingData.getName(),
|
Element prop_mapping = MetadataTools.addProperty(parent, propertyAuditingData.getName(),
|
||||||
value.getType().getName(), insertable, key);
|
value.getType().getName(), insertable, key);
|
||||||
MetadataTools.addColumns(prop_mapping, (Iterator<Column>) value.getColumnIterator());
|
MetadataTools.addColumns(prop_mapping, (Iterator<Column>) value.getColumnIterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// A null mapper means that we only want to add xml mappings
|
// A null mapper means that we only want to add xml mappings
|
||||||
if (mapper != null) {
|
if (mapper != null) {
|
||||||
mapper.add(persistentPropertyAuditingData.getPropertyData());
|
mapper.add(propertyAuditingData.getPropertyData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
private void addCustomValue(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData,
|
private void addCustomValue(Element parent, PropertyAuditingData propertyAuditingData,
|
||||||
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
Element prop_mapping = MetadataTools.addProperty(parent, persistentPropertyAuditingData.getName(),
|
Element prop_mapping = MetadataTools.addProperty(parent, propertyAuditingData.getName(),
|
||||||
null, insertable, key);
|
null, insertable, key);
|
||||||
|
|
||||||
//CustomType propertyType = (CustomType) value.getType();
|
//CustomType propertyType = (CustomType) value.getType();
|
||||||
@ -102,7 +103,7 @@ private void addCustomValue(Element parent, PersistentPropertyAuditingData persi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mapper != null) {
|
if (mapper != null) {
|
||||||
mapper.add(persistentPropertyAuditingData.getPropertyData());
|
mapper.add(propertyAuditingData.getPropertyData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
import org.hibernate.envers.ModificationStore;
|
import org.hibernate.envers.ModificationStore;
|
||||||
|
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
|
||||||
import org.hibernate.envers.entities.EntityConfiguration;
|
import org.hibernate.envers.entities.EntityConfiguration;
|
||||||
import org.hibernate.envers.entities.IdMappingData;
|
import org.hibernate.envers.entities.IdMappingData;
|
||||||
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
|
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
|
||||||
@ -89,7 +90,7 @@ public final class CollectionMetadataGenerator {
|
|||||||
private final CompositeMapperBuilder currentMapper;
|
private final CompositeMapperBuilder currentMapper;
|
||||||
private final String referencingEntityName;
|
private final String referencingEntityName;
|
||||||
private final EntityXmlMappingData xmlMappingData;
|
private final EntityXmlMappingData xmlMappingData;
|
||||||
private final PersistentPropertyAuditingData persistentPropertyAuditingData;
|
private final PropertyAuditingData propertyAuditingData;
|
||||||
|
|
||||||
private final EntityConfiguration referencingEntityConfiguration;
|
private final EntityConfiguration referencingEntityConfiguration;
|
||||||
/**
|
/**
|
||||||
@ -105,22 +106,22 @@ public final class CollectionMetadataGenerator {
|
|||||||
* @param referencingEntityName Name of the entity that owns this collection.
|
* @param referencingEntityName Name of the entity that owns this collection.
|
||||||
* @param xmlMappingData In case this collection requires a middle table, additional mapping documents will
|
* @param xmlMappingData In case this collection requires a middle table, additional mapping documents will
|
||||||
* be created using this object.
|
* be created using this object.
|
||||||
* @param persistentPropertyAuditingData Property auditing (meta-)data. Among other things, holds the name of the
|
* @param propertyAuditingData Property auditing (meta-)data. Among other things, holds the name of the
|
||||||
* property that references the collection in the referencing entity, the user data for middle (join)
|
* property that references the collection in the referencing entity, the user data for middle (join)
|
||||||
* table and the value of the <code>@MapKey</code> annotation, if there was one.
|
* table and the value of the <code>@MapKey</code> annotation, if there was one.
|
||||||
*/
|
*/
|
||||||
public CollectionMetadataGenerator(AuditMetadataGenerator mainGenerator,
|
public CollectionMetadataGenerator(AuditMetadataGenerator mainGenerator,
|
||||||
Collection propertyValue, CompositeMapperBuilder currentMapper,
|
Collection propertyValue, CompositeMapperBuilder currentMapper,
|
||||||
String referencingEntityName, EntityXmlMappingData xmlMappingData,
|
String referencingEntityName, EntityXmlMappingData xmlMappingData,
|
||||||
PersistentPropertyAuditingData persistentPropertyAuditingData) {
|
PropertyAuditingData propertyAuditingData) {
|
||||||
this.mainGenerator = mainGenerator;
|
this.mainGenerator = mainGenerator;
|
||||||
this.propertyValue = propertyValue;
|
this.propertyValue = propertyValue;
|
||||||
this.currentMapper = currentMapper;
|
this.currentMapper = currentMapper;
|
||||||
this.referencingEntityName = referencingEntityName;
|
this.referencingEntityName = referencingEntityName;
|
||||||
this.xmlMappingData = xmlMappingData;
|
this.xmlMappingData = xmlMappingData;
|
||||||
this.persistentPropertyAuditingData = persistentPropertyAuditingData;
|
this.propertyAuditingData = propertyAuditingData;
|
||||||
|
|
||||||
this.propertyName = persistentPropertyAuditingData.getName();
|
this.propertyName = propertyAuditingData.getName();
|
||||||
|
|
||||||
referencingEntityConfiguration = mainGenerator.getEntitiesConfigurations().get(referencingEntityName);
|
referencingEntityConfiguration = mainGenerator.getEntitiesConfigurations().get(referencingEntityName);
|
||||||
if (referencingEntityConfiguration == null) {
|
if (referencingEntityConfiguration == null) {
|
||||||
@ -189,7 +190,7 @@ private void addOneToManyAttached() {
|
|||||||
// Creating common mapper data.
|
// Creating common mapper data.
|
||||||
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
|
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
|
||||||
mainGenerator.getVerEntCfg(), referencedEntityName,
|
mainGenerator.getVerEntCfg(), referencedEntityName,
|
||||||
persistentPropertyAuditingData.getPropertyData(),
|
propertyAuditingData.getPropertyData(),
|
||||||
referencingIdData, queryGenerator);
|
referencingIdData, queryGenerator);
|
||||||
|
|
||||||
// Checking the type of the collection and adding an appropriate mapper.
|
// Checking the type of the collection and adding an appropriate mapper.
|
||||||
@ -235,9 +236,9 @@ private void addWithMiddleTable() {
|
|||||||
// Generating the name of the middle table
|
// Generating the name of the middle table
|
||||||
String auditMiddleTableName;
|
String auditMiddleTableName;
|
||||||
String auditMiddleEntityName;
|
String auditMiddleEntityName;
|
||||||
if (!StringTools.isEmpty(persistentPropertyAuditingData.getJoinTable().name())) {
|
if (!StringTools.isEmpty(propertyAuditingData.getJoinTable().name())) {
|
||||||
auditMiddleTableName = persistentPropertyAuditingData.getJoinTable().name();
|
auditMiddleTableName = propertyAuditingData.getJoinTable().name();
|
||||||
auditMiddleEntityName = persistentPropertyAuditingData.getJoinTable().name();
|
auditMiddleEntityName = propertyAuditingData.getJoinTable().name();
|
||||||
} else {
|
} else {
|
||||||
String middleTableName = getMiddleTableName(propertyValue, referencingEntityName);
|
String middleTableName = getMiddleTableName(propertyValue, referencingEntityName);
|
||||||
auditMiddleTableName = mainGenerator.getVerEntCfg().getAuditTableName(null, middleTableName);
|
auditMiddleTableName = mainGenerator.getVerEntCfg().getAuditTableName(null, middleTableName);
|
||||||
@ -301,7 +302,7 @@ private void addWithMiddleTable() {
|
|||||||
// Generating the element mapping.
|
// Generating the element mapping.
|
||||||
// ******
|
// ******
|
||||||
MiddleComponentData elementComponentData = addValueToMiddleTable(propertyValue.getElement(), middleEntityXml,
|
MiddleComponentData elementComponentData = addValueToMiddleTable(propertyValue.getElement(), middleEntityXml,
|
||||||
queryGeneratorBuilder, referencedPrefix, persistentPropertyAuditingData.getJoinTable().inverseJoinColumns());
|
queryGeneratorBuilder, referencedPrefix, propertyAuditingData.getJoinTable().inverseJoinColumns());
|
||||||
|
|
||||||
// ******
|
// ******
|
||||||
// Generating the index mapping, if an index exists.
|
// Generating the index mapping, if an index exists.
|
||||||
@ -317,7 +318,7 @@ private void addWithMiddleTable() {
|
|||||||
// Creating common data
|
// Creating common data
|
||||||
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
|
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
|
||||||
mainGenerator.getVerEntCfg(), auditMiddleEntityName,
|
mainGenerator.getVerEntCfg(), auditMiddleEntityName,
|
||||||
persistentPropertyAuditingData.getPropertyData(),
|
propertyAuditingData.getPropertyData(),
|
||||||
referencingIdData, queryGenerator);
|
referencingIdData, queryGenerator);
|
||||||
|
|
||||||
// Checking the type of the collection and adding an appropriate mapper.
|
// Checking the type of the collection and adding an appropriate mapper.
|
||||||
@ -332,7 +333,7 @@ private void addWithMiddleTable() {
|
|||||||
private MiddleComponentData addIndex(Element middleEntityXml, QueryGeneratorBuilder queryGeneratorBuilder) {
|
private MiddleComponentData addIndex(Element middleEntityXml, QueryGeneratorBuilder queryGeneratorBuilder) {
|
||||||
if (propertyValue instanceof IndexedCollection) {
|
if (propertyValue instanceof IndexedCollection) {
|
||||||
IndexedCollection indexedValue = (IndexedCollection) propertyValue;
|
IndexedCollection indexedValue = (IndexedCollection) propertyValue;
|
||||||
String mapKey = persistentPropertyAuditingData.getMapKey();
|
String mapKey = propertyAuditingData.getMapKey();
|
||||||
if (mapKey == null) {
|
if (mapKey == null) {
|
||||||
// This entity doesn't specify a javax.persistence.MapKey. Mapping it to the middle entity.
|
// This entity doesn't specify a javax.persistence.MapKey. Mapping it to the middle entity.
|
||||||
return addValueToMiddleTable(indexedValue.getIndex(), middleEntityXml,
|
return addValueToMiddleTable(indexedValue.getIndex(), middleEntityXml,
|
||||||
@ -348,7 +349,7 @@ private MiddleComponentData addIndex(Element middleEntityXml, QueryGeneratorBuil
|
|||||||
} else {
|
} else {
|
||||||
// The key of the map is a property of the entity.
|
// The key of the map is a property of the entity.
|
||||||
return new MiddleComponentData(new MiddleMapKeyPropertyComponentMapper(mapKey,
|
return new MiddleComponentData(new MiddleMapKeyPropertyComponentMapper(mapKey,
|
||||||
persistentPropertyAuditingData.getAccessType()), currentIndex);
|
propertyAuditingData.getAccessType()), currentIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -401,7 +402,7 @@ private MiddleComponentData addValueToMiddleTable(Value value, Element xmlMappin
|
|||||||
} else {
|
} else {
|
||||||
// Last but one parameter: collection components are always insertable
|
// Last but one parameter: collection components are always insertable
|
||||||
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
|
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
|
||||||
new PersistentPropertyAuditingData(prefix, "field", ModificationStore.FULL), value, null,
|
new PropertyAuditingData(prefix, "field", ModificationStore.FULL), value, null,
|
||||||
true, true);
|
true, true);
|
||||||
|
|
||||||
if (mapped) {
|
if (mapped) {
|
||||||
@ -419,30 +420,30 @@ private void addMapper(CommonCollectionMapperData commonCollectionMapperData, Mi
|
|||||||
MiddleComponentData indexComponentData) {
|
MiddleComponentData indexComponentData) {
|
||||||
Type type = propertyValue.getType();
|
Type type = propertyValue.getType();
|
||||||
if (type instanceof SortedSetType) {
|
if (type instanceof SortedSetType) {
|
||||||
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
|
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||||
new BasicCollectionMapper<Set>(commonCollectionMapperData,
|
new BasicCollectionMapper<Set>(commonCollectionMapperData,
|
||||||
TreeSet.class, SortedSetProxy.class, elementComponentData));
|
TreeSet.class, SortedSetProxy.class, elementComponentData));
|
||||||
} else if (type instanceof SetType) {
|
} else if (type instanceof SetType) {
|
||||||
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
|
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||||
new BasicCollectionMapper<Set>(commonCollectionMapperData,
|
new BasicCollectionMapper<Set>(commonCollectionMapperData,
|
||||||
HashSet.class, SetProxy.class, elementComponentData));
|
HashSet.class, SetProxy.class, elementComponentData));
|
||||||
} else if (type instanceof SortedMapType) {
|
} else if (type instanceof SortedMapType) {
|
||||||
// Indexed collection, so <code>indexComponentData</code> is not null.
|
// Indexed collection, so <code>indexComponentData</code> is not null.
|
||||||
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
|
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||||
new MapCollectionMapper<Map>(commonCollectionMapperData,
|
new MapCollectionMapper<Map>(commonCollectionMapperData,
|
||||||
TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData));
|
TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData));
|
||||||
} else if (type instanceof MapType) {
|
} else if (type instanceof MapType) {
|
||||||
// Indexed collection, so <code>indexComponentData</code> is not null.
|
// Indexed collection, so <code>indexComponentData</code> is not null.
|
||||||
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
|
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||||
new MapCollectionMapper<Map>(commonCollectionMapperData,
|
new MapCollectionMapper<Map>(commonCollectionMapperData,
|
||||||
HashMap.class, MapProxy.class, elementComponentData, indexComponentData));
|
HashMap.class, MapProxy.class, elementComponentData, indexComponentData));
|
||||||
} else if (type instanceof BagType) {
|
} else if (type instanceof BagType) {
|
||||||
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
|
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||||
new BasicCollectionMapper<List>(commonCollectionMapperData,
|
new BasicCollectionMapper<List>(commonCollectionMapperData,
|
||||||
ArrayList.class, ListProxy.class, elementComponentData));
|
ArrayList.class, ListProxy.class, elementComponentData));
|
||||||
} else if (type instanceof ListType) {
|
} else if (type instanceof ListType) {
|
||||||
// Indexed collection, so <code>indexComponentData</code> is not null.
|
// Indexed collection, so <code>indexComponentData</code> is not null.
|
||||||
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
|
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
|
||||||
new ListCollectionMapper(commonCollectionMapperData,
|
new ListCollectionMapper(commonCollectionMapperData,
|
||||||
elementComponentData, indexComponentData));
|
elementComponentData, indexComponentData));
|
||||||
} else {
|
} else {
|
||||||
@ -462,10 +463,10 @@ private void storeMiddleEntityRelationInformation(String mappedBy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Element createMiddleEntityXml(String auditMiddleTableName, String auditMiddleEntityName) {
|
private Element createMiddleEntityXml(String auditMiddleTableName, String auditMiddleEntityName) {
|
||||||
String schema = StringTools.isEmpty(persistentPropertyAuditingData.getJoinTable().schema()) ?
|
String schema = StringTools.isEmpty(propertyAuditingData.getJoinTable().schema()) ?
|
||||||
propertyValue.getCollectionTable().getSchema() : persistentPropertyAuditingData.getJoinTable().schema();
|
propertyValue.getCollectionTable().getSchema() : propertyAuditingData.getJoinTable().schema();
|
||||||
String catalog = StringTools.isEmpty(persistentPropertyAuditingData.getJoinTable().catalog()) ?
|
String catalog = StringTools.isEmpty(propertyAuditingData.getJoinTable().catalog()) ?
|
||||||
propertyValue.getCollectionTable().getCatalog() : persistentPropertyAuditingData.getJoinTable().catalog();
|
propertyValue.getCollectionTable().getCatalog() : propertyAuditingData.getJoinTable().catalog();
|
||||||
|
|
||||||
Element middleEntityXml = MetadataTools.createEntity(xmlMappingData.newAdditionalMapping(),
|
Element middleEntityXml = MetadataTools.createEntity(xmlMappingData.newAdditionalMapping(),
|
||||||
new AuditTableData(auditMiddleEntityName, auditMiddleTableName, schema, catalog), null);
|
new AuditTableData(auditMiddleEntityName, auditMiddleTableName, schema, catalog), null);
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
|
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
|
||||||
import org.hibernate.envers.ModificationStore;
|
import org.hibernate.envers.configuration.metadata.reader.ComponentAuditingData;
|
||||||
|
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
@ -21,25 +22,24 @@ public final class ComponentMetadataGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
public void addComponent(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData,
|
public void addComponent(Element parent, PropertyAuditingData propertyAuditingData,
|
||||||
Value value, CompositeMapperBuilder mapper, String entityName,
|
Value value, CompositeMapperBuilder mapper, String entityName,
|
||||||
EntityXmlMappingData xmlMappingData, boolean firstPass) {
|
EntityXmlMappingData xmlMappingData, boolean firstPass) {
|
||||||
Component prop_component = (Component) value;
|
Component prop_component = (Component) value;
|
||||||
|
|
||||||
CompositeMapperBuilder componentMapper = mapper.addComponent(persistentPropertyAuditingData.getPropertyData());
|
CompositeMapperBuilder componentMapper = mapper.addComponent(propertyAuditingData.getPropertyData());
|
||||||
|
|
||||||
|
// The property auditing data must be for a component.
|
||||||
|
ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
|
||||||
|
|
||||||
// Adding all properties of the component
|
// Adding all properties of the component
|
||||||
Iterator<Property> properties = (Iterator<Property>) prop_component.getPropertyIterator();
|
Iterator<Property> properties = (Iterator<Property>) prop_component.getPropertyIterator();
|
||||||
while (properties.hasNext()) {
|
while (properties.hasNext()) {
|
||||||
Property property = properties.next();
|
Property property = properties.next();
|
||||||
// The name of the property in the entity will consist of the name of the component property concatenated
|
|
||||||
// with the name of the property in the bean, to avoid conflicts.
|
|
||||||
PersistentPropertyAuditingData propertyAuditingData = new PersistentComponentPropertyAuditingData(
|
|
||||||
persistentPropertyAuditingData.getName() + "_" + property.getName(),
|
|
||||||
property.getName(), property.getPropertyAccessorName(), ModificationStore.FULL);
|
|
||||||
|
|
||||||
mainGenerator.addValue(parent, property.getValue(), componentMapper,
|
mainGenerator.addValue(parent, property.getValue(), componentMapper, entityName, xmlMappingData,
|
||||||
entityName, xmlMappingData, propertyAuditingData, property.isInsertable(), firstPass);
|
componentAuditingData.getPropertyAuditingData(property.getName()),
|
||||||
|
property.isInsertable(), firstPass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
import org.dom4j.Element;
|
import org.dom4j.Element;
|
||||||
import org.dom4j.tree.DefaultElement;
|
import org.dom4j.tree.DefaultElement;
|
||||||
import org.hibernate.envers.ModificationStore;
|
import org.hibernate.envers.ModificationStore;
|
||||||
|
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
|
||||||
import org.hibernate.envers.entities.IdMappingData;
|
import org.hibernate.envers.entities.IdMappingData;
|
||||||
import org.hibernate.envers.entities.PropertyData;
|
import org.hibernate.envers.entities.PropertyData;
|
||||||
import org.hibernate.envers.entities.mapper.SimpleMapperBuilder;
|
import org.hibernate.envers.entities.mapper.SimpleMapperBuilder;
|
||||||
@ -130,8 +131,8 @@ private PropertyData getIdPropertyData(Property property) {
|
|||||||
ModificationStore.FULL);
|
ModificationStore.FULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PersistentPropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
|
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
|
||||||
return new PersistentPropertyAuditingData(property.getName(), property.getPropertyAccessorName(),
|
return new PropertyAuditingData(property.getName(), property.getPropertyAccessorName(),
|
||||||
ModificationStore.FULL);
|
ModificationStore.FULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
import org.hibernate.envers.entities.mapper.id.IdMapper;
|
import org.hibernate.envers.entities.mapper.id.IdMapper;
|
||||||
import org.hibernate.envers.entities.mapper.relation.OneToOneNotOwningMapper;
|
import org.hibernate.envers.entities.mapper.relation.OneToOneNotOwningMapper;
|
||||||
import org.hibernate.envers.entities.mapper.relation.ToOneIdMapper;
|
import org.hibernate.envers.entities.mapper.relation.ToOneIdMapper;
|
||||||
|
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.mapping.OneToOne;
|
import org.hibernate.mapping.OneToOne;
|
||||||
@ -49,7 +50,7 @@ public final class ToOneRelationMetadataGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
void addToOne(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData, Value value,
|
void addToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value,
|
||||||
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
|
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
|
||||||
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
|
||||||
|
|
||||||
@ -60,30 +61,30 @@ void addToOne(Element parent, PersistentPropertyAuditingData persistentPropertyA
|
|||||||
|
|
||||||
IdMappingData idMapping = configuration.getIdMappingData();
|
IdMappingData idMapping = configuration.getIdMappingData();
|
||||||
|
|
||||||
String lastPropertyPrefix = persistentPropertyAuditingData.getName() + "_";
|
String lastPropertyPrefix = propertyAuditingData.getName() + "_";
|
||||||
|
|
||||||
// Generating the id mapper for the relation
|
// Generating the id mapper for the relation
|
||||||
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
|
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
|
||||||
|
|
||||||
// Storing information about this relation
|
// Storing information about this relation
|
||||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(
|
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(
|
||||||
persistentPropertyAuditingData.getName(), referencedEntityName, relMapper);
|
propertyAuditingData.getName(), referencedEntityName, relMapper);
|
||||||
|
|
||||||
// Adding an element to the mapping corresponding to the references entity id's
|
// Adding an element to the mapping corresponding to the references entity id's
|
||||||
Element properties = (Element) idMapping.getXmlRelationMapping().clone();
|
Element properties = (Element) idMapping.getXmlRelationMapping().clone();
|
||||||
properties.addAttribute("name", persistentPropertyAuditingData.getName());
|
properties.addAttribute("name", propertyAuditingData.getName());
|
||||||
|
|
||||||
MetadataTools.prefixNamesInPropertyElement(properties, lastPropertyPrefix,
|
MetadataTools.prefixNamesInPropertyElement(properties, lastPropertyPrefix,
|
||||||
MetadataTools.getColumnNameIterator(value.getColumnIterator()), false, insertable);
|
MetadataTools.getColumnNameIterator(value.getColumnIterator()), false, insertable);
|
||||||
parent.add(properties);
|
parent.add(properties);
|
||||||
|
|
||||||
// Adding mapper for the id
|
// Adding mapper for the id
|
||||||
PropertyData propertyData = persistentPropertyAuditingData.getPropertyData();
|
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||||
mapper.addComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName));
|
mapper.addComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
void addOneToOneNotOwning(PersistentPropertyAuditingData persistentPropertyAuditingData, Value value,
|
void addOneToOneNotOwning(PropertyAuditingData propertyAuditingData, Value value,
|
||||||
CompositeMapperBuilder mapper, String entityName) {
|
CompositeMapperBuilder mapper, String entityName) {
|
||||||
OneToOne propertyValue = (OneToOne) value;
|
OneToOne propertyValue = (OneToOne) value;
|
||||||
|
|
||||||
@ -108,11 +109,11 @@ void addOneToOneNotOwning(PersistentPropertyAuditingData persistentPropertyAudit
|
|||||||
|
|
||||||
// Storing information about this relation
|
// Storing information about this relation
|
||||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneNotOwningRelation(
|
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneNotOwningRelation(
|
||||||
persistentPropertyAuditingData.getName(), owningReferencePropertyName,
|
propertyAuditingData.getName(), owningReferencePropertyName,
|
||||||
referencedEntityName, ownedIdMapper);
|
referencedEntityName, ownedIdMapper);
|
||||||
|
|
||||||
// Adding mapper for the id
|
// Adding mapper for the id
|
||||||
PropertyData propertyData = persistentPropertyAuditingData.getPropertyData();
|
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||||
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(owningReferencePropertyName,
|
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(owningReferencePropertyName,
|
||||||
referencedEntityName, propertyData));
|
referencedEntityName, propertyData));
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* 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.configuration.metadata.reader;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.hibernate.envers.SecondaryAuditTable;
|
||||||
|
import org.hibernate.envers.*;
|
||||||
|
import org.hibernate.envers.ModificationStore;
|
||||||
|
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||||
|
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||||
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
import org.hibernate.mapping.Property;
|
||||||
|
import org.jboss.envers.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class to read versioning meta-data from annotations on a persistent class.
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
* @author Sebastian Komander
|
||||||
|
*/
|
||||||
|
public final class AnnotationsMetadataReader {
|
||||||
|
private final GlobalConfiguration globalCfg;
|
||||||
|
private final ReflectionManager reflectionManager;
|
||||||
|
private final PersistentClass pc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is filled with information read from annotations and returned by the <code>getVersioningData</code>
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
private final ClassAuditingData auditData;
|
||||||
|
|
||||||
|
public AnnotationsMetadataReader(GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
|
||||||
|
PersistentClass pc) {
|
||||||
|
this.globalCfg = globalCfg;
|
||||||
|
this.reflectionManager = reflectionManager;
|
||||||
|
this.pc = pc;
|
||||||
|
|
||||||
|
auditData = new ClassAuditingData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModificationStore getDefaultAudited(XClass clazz) {
|
||||||
|
Audited defaultAudited = clazz.getAnnotation(Audited.class);
|
||||||
|
|
||||||
|
if (defaultAudited != null) {
|
||||||
|
return defaultAudited.modStore();
|
||||||
|
} else {
|
||||||
|
Versioned defaultVersioned = clazz.getAnnotation(Versioned.class);
|
||||||
|
if (defaultVersioned != null) {
|
||||||
|
return ModificationStore.FULL;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAuditTable(XClass clazz) {
|
||||||
|
AuditTable auditTable = clazz.getAnnotation(AuditTable.class);
|
||||||
|
if (auditTable != null) {
|
||||||
|
auditData.setAuditTable(auditTable);
|
||||||
|
} else {
|
||||||
|
auditData.setAuditTable(getDefaultAuditTable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAuditSecondaryTables(XClass clazz) {
|
||||||
|
// Getting information on secondary tables
|
||||||
|
SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation(SecondaryAuditTable.class);
|
||||||
|
if (secondaryVersionsTable1 != null) {
|
||||||
|
auditData.getSecondaryTableDictionary().put(secondaryVersionsTable1.secondaryTableName(),
|
||||||
|
secondaryVersionsTable1.secondaryAuditTableName());
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondaryAuditTables secondaryAuditTables = clazz.getAnnotation(SecondaryAuditTables.class);
|
||||||
|
if (secondaryAuditTables != null) {
|
||||||
|
for (SecondaryAuditTable secondaryAuditTable2 : secondaryAuditTables.value()) {
|
||||||
|
auditData.getSecondaryTableDictionary().put(secondaryAuditTable2.secondaryTableName(),
|
||||||
|
secondaryAuditTable2.secondaryAuditTableName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassAuditingData getAuditData() {
|
||||||
|
if (pc.getClassName() == null) {
|
||||||
|
return auditData;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
XClass xclass = reflectionManager.classForName(pc.getClassName(), this.getClass());
|
||||||
|
|
||||||
|
ModificationStore defaultStore = getDefaultAudited(xclass);
|
||||||
|
if (defaultStore != null) {
|
||||||
|
auditData.setDefaultAudited(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
new AuditedPropertiesReader(defaultStore, new PersistentClassPropertiesSource(xclass), auditData,
|
||||||
|
globalCfg, "").read();
|
||||||
|
|
||||||
|
addAuditTable(xclass);
|
||||||
|
addAuditSecondaryTables(xclass);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new MappingException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return auditData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuditTable defaultAuditTable = new AuditTable() {
|
||||||
|
public String value() { return ""; }
|
||||||
|
public String schema() { return ""; }
|
||||||
|
public String catalog() { return ""; }
|
||||||
|
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
private AuditTable getDefaultAuditTable() {
|
||||||
|
return defaultAuditTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PersistentClassPropertiesSource implements PersistentPropertiesSource {
|
||||||
|
private final XClass xclass;
|
||||||
|
|
||||||
|
private PersistentClassPropertiesSource(XClass xclass) { this.xclass = xclass; }
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
public Iterator<Property> getPropertyIterator() { return pc.getPropertyIterator(); }
|
||||||
|
public Property getProperty(String propertyName) { return pc.getProperty(propertyName); }
|
||||||
|
public XClass getXClass() { return xclass; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.hibernate.envers.configuration.metadata.reader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementations hold other audited properties.
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public interface AuditedPropertiesHolder {
|
||||||
|
/**
|
||||||
|
* Add an audited property.
|
||||||
|
* @param propertyName Name of the audited property.
|
||||||
|
* @param auditingData Data for the audited property.
|
||||||
|
*/
|
||||||
|
void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param propertyName Name of a property.
|
||||||
|
* @return Auditing data for the property.
|
||||||
|
*/
|
||||||
|
PropertyAuditingData getPropertyAuditingData(String propertyName);
|
||||||
|
}
|
@ -0,0 +1,210 @@
|
|||||||
|
package org.hibernate.envers.configuration.metadata.reader;
|
||||||
|
|
||||||
|
import org.hibernate.envers.ModificationStore;
|
||||||
|
import org.hibernate.envers.NotAudited;
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
import org.hibernate.envers.AuditJoinTable;
|
||||||
|
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||||
|
import static org.hibernate.envers.tools.Tools.*;
|
||||||
|
import org.hibernate.envers.tools.MappingTools;
|
||||||
|
import org.hibernate.mapping.Property;
|
||||||
|
import org.hibernate.mapping.Component;
|
||||||
|
import org.hibernate.mapping.Value;
|
||||||
|
import org.hibernate.annotations.common.reflection.XProperty;
|
||||||
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
|
import org.jboss.envers.Versioned;
|
||||||
|
|
||||||
|
import javax.persistence.Version;
|
||||||
|
import javax.persistence.MapKey;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads persistent properties form a
|
||||||
|
* {@link org.hibernate.envers.configuration.metadata.reader.PersistentPropertiesSource}
|
||||||
|
* and adds the ones that are audited to a
|
||||||
|
* {@link org.hibernate.envers.configuration.metadata.reader.AuditedPropertiesHolder},
|
||||||
|
* filling all the auditing data.
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public class AuditedPropertiesReader {
|
||||||
|
private final ModificationStore defaultStore;
|
||||||
|
private final PersistentPropertiesSource persistentPropertiesSource;
|
||||||
|
private final AuditedPropertiesHolder auditedPropertiesHolder;
|
||||||
|
private final GlobalConfiguration globalCfg;
|
||||||
|
private final String propertyNamePrefix;
|
||||||
|
|
||||||
|
private final Set<String> propertyAccessedPersistentProperties;
|
||||||
|
private final Set<String> fieldAccessedPersistentProperties;
|
||||||
|
|
||||||
|
public AuditedPropertiesReader(ModificationStore defaultStore,
|
||||||
|
PersistentPropertiesSource persistentPropertiesSource,
|
||||||
|
AuditedPropertiesHolder auditedPropertiesHolder,
|
||||||
|
GlobalConfiguration globalCfg,
|
||||||
|
String propertyNamePrefix) {
|
||||||
|
this.defaultStore = defaultStore;
|
||||||
|
this.persistentPropertiesSource = persistentPropertiesSource;
|
||||||
|
this.auditedPropertiesHolder = auditedPropertiesHolder;
|
||||||
|
this.globalCfg = globalCfg;
|
||||||
|
this.propertyNamePrefix = propertyNamePrefix;
|
||||||
|
|
||||||
|
propertyAccessedPersistentProperties = newHashSet();
|
||||||
|
fieldAccessedPersistentProperties = newHashSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void read() {
|
||||||
|
// First reading the access types for the persistent properties.
|
||||||
|
readPersistentPropertiesAccess();
|
||||||
|
|
||||||
|
// Adding all properties from the given class.
|
||||||
|
addPropertiesFromClass(persistentPropertiesSource.getXClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readPersistentPropertiesAccess() {
|
||||||
|
Iterator propertyIter = persistentPropertiesSource.getPropertyIterator();
|
||||||
|
while (propertyIter.hasNext()) {
|
||||||
|
Property property = (Property) propertyIter.next();
|
||||||
|
if ("field".equals(property.getPropertyAccessorName())) {
|
||||||
|
fieldAccessedPersistentProperties.add(property.getName());
|
||||||
|
} else {
|
||||||
|
propertyAccessedPersistentProperties.add(property.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPropertiesFromClass(XClass clazz) {
|
||||||
|
XClass superclazz = clazz.getSuperclass();
|
||||||
|
if (!"java.lang.Object".equals(superclazz.getName())) {
|
||||||
|
addPropertiesFromClass(superclazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties);
|
||||||
|
addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFromProperties(Iterable<XProperty> properties, String accessType, Set<String> persistentProperties) {
|
||||||
|
for (XProperty property : properties) {
|
||||||
|
// If this is not a persistent property, with the same access type as currently checked,
|
||||||
|
// it's not audited as well.
|
||||||
|
if (persistentProperties.contains(property.getName())) {
|
||||||
|
Value propertyValue = persistentPropertiesSource.getProperty(property.getName()).getValue();
|
||||||
|
|
||||||
|
PropertyAuditingData propertyData;
|
||||||
|
boolean isAudited;
|
||||||
|
if (propertyValue instanceof Component) {
|
||||||
|
ComponentAuditingData componentData = new ComponentAuditingData();
|
||||||
|
isAudited = fillPropertyData(property, componentData, accessType);
|
||||||
|
|
||||||
|
// TODO: component stuff
|
||||||
|
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
|
||||||
|
property.getType(), (Component) propertyValue);
|
||||||
|
new AuditedPropertiesReader(ModificationStore.FULL, componentPropertiesSource, componentData,
|
||||||
|
globalCfg, propertyNamePrefix+ MappingTools.createComponentPrefix(property.getName()))
|
||||||
|
.read();
|
||||||
|
|
||||||
|
propertyData = componentData;
|
||||||
|
} else {
|
||||||
|
propertyData = new PropertyAuditingData();
|
||||||
|
isAudited = fillPropertyData(property, propertyData, accessType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAudited) {
|
||||||
|
// Now we know that the property is audited
|
||||||
|
auditedPropertiesHolder.addPropertyAuditingData(property.getName(), propertyData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a property is audited and if yes, fills all of its data.
|
||||||
|
* @param property Property to check.
|
||||||
|
* @param propertyData Property data, on which to set this property's modification store.
|
||||||
|
* @param accessType Access type for the property.
|
||||||
|
* @return False if this property is not audited.
|
||||||
|
*/
|
||||||
|
private boolean fillPropertyData(XProperty property, PropertyAuditingData propertyData,
|
||||||
|
String accessType) {
|
||||||
|
|
||||||
|
// check if a property is declared as not audited to exclude it
|
||||||
|
// useful if a class is audited but some properties should be excluded
|
||||||
|
NotAudited unVer = property.getAnnotation(NotAudited.class);
|
||||||
|
if (unVer != null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// if the optimistic locking field has to be unversioned and the current property
|
||||||
|
// is the optimistic locking field, don't audit it
|
||||||
|
if (globalCfg.isDoNotAuditOptimisticLockingField()) {
|
||||||
|
Version jpaVer = property.getAnnotation(Version.class);
|
||||||
|
if (jpaVer != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking if this property is explicitly audited or if all properties are.
|
||||||
|
Audited aud = property.getAnnotation(Audited.class);
|
||||||
|
Versioned ver = property.getAnnotation(Versioned.class);
|
||||||
|
if (aud != null) {
|
||||||
|
propertyData.setStore(aud.modStore());
|
||||||
|
} else if (ver != null) {
|
||||||
|
propertyData.setStore(ModificationStore.FULL);
|
||||||
|
} else {
|
||||||
|
if (defaultStore != null) {
|
||||||
|
propertyData.setStore(defaultStore);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
propertyData.setName(propertyNamePrefix + property.getName());
|
||||||
|
propertyData.setBeanName(property.getName());
|
||||||
|
propertyData.setAccessType(accessType);
|
||||||
|
|
||||||
|
addPropertyJoinTables(property, propertyData);
|
||||||
|
addPropertyMapKey(property, propertyData);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
|
||||||
|
MapKey mapKey = property.getAnnotation(MapKey.class);
|
||||||
|
if (mapKey != null) {
|
||||||
|
propertyData.setMapKey(mapKey.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
|
||||||
|
AuditJoinTable joinTable = property.getAnnotation(AuditJoinTable.class);
|
||||||
|
if (joinTable != null) {
|
||||||
|
propertyData.setJoinTable(joinTable);
|
||||||
|
} else {
|
||||||
|
propertyData.setJoinTable(DEFAULT_AUDIT_JOIN_TABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() {
|
||||||
|
public String name() { return ""; }
|
||||||
|
public String schema() { return ""; }
|
||||||
|
public String catalog() { return ""; }
|
||||||
|
public JoinColumn[] inverseJoinColumns() { return new JoinColumn[0]; }
|
||||||
|
public Class<? extends Annotation> annotationType() { return this.getClass(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
private class ComponentPropertiesSource implements PersistentPropertiesSource {
|
||||||
|
private final XClass xclass;
|
||||||
|
private final Component component;
|
||||||
|
|
||||||
|
private ComponentPropertiesSource(XClass xclass, Component component) {
|
||||||
|
this.xclass = xclass;
|
||||||
|
this.component = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
public Iterator<Property> getPropertyIterator() { return component.getPropertyIterator(); }
|
||||||
|
public Property getProperty(String propertyName) { return component.getProperty(propertyName); }
|
||||||
|
public XClass getXClass() { return xclass; }
|
||||||
|
}
|
||||||
|
}
|
@ -21,37 +21,39 @@
|
|||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.metadata;
|
package org.hibernate.envers.configuration.metadata.reader;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.AuditTable;
|
import org.hibernate.envers.AuditTable;
|
||||||
import org.hibernate.envers.tools.Tools;
|
import static org.hibernate.envers.tools.Tools.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Sebastian Komander
|
* @author Sebastian Komander
|
||||||
*/
|
*/
|
||||||
public class PersistentClassAuditingData {
|
public class ClassAuditingData implements AuditedPropertiesHolder {
|
||||||
public PersistentClassAuditingData() {
|
private final Map<String, PropertyAuditingData> properties;
|
||||||
properties = Tools.newHashMap();
|
private final Map<String, String> secondaryTableDictionary;
|
||||||
secondaryTableDictionary = Tools.newHashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, PersistentPropertyAuditingData> properties;
|
|
||||||
private AuditTable auditTable;
|
private AuditTable auditTable;
|
||||||
private Map<String, String> secondaryTableDictionary;
|
|
||||||
/**
|
/**
|
||||||
* True if the class is audited globally (this helps to cover the cases when there are no fields in the class,
|
* True if the class is audited globally (this helps to cover the cases when there are no fields in the class,
|
||||||
* but it's still audited).
|
* but it's still audited).
|
||||||
*/
|
*/
|
||||||
private boolean defaultAudited;
|
private boolean defaultAudited;
|
||||||
|
|
||||||
public Map<String, PersistentPropertyAuditingData> getProperties() {
|
public ClassAuditingData() {
|
||||||
return properties;
|
properties = newHashMap();
|
||||||
|
secondaryTableDictionary = newHashMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PersistentPropertyAuditingData getPropertyAuditingData(String propertyName) {
|
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
||||||
|
properties.put(propertyName, auditingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
||||||
return properties.get(propertyName);
|
return properties.get(propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,10 +74,6 @@ public void setDefaultAudited(boolean defaultAudited) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAudited() {
|
public boolean isAudited() {
|
||||||
if (defaultAudited || properties.size() > 0) {
|
return defaultAudited || properties.size() > 0;
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,25 +22,28 @@
|
|||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.metadata;
|
package org.hibernate.envers.configuration.metadata.reader;
|
||||||
|
|
||||||
import org.hibernate.envers.ModificationStore;
|
import static org.hibernate.envers.tools.Tools.*;
|
||||||
import org.hibernate.envers.entities.PropertyData;
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Audit mapping meta-data for component.
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class PersistentComponentPropertyAuditingData extends PersistentPropertyAuditingData {
|
public class ComponentAuditingData extends PropertyAuditingData implements AuditedPropertiesHolder {
|
||||||
private final String beanName;
|
private final Map<String, PropertyAuditingData> properties;
|
||||||
|
|
||||||
public PersistentComponentPropertyAuditingData(String name, String beanName, String accessType,
|
public ComponentAuditingData() {
|
||||||
ModificationStore store) {
|
this.properties = newHashMap();
|
||||||
super(name, accessType, store);
|
|
||||||
|
|
||||||
this.beanName = beanName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyData getPropertyData() {
|
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
|
||||||
return new PropertyData(getName(), beanName, getAccessType(), getStore());
|
properties.put(propertyName, auditingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
|
||||||
|
return properties.get(propertyName);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package org.hibernate.envers.configuration.metadata.reader;
|
||||||
|
|
||||||
|
import org.hibernate.mapping.Property;
|
||||||
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A source of data on persistent properties of a class or component.
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public interface PersistentPropertiesSource {
|
||||||
|
Iterator<Property> getPropertyIterator();
|
||||||
|
Property getProperty(String propertyName);
|
||||||
|
XClass getXClass();
|
||||||
|
}
|
@ -22,7 +22,7 @@
|
|||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.configuration.metadata;
|
package org.hibernate.envers.configuration.metadata.reader;
|
||||||
|
|
||||||
import org.hibernate.envers.ModificationStore;
|
import org.hibernate.envers.ModificationStore;
|
||||||
import org.hibernate.envers.AuditJoinTable;
|
import org.hibernate.envers.AuditJoinTable;
|
||||||
@ -31,18 +31,20 @@
|
|||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class PersistentPropertyAuditingData {
|
public class PropertyAuditingData {
|
||||||
private String name;
|
private String name;
|
||||||
|
private String beanName;
|
||||||
private ModificationStore store;
|
private ModificationStore store;
|
||||||
private String mapKey;
|
private String mapKey;
|
||||||
private AuditJoinTable joinTable;
|
private AuditJoinTable joinTable;
|
||||||
private String accessType;
|
private String accessType;
|
||||||
|
|
||||||
public PersistentPropertyAuditingData() {
|
public PropertyAuditingData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PersistentPropertyAuditingData(String name, String accessType, ModificationStore store) {
|
public PropertyAuditingData(String name, String accessType, ModificationStore store) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.beanName = name;
|
||||||
this.accessType = accessType;
|
this.accessType = accessType;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
}
|
}
|
||||||
@ -55,6 +57,14 @@ public void setName(String name) {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getBeanName() {
|
||||||
|
return beanName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanName(String beanName) {
|
||||||
|
this.beanName = beanName;
|
||||||
|
}
|
||||||
|
|
||||||
public ModificationStore getStore() {
|
public ModificationStore getStore() {
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
@ -88,6 +98,6 @@ public void setAccessType(String accessType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public PropertyData getPropertyData() {
|
public PropertyData getPropertyData() {
|
||||||
return new PropertyData(name, name, accessType, store);
|
return new PropertyData(name, beanName, accessType, store);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -32,6 +32,7 @@
|
|||||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||||
import org.hibernate.envers.tools.reflection.ReflectionTools;
|
import org.hibernate.envers.tools.reflection.ReflectionTools;
|
||||||
import org.hibernate.envers.tools.Tools;
|
import org.hibernate.envers.tools.Tools;
|
||||||
|
import org.hibernate.envers.tools.MappingTools;
|
||||||
|
|
||||||
import org.hibernate.collection.PersistentCollection;
|
import org.hibernate.collection.PersistentCollection;
|
||||||
import org.hibernate.property.Getter;
|
import org.hibernate.property.Getter;
|
||||||
@ -120,9 +121,30 @@ public List<PersistentCollectionChangeData> mapCollectionChanges(String referenc
|
|||||||
PersistentCollection newColl,
|
PersistentCollection newColl,
|
||||||
Serializable oldColl,
|
Serializable oldColl,
|
||||||
Serializable id) {
|
Serializable id) {
|
||||||
|
// Name of the properyt, to which we will delegate the mapping.
|
||||||
|
String delegatePropertyName;
|
||||||
|
|
||||||
|
// Checking if the property name doesn't reference a collection in a component - then the name will containa a .
|
||||||
|
int dotIndex = referencingPropertyName.indexOf('.');
|
||||||
|
if (dotIndex != -1) {
|
||||||
|
// Computing the name of the component
|
||||||
|
String componentName = referencingPropertyName.substring(0, dotIndex);
|
||||||
|
// And the name of the property in the component
|
||||||
|
String propertyInComponentName = MappingTools.createComponentPrefix(componentName)
|
||||||
|
+ referencingPropertyName.substring(dotIndex+1);
|
||||||
|
|
||||||
|
// We need to get the mapper for the component.
|
||||||
|
referencingPropertyName = componentName;
|
||||||
|
// As this is a component, we delegate to the property in the component.
|
||||||
|
delegatePropertyName = propertyInComponentName;
|
||||||
|
} else {
|
||||||
|
// If this is not a component, we delegate to the same property.
|
||||||
|
delegatePropertyName = referencingPropertyName;
|
||||||
|
}
|
||||||
|
|
||||||
PropertyMapper mapper = properties.get(propertyDatas.get(referencingPropertyName));
|
PropertyMapper mapper = properties.get(propertyDatas.get(referencingPropertyName));
|
||||||
if (mapper != null) {
|
if (mapper != null) {
|
||||||
return mapper.mapCollectionChanges(referencingPropertyName, newColl, oldColl, id);
|
return mapper.mapCollectionChanges(delegatePropertyName, newColl, oldColl, id);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.hibernate.envers.tools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public class MappingTools {
|
||||||
|
/**
|
||||||
|
* @param componentName Name of the component, that is, name of the property in the entity that references the
|
||||||
|
* component.
|
||||||
|
* @return A prefix for properties in the given component.
|
||||||
|
*/
|
||||||
|
public static String createComponentPrefix(String componentName) {
|
||||||
|
return componentName + "_";
|
||||||
|
}
|
||||||
|
}
|
@ -23,9 +23,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.envers.test.entities.components;
|
package org.hibernate.envers.test.entities.components;
|
||||||
|
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
|
@Embeddable
|
||||||
public class Component1 {
|
public class Component1 {
|
||||||
private String str1;
|
private String str1;
|
||||||
|
|
||||||
|
@ -23,9 +23,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.envers.test.entities.components;
|
package org.hibernate.envers.test.entities.components;
|
||||||
|
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
|
@Embeddable
|
||||||
public class Component2 {
|
public class Component2 {
|
||||||
private String str5;
|
private String str5;
|
||||||
|
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.hibernate.envers.test.entities.StrTestEntity;
|
||||||
|
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
@Embeddable
|
||||||
|
public class ManyToOneComponent {
|
||||||
|
@ManyToOne
|
||||||
|
private StrTestEntity entity;
|
||||||
|
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
public ManyToOneComponent(StrTestEntity entity, String data) {
|
||||||
|
this.entity = entity;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ManyToOneComponent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StrTestEntity getEntity() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntity(StrTestEntity entity) {
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
ManyToOneComponent that = (ManyToOneComponent) 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 "ManyToOneComponent(str1 = " + data + ")";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* 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.Embedded;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class ManyToOneComponentTestEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
@Audited
|
||||||
|
private ManyToOneComponent comp1;
|
||||||
|
|
||||||
|
public ManyToOneComponentTestEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ManyToOneComponentTestEntity(Integer id, ManyToOneComponent comp1) {
|
||||||
|
this.id = id;
|
||||||
|
this.comp1 = comp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ManyToOneComponentTestEntity(ManyToOneComponent comp1) {
|
||||||
|
this.comp1 = comp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ManyToOneComponent getComp1() {
|
||||||
|
return comp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComp1(ManyToOneComponent comp1) {
|
||||||
|
this.comp1 = comp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
ManyToOneComponentTestEntity that = (ManyToOneComponentTestEntity) o;
|
||||||
|
|
||||||
|
if (comp1 != null ? !comp1.equals(that.comp1) : that.comp1 != null) return false;
|
||||||
|
if (id != null ? !id.equals(that.id) : that.id != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = id != null ? id.hashCode() : 0;
|
||||||
|
result = 31 * result + (comp1 != null ? comp1.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "MTOCTE(id = " + id + ", comp1 = " + comp1 + ")";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.hibernate.envers.test.entities.StrTestEntity;
|
||||||
|
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
@Embeddable
|
||||||
|
public class OneToManyComponent {
|
||||||
|
@OneToMany
|
||||||
|
private Set<StrTestEntity> entities = new HashSet<StrTestEntity>();
|
||||||
|
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
public OneToManyComponent(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OneToManyComponent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<StrTestEntity> getEntities() {
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntities(Set<StrTestEntity> entities) {
|
||||||
|
this.entities = entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
OneToManyComponent that = (OneToManyComponent) o;
|
||||||
|
|
||||||
|
if (data != null ? !data.equals(that.data) : that.data != null) return false;
|
||||||
|
if (entities != null ? !entities.equals(that.entities) : that.entities != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = entities != null ? entities.hashCode() : 0;
|
||||||
|
result = 31 * result + (data != null ? data.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "OneToManyComponent(data = " + data + ")";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* 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.Embedded;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class OneToManyComponentTestEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
@Audited
|
||||||
|
private OneToManyComponent comp1;
|
||||||
|
|
||||||
|
public OneToManyComponentTestEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public OneToManyComponentTestEntity(Integer id, OneToManyComponent comp1) {
|
||||||
|
this.id = id;
|
||||||
|
this.comp1 = comp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OneToManyComponentTestEntity(OneToManyComponent comp1) {
|
||||||
|
this.comp1 = comp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OneToManyComponent getComp1() {
|
||||||
|
return comp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComp1(OneToManyComponent comp1) {
|
||||||
|
this.comp1 = comp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
OneToManyComponentTestEntity that = (OneToManyComponentTestEntity) o;
|
||||||
|
|
||||||
|
if (comp1 != null ? !comp1.equals(that.comp1) : that.comp1 != null) return false;
|
||||||
|
if (id != null ? !id.equals(that.id) : that.id != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = id != null ? id.hashCode() : 0;
|
||||||
|
result = 31 * result + (comp1 != null ? comp1.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "OTMCTE(id = " + id + ", comp1 = " + comp1 + ")";
|
||||||
|
}
|
||||||
|
}
|
@ -42,7 +42,7 @@ public void configure(Ejb3Configuration cfg) {
|
|||||||
cfg.addAnnotatedClass(MixedAccessTypeEntity.class);
|
cfg.addAnnotatedClass(MixedAccessTypeEntity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeClass(dependsOnMethods = "init")
|
@Test
|
||||||
public void initData() {
|
public void initData() {
|
||||||
EntityManager em = getEntityManager();
|
EntityManager em = getEntityManager();
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
@ -57,12 +57,12 @@ public void initData() {
|
|||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(dependsOnMethods = "initData")
|
||||||
public void testRevisionsCounts() {
|
public void testRevisionsCounts() {
|
||||||
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(MixedAccessTypeEntity.class, id1));
|
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(MixedAccessTypeEntity.class, id1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(dependsOnMethods = "initData")
|
||||||
public void testHistoryOfId1() {
|
public void testHistoryOfId1() {
|
||||||
MixedAccessTypeEntity ver1 = new MixedAccessTypeEntity(id1, "data");
|
MixedAccessTypeEntity ver1 = new MixedAccessTypeEntity(id1, "data");
|
||||||
MixedAccessTypeEntity ver2 = new MixedAccessTypeEntity(id1, "data2");
|
MixedAccessTypeEntity ver2 = new MixedAccessTypeEntity(id1, "data2");
|
||||||
|
@ -43,7 +43,7 @@ public void configure(Ejb3Configuration cfg) {
|
|||||||
cfg.addAnnotatedClass(IntTestEntity.class);
|
cfg.addAnnotatedClass(IntTestEntity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeClass(dependsOnMethods = "init")
|
@Test
|
||||||
public void initData() {
|
public void initData() {
|
||||||
EntityManager em = getEntityManager();
|
EntityManager em = getEntityManager();
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
@ -58,12 +58,12 @@ public void initData() {
|
|||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(dependsOnMethods = "initData")
|
||||||
public void testRevisionsCounts() {
|
public void testRevisionsCounts() {
|
||||||
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(IntTestEntity.class, id1));
|
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(IntTestEntity.class, id1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(dependsOnMethods = "initData")
|
||||||
public void testHistoryOfId1() {
|
public void testHistoryOfId1() {
|
||||||
IntTestEntity ver1 = new IntTestEntity(10, id1);
|
IntTestEntity ver1 = new IntTestEntity(10, id1);
|
||||||
IntTestEntity ver2 = new IntTestEntity(20, id1);
|
IntTestEntity ver2 = new IntTestEntity(20, id1);
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* 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.components.relations;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.hibernate.envers.test.AbstractEntityTest;
|
||||||
|
import org.hibernate.envers.test.entities.components.relations.ManyToOneComponentTestEntity;
|
||||||
|
import org.hibernate.envers.test.entities.components.relations.ManyToOneComponent;
|
||||||
|
import org.hibernate.envers.test.entities.StrTestEntity;
|
||||||
|
import org.testng.annotations.BeforeClass;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public class ManyToOneInComponent extends AbstractEntityTest {
|
||||||
|
private Integer mtocte_id1;
|
||||||
|
private Integer ste_id1;
|
||||||
|
private Integer ste_id2;
|
||||||
|
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
cfg.addAnnotatedClass(ManyToOneComponentTestEntity.class);
|
||||||
|
cfg.addAnnotatedClass(StrTestEntity.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initData() {
|
||||||
|
// Revision 1
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
StrTestEntity ste1 = new StrTestEntity();
|
||||||
|
ste1.setStr("str1");
|
||||||
|
|
||||||
|
StrTestEntity ste2 = new StrTestEntity();
|
||||||
|
ste2.setStr("str2");
|
||||||
|
|
||||||
|
em.persist(ste1);
|
||||||
|
em.persist(ste2);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 2
|
||||||
|
em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
ManyToOneComponentTestEntity mtocte1 = new ManyToOneComponentTestEntity(new ManyToOneComponent(ste1, "data1"));
|
||||||
|
|
||||||
|
em.persist(mtocte1);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 3
|
||||||
|
em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
mtocte1 = em.find(ManyToOneComponentTestEntity.class, mtocte1.getId());
|
||||||
|
mtocte1.getComp1().setEntity(ste2);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
mtocte_id1 = mtocte1.getId();
|
||||||
|
ste_id1 = ste1.getId();
|
||||||
|
ste_id2 = ste2.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "initData")
|
||||||
|
public void testRevisionsCounts() {
|
||||||
|
assert Arrays.asList(2, 3).equals(getAuditReader().getRevisions(ManyToOneComponentTestEntity.class, mtocte_id1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "initData")
|
||||||
|
public void testHistoryOfId1() {
|
||||||
|
StrTestEntity ste1 = getEntityManager().find(StrTestEntity.class, ste_id1);
|
||||||
|
StrTestEntity ste2 = getEntityManager().find(StrTestEntity.class, ste_id2);
|
||||||
|
|
||||||
|
ManyToOneComponentTestEntity ver2 = new ManyToOneComponentTestEntity(mtocte_id1, new ManyToOneComponent(ste1, "data1"));
|
||||||
|
ManyToOneComponentTestEntity ver3 = new ManyToOneComponentTestEntity(mtocte_id1, new ManyToOneComponent(ste2, "data1"));
|
||||||
|
|
||||||
|
assert getAuditReader().find(ManyToOneComponentTestEntity.class, mtocte_id1, 1) == null;
|
||||||
|
assert getAuditReader().find(ManyToOneComponentTestEntity.class, mtocte_id1, 2).equals(ver2);
|
||||||
|
assert getAuditReader().find(ManyToOneComponentTestEntity.class, mtocte_id1, 3).equals(ver3);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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.components.relations;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.hibernate.envers.test.AbstractEntityTest;
|
||||||
|
import org.hibernate.envers.test.entities.components.relations.OneToManyComponentTestEntity;
|
||||||
|
import org.hibernate.envers.test.entities.components.relations.OneToManyComponent;
|
||||||
|
import org.hibernate.envers.test.entities.StrTestEntity;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public class OneToManyInComponent extends AbstractEntityTest {
|
||||||
|
private Integer otmcte_id1;
|
||||||
|
private Integer ste_id1;
|
||||||
|
private Integer ste_id2;
|
||||||
|
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
cfg.addAnnotatedClass(OneToManyComponentTestEntity.class);
|
||||||
|
cfg.addAnnotatedClass(StrTestEntity.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initData() {
|
||||||
|
// Revision 1
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
StrTestEntity ste1 = new StrTestEntity();
|
||||||
|
ste1.setStr("str1");
|
||||||
|
|
||||||
|
StrTestEntity ste2 = new StrTestEntity();
|
||||||
|
ste2.setStr("str2");
|
||||||
|
|
||||||
|
em.persist(ste1);
|
||||||
|
em.persist(ste2);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 2
|
||||||
|
em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
OneToManyComponentTestEntity otmcte1 = new OneToManyComponentTestEntity(new OneToManyComponent("data1"));
|
||||||
|
otmcte1.getComp1().getEntities().add(ste1);
|
||||||
|
|
||||||
|
em.persist(otmcte1);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 3
|
||||||
|
em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
otmcte1 = em.find(OneToManyComponentTestEntity.class, otmcte1.getId());
|
||||||
|
otmcte1.getComp1().getEntities().add(ste2);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
otmcte_id1 = otmcte1.getId();
|
||||||
|
ste_id1 = ste1.getId();
|
||||||
|
ste_id2 = ste2.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "initData")
|
||||||
|
public void testRevisionsCounts() {
|
||||||
|
assert Arrays.asList(2, 3).equals(getAuditReader().getRevisions(OneToManyComponentTestEntity.class, otmcte_id1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "initData")
|
||||||
|
public void testHistoryOfId1() {
|
||||||
|
StrTestEntity ste1 = getEntityManager().find(StrTestEntity.class, ste_id1);
|
||||||
|
StrTestEntity ste2 = getEntityManager().find(StrTestEntity.class, ste_id2);
|
||||||
|
|
||||||
|
OneToManyComponentTestEntity ver2 = new OneToManyComponentTestEntity(otmcte_id1, new OneToManyComponent("data1"));
|
||||||
|
ver2.getComp1().getEntities().add(ste1);
|
||||||
|
OneToManyComponentTestEntity ver3 = new OneToManyComponentTestEntity(otmcte_id1, new OneToManyComponent("data1"));
|
||||||
|
ver3.getComp1().getEntities().add(ste1);
|
||||||
|
ver3.getComp1().getEntities().add(ste2);
|
||||||
|
|
||||||
|
assert getAuditReader().find(OneToManyComponentTestEntity.class, otmcte_id1, 1) == null;
|
||||||
|
assert getAuditReader().find(OneToManyComponentTestEntity.class, otmcte_id1, 2).equals(ver2);
|
||||||
|
assert getAuditReader().find(OneToManyComponentTestEntity.class, otmcte_id1, 3).equals(ver3);
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
<package name="org.hibernate.envers.test.integration.collection" />
|
<package name="org.hibernate.envers.test.integration.collection" />
|
||||||
<package name="org.hibernate.envers.test.integration.collection.mapkey" />
|
<package name="org.hibernate.envers.test.integration.collection.mapkey" />
|
||||||
<package name="org.hibernate.envers.test.integration.components" />
|
<package name="org.hibernate.envers.test.integration.components" />
|
||||||
|
<package name="org.hibernate.envers.test.integration.components.relations" />
|
||||||
<package name="org.hibernate.envers.test.integration.customtype" />
|
<package name="org.hibernate.envers.test.integration.customtype" />
|
||||||
<package name="org.hibernate.envers.test.integration.data" />
|
<package name="org.hibernate.envers.test.integration.data" />
|
||||||
<package name="org.hibernate.envers.test.integration.flush" />
|
<package name="org.hibernate.envers.test.integration.flush" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user