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:
Adam Warski 2009-01-20 08:13:54 +00:00
parent 6d56458124
commit bf8e6fed6f
28 changed files with 1175 additions and 409 deletions

View File

@ -37,9 +37,9 @@ import org.dom4j.Element;
import org.dom4j.io.DOMWriter;
import org.dom4j.io.OutputFormat;
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.PersistentClassAuditingData;
import org.hibernate.envers.configuration.metadata.reader.ClassAuditingData;
import org.hibernate.envers.configuration.metadata.AuditMetadataGenerator;
import org.hibernate.envers.entities.EntitiesConfigurations;
import org.hibernate.envers.tools.StringTools;
@ -64,8 +64,8 @@ public class EntitiesConfigurator {
// Sorting the persistent class topologically - superclass always before subclass
Iterator<PersistentClass> classes = GraphTopologicalSort.sort(new PersistentClassGraphDefiner(cfg)).iterator();
Map<PersistentClass, PersistentClassAuditingData> pcDatas =
new HashMap<PersistentClass, PersistentClassAuditingData>();
Map<PersistentClass, ClassAuditingData> pcDatas =
new HashMap<PersistentClass, ClassAuditingData>();
Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
// First pass
@ -74,7 +74,7 @@ public class EntitiesConfigurator {
// Collecting information from annotations on the persistent class pc
AnnotationsMetadataReader annotationsMetadataReader =
new AnnotationsMetadataReader(globalCfg, reflectionManager, pc);
PersistentClassAuditingData auditData = annotationsMetadataReader.getAuditData();
ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
if (auditData.isAudited()) {
pcDatas.put(pc, auditData);
@ -90,7 +90,7 @@ public class EntitiesConfigurator {
}
// Second pass
for (Map.Entry<PersistentClass, PersistentClassAuditingData> pcDatasEntry : pcDatas.entrySet()) {
for (Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : pcDatas.entrySet()) {
EntityXmlMappingData xmlMappingData = xmlMappings.get(pcDatasEntry.getKey());
auditMetaGen.generateSecondPass(pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData);

View File

@ -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;
}
}

View File

@ -30,6 +30,8 @@ import java.util.Map;
import org.dom4j.Element;
import org.hibernate.envers.configuration.GlobalConfiguration;
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.IdMappingData;
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
@ -100,14 +102,14 @@ public final class AuditMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PersistentPropertyAuditingData persistentPropertyAuditingData,
void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean firstPass) {
Type type = value.getType();
// only first pass
if (firstPass) {
if (basicMetadataGenerator.addBasic(parent, persistentPropertyAuditingData, value, currentMapper,
if (basicMetadataGenerator.addBasic(parent, propertyAuditingData, value, currentMapper,
insertable, false)) {
// The property was mapped by the basic generator.
return;
@ -116,18 +118,18 @@ public final class AuditMetadataGenerator {
if (type instanceof ComponentType) {
// both passes
componentMetadataGenerator.addComponent(parent, persistentPropertyAuditingData, value, currentMapper,
componentMetadataGenerator.addComponent(parent, propertyAuditingData, value, currentMapper,
entityName, xmlMappingData, firstPass);
} else if (type instanceof ManyToOneType) {
// only second pass
if (!firstPass) {
toOneRelationMetadataGenerator.addToOne(parent, persistentPropertyAuditingData, value, currentMapper,
toOneRelationMetadataGenerator.addToOne(parent, propertyAuditingData, value, currentMapper,
entityName, insertable);
}
} else if (type instanceof OneToOneType) {
// only second pass
if (!firstPass) {
toOneRelationMetadataGenerator.addOneToOneNotOwning(persistentPropertyAuditingData, value,
toOneRelationMetadataGenerator.addOneToOneNotOwning(propertyAuditingData, value,
currentMapper, entityName);
}
} else if (type instanceof CollectionType) {
@ -135,35 +137,35 @@ public final class AuditMetadataGenerator {
if (!firstPass) {
CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(this,
(Collection) value, currentMapper, entityName, xmlMappingData,
persistentPropertyAuditingData);
propertyAuditingData);
collectionMetadataGenerator.addCollection();
}
} else {
if (firstPass) {
// If we got here in the first pass, it means the basic mapper didn't map it, and none of the
// above branches either.
throwUnsupportedTypeException(type, entityName, persistentPropertyAuditingData.getName());
throwUnsupportedTypeException(type, entityName, propertyAuditingData.getName());
}
}
}
@SuppressWarnings({"unchecked"})
private void addProperties(Element parent, Iterator<Property> properties, CompositeMapperBuilder currentMapper,
PersistentClassAuditingData auditingData, String entityName, EntityXmlMappingData xmlMappingData,
ClassAuditingData auditingData, String entityName, EntityXmlMappingData xmlMappingData,
boolean firstPass) {
while (properties.hasNext()) {
Property property = properties.next();
String propertyName = property.getName();
if (auditingData.getPropertyAuditingData(propertyName) != null) {
addValue(parent, property.getValue(), currentMapper, entityName,
xmlMappingData, auditingData.getPropertyAuditingData(propertyName),
property.isInsertable(), firstPass);
PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData(propertyName);
if (propertyAuditingData != null) {
addValue(parent, property.getValue(), currentMapper, entityName, xmlMappingData, propertyAuditingData,
property.isInsertable(), firstPass);
}
}
}
@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();
Map<Join, Element> joinElements = new HashMap<Join, Element>();
@ -200,7 +202,7 @@ public final class AuditMetadataGenerator {
}
@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) {
Iterator<Join> joins = pc.getJoinIterator();
@ -255,7 +257,7 @@ public final class AuditMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
public void generateFirstPass(PersistentClass pc, PersistentClassAuditingData auditingData,
public void generateFirstPass(PersistentClass pc, ClassAuditingData auditingData,
EntityXmlMappingData xmlMappingData) {
String schema = auditingData.getAuditTable().schema();
if (StringTools.isEmpty(schema)) {
@ -334,7 +336,7 @@ public final class AuditMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
public void generateSecondPass(PersistentClass pc, PersistentClassAuditingData auditingData,
public void generateSecondPass(PersistentClass pc, ClassAuditingData auditingData,
EntityXmlMappingData xmlMappingData) {
String entityName = pc.getEntityName();

View File

@ -28,6 +28,7 @@ import java.util.Properties;
import org.dom4j.Element;
import org.hibernate.envers.entities.mapper.SimpleMapperBuilder;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.SimpleValue;
@ -43,16 +44,16 @@ import org.hibernate.type.Type;
* @author Adam Warski (adam at warski dot org)
*/
public final class BasicMetadataGenerator {
boolean addBasic(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData,
boolean addBasic(Element parent, PropertyAuditingData propertyAuditingData,
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
Type type = value.getType();
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) {
addCustomValue(parent, persistentPropertyAuditingData, value, mapper, insertable, key);
addCustomValue(parent, propertyAuditingData, value, mapper, insertable, key);
} 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 {
return false;
}
@ -61,25 +62,25 @@ public final class BasicMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
private void addSimpleValue(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData,
private void addSimpleValue(Element parent, PropertyAuditingData propertyAuditingData,
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
if (parent != null) {
Element prop_mapping = MetadataTools.addProperty(parent, persistentPropertyAuditingData.getName(),
Element prop_mapping = MetadataTools.addProperty(parent, propertyAuditingData.getName(),
value.getType().getName(), insertable, key);
MetadataTools.addColumns(prop_mapping, (Iterator<Column>) value.getColumnIterator());
}
// A null mapper means that we only want to add xml mappings
if (mapper != null) {
mapper.add(persistentPropertyAuditingData.getPropertyData());
mapper.add(propertyAuditingData.getPropertyData());
}
}
@SuppressWarnings({"unchecked"})
private void addCustomValue(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData,
private void addCustomValue(Element parent, PropertyAuditingData propertyAuditingData,
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
if (parent != null) {
Element prop_mapping = MetadataTools.addProperty(parent, persistentPropertyAuditingData.getName(),
Element prop_mapping = MetadataTools.addProperty(parent, propertyAuditingData.getName(),
null, insertable, key);
//CustomType propertyType = (CustomType) value.getType();
@ -102,7 +103,7 @@ public final class BasicMetadataGenerator {
}
if (mapper != null) {
mapper.add(persistentPropertyAuditingData.getPropertyData());
mapper.add(propertyAuditingData.getPropertyData());
}
}
}

View File

@ -36,6 +36,7 @@ import javax.persistence.JoinColumn;
import org.dom4j.Element;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
@ -89,7 +90,7 @@ public final class CollectionMetadataGenerator {
private final CompositeMapperBuilder currentMapper;
private final String referencingEntityName;
private final EntityXmlMappingData xmlMappingData;
private final PersistentPropertyAuditingData persistentPropertyAuditingData;
private final PropertyAuditingData propertyAuditingData;
private final EntityConfiguration referencingEntityConfiguration;
/**
@ -97,7 +98,7 @@ public final class CollectionMetadataGenerator {
*/
private final String referencedEntityName;
/**
/**
* @param mainGenerator Main generator, giving access to configuration and the basic mapper.
* @param propertyValue Value of the collection, as mapped by Hibernate.
* @param currentMapper Mapper, to which the appropriate {@link org.hibernate.envers.entities.mapper.PropertyMapper}
@ -105,22 +106,22 @@ public final class CollectionMetadataGenerator {
* @param referencingEntityName Name of the entity that owns this collection.
* @param xmlMappingData In case this collection requires a middle table, additional mapping documents will
* 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)
* table and the value of the <code>@MapKey</code> annotation, if there was one.
*/
public CollectionMetadataGenerator(AuditMetadataGenerator mainGenerator,
Collection propertyValue, CompositeMapperBuilder currentMapper,
String referencingEntityName, EntityXmlMappingData xmlMappingData,
PersistentPropertyAuditingData persistentPropertyAuditingData) {
PropertyAuditingData propertyAuditingData) {
this.mainGenerator = mainGenerator;
this.propertyValue = propertyValue;
this.currentMapper = currentMapper;
this.referencingEntityName = referencingEntityName;
this.xmlMappingData = xmlMappingData;
this.persistentPropertyAuditingData = persistentPropertyAuditingData;
this.propertyAuditingData = propertyAuditingData;
this.propertyName = persistentPropertyAuditingData.getName();
this.propertyName = propertyAuditingData.getName();
referencingEntityConfiguration = mainGenerator.getEntitiesConfigurations().get(referencingEntityName);
if (referencingEntityConfiguration == null) {
@ -189,7 +190,7 @@ public final class CollectionMetadataGenerator {
// Creating common mapper data.
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(), referencedEntityName,
persistentPropertyAuditingData.getPropertyData(),
propertyAuditingData.getPropertyData(),
referencingIdData, queryGenerator);
// Checking the type of the collection and adding an appropriate mapper.
@ -235,9 +236,9 @@ public final class CollectionMetadataGenerator {
// Generating the name of the middle table
String auditMiddleTableName;
String auditMiddleEntityName;
if (!StringTools.isEmpty(persistentPropertyAuditingData.getJoinTable().name())) {
auditMiddleTableName = persistentPropertyAuditingData.getJoinTable().name();
auditMiddleEntityName = persistentPropertyAuditingData.getJoinTable().name();
if (!StringTools.isEmpty(propertyAuditingData.getJoinTable().name())) {
auditMiddleTableName = propertyAuditingData.getJoinTable().name();
auditMiddleEntityName = propertyAuditingData.getJoinTable().name();
} else {
String middleTableName = getMiddleTableName(propertyValue, referencingEntityName);
auditMiddleTableName = mainGenerator.getVerEntCfg().getAuditTableName(null, middleTableName);
@ -301,7 +302,7 @@ public final class CollectionMetadataGenerator {
// Generating the element mapping.
// ******
MiddleComponentData elementComponentData = addValueToMiddleTable(propertyValue.getElement(), middleEntityXml,
queryGeneratorBuilder, referencedPrefix, persistentPropertyAuditingData.getJoinTable().inverseJoinColumns());
queryGeneratorBuilder, referencedPrefix, propertyAuditingData.getJoinTable().inverseJoinColumns());
// ******
// Generating the index mapping, if an index exists.
@ -317,7 +318,7 @@ public final class CollectionMetadataGenerator {
// Creating common data
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(), auditMiddleEntityName,
persistentPropertyAuditingData.getPropertyData(),
propertyAuditingData.getPropertyData(),
referencingIdData, queryGenerator);
// Checking the type of the collection and adding an appropriate mapper.
@ -332,7 +333,7 @@ public final class CollectionMetadataGenerator {
private MiddleComponentData addIndex(Element middleEntityXml, QueryGeneratorBuilder queryGeneratorBuilder) {
if (propertyValue instanceof IndexedCollection) {
IndexedCollection indexedValue = (IndexedCollection) propertyValue;
String mapKey = persistentPropertyAuditingData.getMapKey();
String mapKey = propertyAuditingData.getMapKey();
if (mapKey == null) {
// This entity doesn't specify a javax.persistence.MapKey. Mapping it to the middle entity.
return addValueToMiddleTable(indexedValue.getIndex(), middleEntityXml,
@ -348,7 +349,7 @@ public final class CollectionMetadataGenerator {
} else {
// The key of the map is a property of the entity.
return new MiddleComponentData(new MiddleMapKeyPropertyComponentMapper(mapKey,
persistentPropertyAuditingData.getAccessType()), currentIndex);
propertyAuditingData.getAccessType()), currentIndex);
}
}
} else {
@ -401,7 +402,7 @@ public final class CollectionMetadataGenerator {
} else {
// Last but one parameter: collection components are always insertable
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
new PersistentPropertyAuditingData(prefix, "field", ModificationStore.FULL), value, null,
new PropertyAuditingData(prefix, "field", ModificationStore.FULL), value, null,
true, true);
if (mapped) {
@ -419,30 +420,30 @@ public final class CollectionMetadataGenerator {
MiddleComponentData indexComponentData) {
Type type = propertyValue.getType();
if (type instanceof SortedSetType) {
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<Set>(commonCollectionMapperData,
TreeSet.class, SortedSetProxy.class, elementComponentData));
} else if (type instanceof SetType) {
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<Set>(commonCollectionMapperData,
HashSet.class, SetProxy.class, elementComponentData));
} else if (type instanceof SortedMapType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new MapCollectionMapper<Map>(commonCollectionMapperData,
TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData));
} else if (type instanceof MapType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new MapCollectionMapper<Map>(commonCollectionMapperData,
HashMap.class, MapProxy.class, elementComponentData, indexComponentData));
} else if (type instanceof BagType) {
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<List>(commonCollectionMapperData,
ArrayList.class, ListProxy.class, elementComponentData));
} else if (type instanceof ListType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(persistentPropertyAuditingData.getPropertyData(),
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new ListCollectionMapper(commonCollectionMapperData,
elementComponentData, indexComponentData));
} else {
@ -462,10 +463,10 @@ public final class CollectionMetadataGenerator {
}
private Element createMiddleEntityXml(String auditMiddleTableName, String auditMiddleEntityName) {
String schema = StringTools.isEmpty(persistentPropertyAuditingData.getJoinTable().schema()) ?
propertyValue.getCollectionTable().getSchema() : persistentPropertyAuditingData.getJoinTable().schema();
String catalog = StringTools.isEmpty(persistentPropertyAuditingData.getJoinTable().catalog()) ?
propertyValue.getCollectionTable().getCatalog() : persistentPropertyAuditingData.getJoinTable().catalog();
String schema = StringTools.isEmpty(propertyAuditingData.getJoinTable().schema()) ?
propertyValue.getCollectionTable().getSchema() : propertyAuditingData.getJoinTable().schema();
String catalog = StringTools.isEmpty(propertyAuditingData.getJoinTable().catalog()) ?
propertyValue.getCollectionTable().getCatalog() : propertyAuditingData.getJoinTable().catalog();
Element middleEntityXml = MetadataTools.createEntity(xmlMappingData.newAdditionalMapping(),
new AuditTableData(auditMiddleEntityName, auditMiddleTableName, schema, catalog), null);

View File

@ -5,7 +5,8 @@ import org.hibernate.mapping.Value;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
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;
@ -21,25 +22,24 @@ public final class ComponentMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
public void addComponent(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData,
public void addComponent(Element parent, PropertyAuditingData propertyAuditingData,
Value value, CompositeMapperBuilder mapper, String entityName,
EntityXmlMappingData xmlMappingData, boolean firstPass) {
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
Iterator<Property> properties = (Iterator<Property>) prop_component.getPropertyIterator();
while (properties.hasNext()) {
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,
entityName, xmlMappingData, propertyAuditingData, property.isInsertable(), firstPass);
mainGenerator.addValue(parent, property.getValue(), componentMapper, entityName, xmlMappingData,
componentAuditingData.getPropertyAuditingData(property.getName()),
property.isInsertable(), firstPass);
}
}
}

View File

@ -28,6 +28,7 @@ import java.util.Iterator;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.entities.mapper.SimpleMapperBuilder;
@ -130,8 +131,8 @@ public final class IdMetadataGenerator {
ModificationStore.FULL);
}
private PersistentPropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
return new PersistentPropertyAuditingData(property.getName(), property.getPropertyAccessorName(),
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
return new PropertyAuditingData(property.getName(), property.getPropertyAccessorName(),
ModificationStore.FULL);
}
}

View File

@ -31,6 +31,7 @@ import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
import org.hibernate.envers.entities.mapper.id.IdMapper;
import org.hibernate.envers.entities.mapper.relation.OneToOneNotOwningMapper;
import org.hibernate.envers.entities.mapper.relation.ToOneIdMapper;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.MappingException;
import org.hibernate.mapping.OneToOne;
@ -49,7 +50,7 @@ public final class ToOneRelationMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
void addToOne(Element parent, PersistentPropertyAuditingData persistentPropertyAuditingData, Value value,
void addToOne(Element parent, PropertyAuditingData propertyAuditingData, Value value,
CompositeMapperBuilder mapper, String entityName, boolean insertable) {
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
@ -60,30 +61,30 @@ public final class ToOneRelationMetadataGenerator {
IdMappingData idMapping = configuration.getIdMappingData();
String lastPropertyPrefix = persistentPropertyAuditingData.getName() + "_";
String lastPropertyPrefix = propertyAuditingData.getName() + "_";
// Generating the id mapper for the relation
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
// Storing information about this relation
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
Element properties = (Element) idMapping.getXmlRelationMapping().clone();
properties.addAttribute("name", persistentPropertyAuditingData.getName());
properties.addAttribute("name", propertyAuditingData.getName());
MetadataTools.prefixNamesInPropertyElement(properties, lastPropertyPrefix,
MetadataTools.getColumnNameIterator(value.getColumnIterator()), false, insertable);
parent.add(properties);
// Adding mapper for the id
PropertyData propertyData = persistentPropertyAuditingData.getPropertyData();
PropertyData propertyData = propertyAuditingData.getPropertyData();
mapper.addComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName));
}
@SuppressWarnings({"unchecked"})
void addOneToOneNotOwning(PersistentPropertyAuditingData persistentPropertyAuditingData, Value value,
void addOneToOneNotOwning(PropertyAuditingData propertyAuditingData, Value value,
CompositeMapperBuilder mapper, String entityName) {
OneToOne propertyValue = (OneToOne) value;
@ -108,11 +109,11 @@ public final class ToOneRelationMetadataGenerator {
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneNotOwningRelation(
persistentPropertyAuditingData.getName(), owningReferencePropertyName,
propertyAuditingData.getName(), owningReferencePropertyName,
referencedEntityName, ownedIdMapper);
// Adding mapper for the id
PropertyData propertyData = persistentPropertyAuditingData.getPropertyData();
PropertyData propertyData = propertyAuditingData.getPropertyData();
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(owningReferencePropertyName,
referencedEntityName, propertyData));
}

View File

@ -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; }
}
}

View File

@ -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);
}

View File

@ -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; }
}
}

View File

@ -21,37 +21,39 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration.metadata;
package org.hibernate.envers.configuration.metadata.reader;
import java.util.Map;
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 Sebastian Komander
*/
public class PersistentClassAuditingData {
public PersistentClassAuditingData() {
properties = Tools.newHashMap();
secondaryTableDictionary = Tools.newHashMap();
}
public class ClassAuditingData implements AuditedPropertiesHolder {
private final Map<String, PropertyAuditingData> properties;
private final Map<String, String> secondaryTableDictionary;
private Map<String, PersistentPropertyAuditingData> properties;
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,
* but it's still audited).
*/
private boolean defaultAudited;
public Map<String, PersistentPropertyAuditingData> getProperties() {
return properties;
public ClassAuditingData() {
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);
}
@ -72,10 +74,6 @@ public class PersistentClassAuditingData {
}
public boolean isAudited() {
if (defaultAudited || properties.size() > 0) {
return true;
} else {
return false;
}
return defaultAudited || properties.size() > 0;
}
}

View File

@ -22,25 +22,28 @@
* 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.entities.PropertyData;
import static org.hibernate.envers.tools.Tools.*;
import java.util.Map;
/**
* Audit mapping meta-data for component.
* @author Adam Warski (adam at warski dot org)
*/
public class PersistentComponentPropertyAuditingData extends PersistentPropertyAuditingData {
private final String beanName;
public class ComponentAuditingData extends PropertyAuditingData implements AuditedPropertiesHolder {
private final Map<String, PropertyAuditingData> properties;
public PersistentComponentPropertyAuditingData(String name, String beanName, String accessType,
ModificationStore store) {
super(name, accessType, store);
this.beanName = beanName;
}
public PropertyData getPropertyData() {
return new PropertyData(getName(), beanName, getAccessType(), getStore());
public ComponentAuditingData() {
this.properties = newHashMap();
}
public void addPropertyAuditingData(String propertyName, PropertyAuditingData auditingData) {
properties.put(propertyName, auditingData);
}
public PropertyAuditingData getPropertyAuditingData(String propertyName) {
return properties.get(propertyName);
}
}

View File

@ -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();
}

View File

@ -22,7 +22,7 @@
* 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.AuditJoinTable;
@ -31,23 +31,25 @@ import org.hibernate.envers.entities.PropertyData;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class PersistentPropertyAuditingData {
public class PropertyAuditingData {
private String name;
private String beanName;
private ModificationStore store;
private String mapKey;
private AuditJoinTable joinTable;
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.beanName = name;
this.accessType = accessType;
this.store = store;
}
public String getName() {
public String getName() {
return name;
}
@ -55,7 +57,15 @@ public class PersistentPropertyAuditingData {
this.name = name;
}
public ModificationStore getStore() {
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public ModificationStore getStore() {
return store;
}
@ -88,6 +98,6 @@ public class PersistentPropertyAuditingData {
}
public PropertyData getPropertyData() {
return new PropertyData(name, name, accessType, store);
return new PropertyData(name, beanName, accessType, store);
}
}

View File

@ -32,6 +32,7 @@ import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.envers.tools.Tools;
import org.hibernate.envers.tools.MappingTools;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Getter;
@ -120,9 +121,30 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
PersistentCollection newColl,
Serializable oldColl,
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));
if (mapper != null) {
return mapper.mapCollectionChanges(referencingPropertyName, newColl, oldColl, id);
return mapper.mapCollectionChanges(delegatePropertyName, newColl, oldColl, id);
} else {
return null;
}

View File

@ -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 + "_";
}
}

View File

@ -23,9 +23,12 @@
*/
package org.hibernate.envers.test.entities.components;
import javax.persistence.Embeddable;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Embeddable
public class Component1 {
private String str1;

View File

@ -23,9 +23,12 @@
*/
package org.hibernate.envers.test.entities.components;
import javax.persistence.Embeddable;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Embeddable
public class Component2 {
private String str5;

View File

@ -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 + ")";
}
}

View File

@ -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 + ")";
}
}

View File

@ -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 + ")";
}
}

View File

@ -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 + ")";
}
}

View File

@ -42,7 +42,7 @@ public class MixedAccessType extends AbstractEntityTest {
cfg.addAnnotatedClass(MixedAccessTypeEntity.class);
}
@BeforeClass(dependsOnMethods = "init")
@Test
public void initData() {
EntityManager em = getEntityManager();
em.getTransaction().begin();
@ -57,12 +57,12 @@ public class MixedAccessType extends AbstractEntityTest {
em.getTransaction().commit();
}
@Test
@Test(dependsOnMethods = "initData")
public void testRevisionsCounts() {
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(MixedAccessTypeEntity.class, id1));
}
@Test
@Test(dependsOnMethods = "initData")
public void testHistoryOfId1() {
MixedAccessTypeEntity ver1 = new MixedAccessTypeEntity(id1, "data");
MixedAccessTypeEntity ver2 = new MixedAccessTypeEntity(id1, "data2");

View File

@ -43,7 +43,7 @@ public class Simple extends AbstractEntityTest {
cfg.addAnnotatedClass(IntTestEntity.class);
}
@BeforeClass(dependsOnMethods = "init")
@Test
public void initData() {
EntityManager em = getEntityManager();
em.getTransaction().begin();
@ -58,12 +58,12 @@ public class Simple extends AbstractEntityTest {
em.getTransaction().commit();
}
@Test
@Test(dependsOnMethods = "initData")
public void testRevisionsCounts() {
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(IntTestEntity.class, id1));
}
@Test
@Test(dependsOnMethods = "initData")
public void testHistoryOfId1() {
IntTestEntity ver1 = new IntTestEntity(10, id1);
IntTestEntity ver2 = new IntTestEntity(20, id1);

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -9,6 +9,7 @@
<package name="org.hibernate.envers.test.integration.collection" />
<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.relations" />
<package name="org.hibernate.envers.test.integration.customtype" />
<package name="org.hibernate.envers.test.integration.data" />
<package name="org.hibernate.envers.test.integration.flush" />