HHH-7490 - Integrate Envers with Metamodel

This commit is contained in:
Gail Badner 2014-03-19 19:24:42 -07:00
parent 6f342358db
commit 24ff8d6eae
158 changed files with 2863 additions and 1893 deletions

View File

@ -166,7 +166,7 @@ class TypeSafeActivator {
for ( EntityBinding entityBinding : activationContext.getMetadata().getEntityBindings() ) {
final String className = entityBinding.getEntity().getDescriptor().getName().toString();
if ( className == null || className.length() == 0 ) {
if ( entityBinding.getEntity().getDescriptor() == null ) {
continue;
}

View File

@ -239,7 +239,7 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA
}
public void addProperty(Property p) {
properties.add(p);
properties.add( p );
declaredProperties.add(p);
p.setPersistentClass(this);
}
@ -879,7 +879,7 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA
}
public void addMappedsuperclassProperty(Property p) {
properties.add(p);
properties.add( p );
p.setPersistentClass(this);
}

View File

@ -25,6 +25,7 @@ package org.hibernate.metamodel;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import javax.persistence.NamedStoredProcedureQuery;
@ -61,6 +62,12 @@ public interface Metadata {
*/
SessionFactory buildSessionFactory();
/**
* Gets the {@link UUID} for this metamodel.
*
* @return the UUID.
*/
UUID getUUID();
EntityBinding getEntityBinding(String entityName);

View File

@ -29,6 +29,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.hibernate.AssertionFailure;
import org.hibernate.DuplicateMappingException;
@ -36,6 +37,7 @@ import org.hibernate.EntityMode;
import org.hibernate.MappingException;
import org.hibernate.SessionFactory;
import org.hibernate.annotations.common.util.StringHelper;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.CacheRegionDefinition;
import org.hibernate.cache.spi.access.AccessType;
@ -117,6 +119,8 @@ import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.jboss.logging.Logger;
import static org.hibernate.metamodel.spi.AdditionalJaxbRootProducer.AdditionalJaxbRootProducerContext;
/**
* Represents the process of building a Metadata object. The main entry point is the
* static {@link #build}
@ -126,7 +130,7 @@ import org.jboss.logging.Logger;
public class MetadataBuildingProcess {
private static final Logger log = Logger.getLogger( MetadataBuildingProcess.class );
public static MetadataImpl build(MetadataSources sources, MetadataBuildingOptions options) {
public static MetadataImpl build(MetadataSources sources, final MetadataBuildingOptions options) {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// preliminary phases
final IndexView jandexView = handleJandex( options, sources );
@ -195,8 +199,19 @@ public class MetadataBuildingProcess {
}
final List<BindResult> bindResults = new ArrayList<BindResult>();
final AdditionalJaxbRootProducerContext jaxbRootProducerContext = new AdditionalJaxbRootProducerContext() {
@Override
public IndexView getJandexIndex() {
return jandexView;
}
@Override
public StandardServiceRegistry getServiceRegistry() {
return options.getServiceRegistry();
}
};
for ( AdditionalJaxbRootProducer producer : classLoaderService.loadJavaServices( AdditionalJaxbRootProducer.class ) ) {
bindResults.addAll( producer.produceRoots( metadataCollector, jandexView ) );
bindResults.addAll( producer.produceRoots( metadataCollector, jaxbRootProducerContext ) );
}
final HbmMetadataSourceProcessorImpl processor = new HbmMetadataSourceProcessorImpl( rootBindingContext, bindResults );
final Binder binder = new Binder( rootBindingContext );
@ -671,6 +686,7 @@ public class MetadataBuildingProcess {
private final MetadataBuildingOptions options;
private final TypeResolver typeResolver;
private final UUID uuid;
private final Database database;
private final ObjectNameNormalizer nameNormalizer;
private final MutableIdentifierGeneratorFactory identifierGeneratorFactory;
@ -702,6 +718,7 @@ public class MetadataBuildingProcess {
new HashMap<Identifier, SecondaryTable>();
public InFlightMetadataCollectorImpl(MetadataBuildingOptions options, TypeResolver typeResolver) {
this.uuid = UUID.randomUUID();
this.options = options;
this.typeResolver = typeResolver;
@ -766,6 +783,10 @@ public class MetadataBuildingProcess {
);
}
@Override
public UUID getUUID() {
return null;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -1157,6 +1178,7 @@ public class MetadataBuildingProcess {
options.getServiceRegistry(),
database,
typeResolver,
uuid,
identifierGeneratorFactory,
typeDefinitionMap,
filterDefinitionMap,

View File

@ -27,6 +27,7 @@ import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
@ -67,6 +68,8 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final TypeResolver typeResolver;
private final IdentifierGeneratorFactory identifierGeneratorFactory;
private final UUID uuid;
private final Map<String, TypeDefinition> typeDefinitionMap = new HashMap<String, TypeDefinition>();
private final Map<String, FilterDefinition> filterDefinitionMap = new HashMap<String, FilterDefinition>();
private final Map<String, EntityBinding> entityBindingMap = new HashMap<String, EntityBinding>();
@ -85,6 +88,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
StandardServiceRegistry serviceRegistry,
Database database,
TypeResolver typeResolver,
UUID uuid,
IdentifierGeneratorFactory identifierGeneratorFactory,
Map<String, TypeDefinition> typeDefinitionMap,
Map<String, FilterDefinition> filterDefinitionMap,
@ -102,6 +106,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
this.serviceRegistry = serviceRegistry;
this.database = database;
this.typeResolver = typeResolver;
this.uuid = uuid;
this.identifierGeneratorFactory = identifierGeneratorFactory;
if ( typeDefinitionMap != null ) {
@ -279,6 +284,11 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
return getSessionFactoryBuilder().build();
}
@Override
public UUID getUUID() {
return null;
}
@Override
public IdentifierGeneratorFactory getIdentifierGeneratorFactory() {
return identifierGeneratorFactory;

View File

@ -552,7 +552,9 @@ public class Binder {
return null;
}
final DotName descriptorTypeName = javaTypeDescriptorRepository.buildName( source.getTypeName() );
final DotName descriptorTypeName = javaTypeDescriptorRepository.buildName(
typeHelper().determineJavaTypeName( source )
);
final JavaTypeDescriptor javaTypeDescriptor = javaTypeDescriptorRepository.getType( descriptorTypeName );
if ( EntitySource.class.isInstance( source ) ) {
@ -1792,7 +1794,7 @@ public class Binder {
if ( attribute != null ) {
// validate its ok to use...
if ( !Aggregate.class.isInstance( attribute.getSingularAttributeType() ) ) {
localBindingContext().makeMappingException(
throw localBindingContext().makeMappingException(
"Found existing attribute on container for '" + attributeSource.getName()
+ "', but was expecting an Aggregate"
);
@ -1805,9 +1807,12 @@ public class Binder {
compositeTypeDescriptor = attributeSource.getTypeDescriptor();
}
else {
final EntityMode entityMode =
attributeBindingContainer.seekEntityBinding().getHierarchyDetails().getEntityMode();
compositeTypeDescriptor = typeHelper().determineJavaType(
attributeSource,
attributeBindingContainer.getAttributeContainer()
attributeBindingContainer.getAttributeContainer(),
entityMode
);
}
composite = new Aggregate( compositeTypeDescriptor, null );

View File

@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Properties;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.internal.util.beans.BeanInfoHelper;
@ -45,6 +46,7 @@ import org.hibernate.metamodel.source.spi.AttributeSource;
import org.hibernate.metamodel.source.spi.BasicPluralAttributeElementSource;
import org.hibernate.metamodel.source.spi.ComponentAttributeSource;
import org.hibernate.metamodel.source.spi.HibernateTypeSource;
import org.hibernate.metamodel.source.spi.IdentifiableTypeSource;
import org.hibernate.metamodel.source.spi.ManyToManyPluralAttributeElementSource;
import org.hibernate.metamodel.source.spi.PluralAttributeSource;
import org.hibernate.metamodel.source.spi.SingularAttributeSource;
@ -808,6 +810,35 @@ class HibernateTypeHelper {
return null;
}
public String determineJavaTypeName(final IdentifiableTypeSource identifiableTypeSource) {
if ( identifiableTypeSource.getTypeName() == null ) {
if ( identifiableTypeSource.getHierarchy().getEntityMode() == EntityMode.MAP ) {
return Map.class.getName();
}
else {
return null;
}
}
else {
return identifiableTypeSource.getTypeName();
}
}
public JavaTypeDescriptor determineJavaType(
final ComponentAttributeSource attributeSource,
final AttributeContainer attributeContainer,
final EntityMode entityMode) {
if ( attributeSource.getTypeDescriptor() != null ) {
return attributeSource.getTypeDescriptor();
}
else if ( entityMode == EntityMode.MAP ) {
return bindingContext().typeDescriptor( Map.class.getName() );
}
else {
return determineJavaType( attributeSource, attributeContainer );
}
}
public JavaTypeDescriptor determineJavaType(
final AttributeSource attributeSource,

View File

@ -689,6 +689,9 @@ public class JandexHelper {
}
returnValue = arr;
}
else if ( type.isEnum() && String.class.isInstance( returnValue ) ) {
returnValue = Enum.valueOf( (Class<Enum>) type, (String) returnValue );
}
return type.cast( nullIfUndefined( returnValue, type ) );
}

View File

@ -202,4 +202,8 @@ class KeyManyToOneSourceImpl
public boolean isCascadeDeleteEnabled() {
return "cascade".equals( keyManyToOneElement.getOnDelete().value() );
}
protected String getClassName() {
return keyManyToOneElement.getClazz();
}
}

View File

@ -25,6 +25,8 @@ package org.hibernate.metamodel.spi;
import java.util.List;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.xml.spi.BindResult;
import org.jboss.jandex.IndexView;
@ -41,9 +43,30 @@ public interface AdditionalJaxbRootProducer {
* Produce and return the list of additional mappings to be processed.
*
* @param metadataCollector The metadata (for access to binding information).
* @param jandexIndex The Jandex annotation index
* @param context The context.
*
* @return List of additional mappings
*
* @see AdditionalJaxbRootProducerContext
*/
public List<BindResult> produceRoots(InFlightMetadataCollector metadataCollector, IndexView jandexIndex);
public List<BindResult> produceRoots(
InFlightMetadataCollector metadataCollector,
AdditionalJaxbRootProducerContext context);
public interface AdditionalJaxbRootProducerContext {
/**
* Gets the Jandex annotation index.
*
* @return the Jandex annotation index
*/
public IndexView getJandexIndex();
/**
* Gets the service registry.
*
* @return The service registry.
*/
public StandardServiceRegistry getServiceRegistry();
}
}

View File

@ -26,6 +26,7 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.FetchMode;
import org.hibernate.metamodel.spi.relational.Value;
/**
* Basic contract describing the commonality between the various types of collection element mappings.
@ -52,6 +53,11 @@ public abstract class AbstractPluralAttributeElementBinding implements PluralAtt
protected abstract RelationalValueBindingContainer getRelationalValueContainer();
@Override
public List<Value> getValues() {
return getRelationalValueContainer().values();
}
@Override
public List<RelationalValueBinding> getRelationalValueBindings() {
return getRelationalValueContainer().relationalValueBindings();

View File

@ -26,6 +26,7 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.metamodel.spi.relational.Value;
/**
*
@ -44,6 +45,11 @@ public class BasicPluralAttributeIndexBinding extends AbstractPluralAttributeInd
return relationalValueBindingContainer.relationalValueBindings();
}
@Override
public List<Value> getValues() {
return relationalValueBindingContainer.values();
}
public void setRelationalValueBindings(List<RelationalValueBinding> relationalValueBindings) {
if ( relationalValueBindings == null || relationalValueBindings.isEmpty() ) {
throw new AssertionFailure( "relationalValueBindings argument must be non-null and non-empty." );

View File

@ -30,6 +30,7 @@ import java.util.Map;
import org.hibernate.metamodel.source.spi.MetaAttributeContext;
import org.hibernate.metamodel.spi.domain.Aggregate;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
import org.hibernate.metamodel.spi.relational.Value;
/**
* Describes plural attributes of {@link org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding.Nature#AGGREGATE} elements
@ -90,4 +91,9 @@ public class CompositePluralAttributeIndexBinding extends AbstractPluralAttribut
public List<RelationalValueBinding> getRelationalValueBindings() {
return compositeAttributeBindingContainer.getRelationalValueBindingContainer().relationalValueBindings();
}
@Override
public List<Value> getValues() {
return compositeAttributeBindingContainer.getRelationalValueBindingContainer().values();
}
}

View File

@ -630,28 +630,33 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
public AttributeBinding[] getNonIdAttributeBindingClosure(){
// TODO: update size to account for joins
if ( isRoot() ) {
return internalGetNonIdAttributeBindingClosure();
return internalGetNonIdAttributeBindings();
}
else {
return ArrayHelper.join(
superEntityBinding.getNonIdAttributeBindingClosure(),
internalGetNonIdAttributeBindingClosure()
internalGetNonIdAttributeBindings()
);
}
}
private AttributeBinding[] internalGetNonIdAttributeBindingClosure() {
List<AttributeBinding> list = new ArrayList<AttributeBinding>();
public List<AttributeBinding> getNonIdAttributeBindings() {
final List<AttributeBinding> list = new ArrayList<AttributeBinding>();
for ( final AttributeBinding ab : attributeBindings() ) {
boolean isId = getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( ab );
if ( !isId ) {
list.add( ab );
}
}
return list.toArray( new AttributeBinding[list.size()] );
return list;
}
private AttributeBinding[] internalGetNonIdAttributeBindings() {
final List<AttributeBinding> list = getNonIdAttributeBindings();
return list.toArray( new AttributeBinding[list.size()] );
}
public List<EntityBinding> getDirectSubEntityBindings() {
return subEntityBindings;
}
@ -772,7 +777,7 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
results = ArrayHelper.join(
results,
subEntityBinding.internalGetNonIdAttributeBindingClosure()
subEntityBinding.internalGetNonIdAttributeBindings()
);
// TODO: if EntityBinding.attributeBindings() excludes joined attributes, then they need to be added here
}

View File

@ -26,6 +26,7 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.FetchMode;
import org.hibernate.metamodel.spi.relational.Value;
/**
@ -41,6 +42,8 @@ public interface PluralAttributeElementBinding {
*/
PluralAttributeBinding getPluralAttributeBinding();
List<Value> getValues();
/**
* Retrieve the relational aspect of the element binding. Essentially describes the column(s) to which the
* binding maps the elements

View File

@ -26,6 +26,7 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.metamodel.spi.domain.Type;
import org.hibernate.metamodel.spi.relational.Value;
/**
* @author Steve Ebersole
@ -43,6 +44,8 @@ public interface PluralAttributeIndexBinding {
*/
public List<RelationalValueBinding> getRelationalValueBindings();
List<Value> getValues();
HibernateTypeDescriptor getHibernateTypeDescriptor();
Type getPluralAttributeIndexType();

View File

@ -225,6 +225,15 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
/**
* Gets the metadata.
* @return the metadata.
* @deprecated This should only be needed for testing and should ultimately be removed.
*/
public MetadataImplementor getMetadata() {
return metadata;
}
private SettingsImpl configure(StandardServiceRegistryBuilder ssrBuilder) {
final SettingsImpl settings = new SettingsImpl();

View File

@ -25,11 +25,11 @@ package org.hibernate.envers;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.MappedSuperclass;
import org.hibernate.annotations.Fetch;
@ -45,7 +45,7 @@ import org.hibernate.annotations.FetchMode;
@MappedSuperclass
public class DefaultTrackingModifiedEntitiesRevisionEntity extends DefaultRevisionEntity {
@ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@CollectionTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME")
@Fetch(FetchMode.JOIN)
@ModifiedEntityNames

View File

@ -0,0 +1,127 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. 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 Inc.
*
* 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.internal;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
import org.jboss.jandex.AnnotationInstance;
import org.hibernate.HibernateException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class AnnotationProxyBuilder {
private final Map<AnnotationInstance, Object> proxyObjectMap = new HashMap<AnnotationInstance, Object>();
private final Map<Class, ProxyFactory> proxyFactoryMap = new HashMap<Class, ProxyFactory>();
public <T> T getAnnotationProxy(
final AnnotationInstance annotationInstance,
final Class<T> annotationClass,
final ClassLoaderService classLoaderService) {
T annotationProxy = (T) proxyObjectMap.get( annotationInstance );
if ( annotationProxy == null ) {
annotationProxy = buildAnnotationProxy( annotationInstance, annotationClass, classLoaderService );
proxyObjectMap.put( annotationInstance, annotationProxy );
}
return annotationProxy;
}
private <T> T buildAnnotationProxy(
final AnnotationInstance annotationInstance,
final Class<T> annotationClass,
final ClassLoaderService classLoaderService) {
try {
final Class annotation = annotationClass.getClassLoader().loadClass( annotationClass.getName() );
final Class proxyClass = getProxyFactory( annotation ).createClass();
final ProxyObject proxyObject = (ProxyObject) proxyClass.newInstance();
proxyObject.setHandler( new MethodHandler() {
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
String executedMethodName = thisMethod.getName();
if ( "toString".equals( executedMethodName ) ) {
return proxyClass.getName() + "@" + System.identityHashCode( self );
}
final Class<?> returnType = thisMethod.getReturnType();
if ( returnType.isArray() && returnType.getComponentType().isAnnotation() ) {
final AnnotationInstance[] returnValues = JandexHelper.getValue(
annotationInstance,
executedMethodName,
AnnotationInstance[].class,
classLoaderService
);
return buildAnnotationProxyArray(
returnValues,
returnType.getComponentType(),
classLoaderService
);
}
return JandexHelper.getValue(
annotationInstance,
executedMethodName,
thisMethod.getReturnType(),
classLoaderService
);
}
} );
return (T) proxyObject;
}
catch ( Exception e ) {
throw new HibernateException( e );
}
}
@SuppressWarnings( {"unchecked"})
private <T> T[] buildAnnotationProxyArray(
final AnnotationInstance[] annotationInstances,
final Class<T> annotationClass,
final ClassLoaderService classLoaderService) {
final T[] annotationProxyArray = (T[]) Array.newInstance( annotationClass, annotationInstances.length );
for ( int i = 0 ; i < annotationInstances.length ; i++ ) {
annotationProxyArray[i] = buildAnnotationProxy( annotationInstances[i], annotationClass, classLoaderService );
}
return annotationProxyArray;
}
private ProxyFactory getProxyFactory(final Class annotation) {
ProxyFactory proxyFactory = proxyFactoryMap.get( annotation );
if ( proxyFactory == null ) {
proxyFactory = new ProxyFactory();
proxyFactoryMap.put( annotation, proxyFactory );
}
proxyFactory.setInterfaces( new Class[] { annotation } );
return proxyFactory;
}
}

View File

@ -25,11 +25,12 @@ package org.hibernate.envers.configuration.internal;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.envers.configuration.EnversSettings;
import org.hibernate.envers.strategy.DefaultAuditStrategy;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.ServiceRegistry;
/**
* Configuration of versions entities - names of fields, entities and tables created to store versioning information.
@ -62,36 +63,48 @@ public class AuditEntitiesConfiguration {
private final String embeddableSetOrdinalPropertyName;
public AuditEntitiesConfiguration(Properties properties, String revisionInfoEntityName) {
public AuditEntitiesConfiguration(ServiceRegistry serviceRegistry, String revisionInfoEntityName) {
this.revisionInfoEntityName = revisionInfoEntityName;
auditTablePrefix = ConfigurationHelper.getString( EnversSettings.AUDIT_TABLE_PREFIX, properties, "" );
auditTableSuffix = ConfigurationHelper.getString( EnversSettings.AUDIT_TABLE_SUFFIX, properties, "_AUD" );
final ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class );
auditStrategyName = ConfigurationHelper.getString(
EnversSettings.AUDIT_STRATEGY, properties, DefaultAuditStrategy.class.getName()
auditTablePrefix = configurationService.getSetting(
EnversSettings.AUDIT_TABLE_PREFIX, StandardConverters.STRING, ""
);
auditTableSuffix = configurationService.getSetting(
EnversSettings.AUDIT_TABLE_SUFFIX, StandardConverters.STRING, "_AUD"
);
auditStrategyName = configurationService.getSetting(
EnversSettings.AUDIT_STRATEGY, StandardConverters.STRING, DefaultAuditStrategy.class.getName()
);
originalIdPropName = "originalId";
revisionFieldName = ConfigurationHelper.getString( EnversSettings.REVISION_FIELD_NAME, properties, "REV" );
revisionFieldName = configurationService.getSetting(
EnversSettings.REVISION_FIELD_NAME, StandardConverters.STRING, "REV"
);
revisionTypePropName = ConfigurationHelper.getString(
EnversSettings.REVISION_TYPE_FIELD_NAME, properties, "REVTYPE"
revisionTypePropName = configurationService.getSetting(
EnversSettings.REVISION_TYPE_FIELD_NAME, StandardConverters.STRING, "REVTYPE"
);
revisionTypePropType = "byte";
revisionEndFieldName = ConfigurationHelper.getString(
EnversSettings.AUDIT_STRATEGY_VALIDITY_END_REV_FIELD_NAME, properties, "REVEND"
revisionEndFieldName = configurationService.getSetting(
EnversSettings.AUDIT_STRATEGY_VALIDITY_END_REV_FIELD_NAME, StandardConverters.STRING, "REVEND"
);
revisionEndTimestampEnabled = ConfigurationHelper.getBoolean(
EnversSettings.AUDIT_STRATEGY_VALIDITY_STORE_REVEND_TIMESTAMP, properties, false
revisionEndTimestampEnabled = configurationService.getSetting(
EnversSettings.AUDIT_STRATEGY_VALIDITY_STORE_REVEND_TIMESTAMP,
StandardConverters.BOOLEAN,
false
);
if ( revisionEndTimestampEnabled ) {
revisionEndTimestampFieldName = ConfigurationHelper.getString(
EnversSettings.AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME, properties, "REVEND_TSTMP"
revisionEndTimestampFieldName = configurationService.getSetting(
EnversSettings.AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME,
StandardConverters.STRING,
"REVEND_TSTMP"
);
}
else {
@ -103,8 +116,8 @@ public class AuditEntitiesConfiguration {
revisionNumberPath = originalIdPropName + "." + revisionFieldName + ".id";
revisionPropBasePath = originalIdPropName + "." + revisionFieldName + ".";
embeddableSetOrdinalPropertyName = ConfigurationHelper.getString(
EnversSettings.EMBEDDABLE_SET_ORDINAL_FIELD_NAME, properties, "SETORDINAL"
embeddableSetOrdinalPropertyName = configurationService.getSetting(
EnversSettings.EMBEDDABLE_SET_ORDINAL_FIELD_NAME, StandardConverters.STRING, "SETORDINAL"
);
}

View File

@ -33,12 +33,12 @@ import org.hibernate.envers.configuration.internal.metadata.reader.ClassAuditing
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.internal.EnversMessageLogger;
import org.hibernate.envers.internal.tools.MappingTools;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.jboss.logging.Logger;
/**
* A helper class holding auditing meta-data for all persistent classes.
* A helper class holding auditing meta-data for all entity bindings.
*
* @author Adam Warski (adam at warski dot org)
*/
@ -49,24 +49,25 @@ public class ClassesAuditingData {
);
private final Map<String, ClassAuditingData> entityNameToAuditingData = new HashMap<String, ClassAuditingData>();
private final Map<PersistentClass, ClassAuditingData> persistentClassToAuditingData = new LinkedHashMap<PersistentClass, ClassAuditingData>();
private final Map<EntityBinding, ClassAuditingData> entityBindingToAuditingData =
new LinkedHashMap<EntityBinding, ClassAuditingData>();
/**
* Stores information about auditing meta-data for the given class.
*
* @param pc Persistent class.
* @param entityBinding The entity binding.
* @param cad Auditing meta-data for the given class.
*/
public void addClassAuditingData(PersistentClass pc, ClassAuditingData cad) {
entityNameToAuditingData.put( pc.getEntityName(), cad );
persistentClassToAuditingData.put( pc, cad );
public void addClassAuditingData(EntityBinding entityBinding, ClassAuditingData cad) {
entityNameToAuditingData.put( entityBinding.getEntityName(), cad );
entityBindingToAuditingData.put( entityBinding, cad );
}
/**
* @return A collection of all auditing meta-data for persistent classes.
*/
public Collection<Map.Entry<PersistentClass, ClassAuditingData>> getAllClassAuditedData() {
return persistentClassToAuditingData.entrySet();
public Collection<Map.Entry<EntityBinding, ClassAuditingData>> getAllEntityBindingAuditedData() {
return entityBindingToAuditingData.entrySet();
}
/**
@ -85,27 +86,27 @@ public class ClassesAuditingData {
* </ul>
*/
public void updateCalculatedFields() {
for ( Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet() ) {
final PersistentClass pc = classAuditingDataEntry.getKey();
for ( Map.Entry<EntityBinding, ClassAuditingData> classAuditingDataEntry : entityBindingToAuditingData.entrySet() ) {
final EntityBinding entityBinding = classAuditingDataEntry.getKey();
final ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
for ( String propertyName : classAuditingData.getPropertyNames() ) {
final PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData( propertyName );
// If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable.
if ( propertyAuditingData.getAuditMappedBy() != null ) {
final String referencedEntityName = MappingTools.getReferencedEntityName(
pc.getProperty( propertyName ).getValue()
entityBinding.locateAttributeBinding( propertyName )
);
final ClassAuditingData referencedClassAuditingData = entityNameToAuditingData.get( referencedEntityName );
forcePropertyInsertable(
referencedClassAuditingData, propertyAuditingData.getAuditMappedBy(),
pc.getEntityName(), referencedEntityName
entityBinding.getEntityName(), referencedEntityName
);
forcePropertyInsertable(
referencedClassAuditingData, propertyAuditingData.getPositionMappedBy(),
pc.getEntityName(), referencedEntityName
entityBinding.getEntityName(), referencedEntityName
);
}
}

View File

@ -28,23 +28,22 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.Configuration;
import org.hibernate.envers.configuration.internal.metadata.AuditEntityNameRegister;
import org.hibernate.envers.configuration.internal.metadata.AuditMetadataGenerator;
import org.hibernate.envers.configuration.internal.metadata.EntityXmlMappingData;
import org.hibernate.envers.configuration.internal.metadata.reader.AnnotationsMetadataReader;
import org.hibernate.envers.configuration.internal.metadata.reader.ClassAuditingData;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.envers.internal.EnversMessageLogger;
import org.hibernate.envers.internal.entities.EntitiesConfigurations;
import org.hibernate.envers.internal.tools.StringTools;
import org.hibernate.envers.internal.tools.graph.GraphTopologicalSort;
import org.hibernate.envers.strategy.AuditStrategy;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.dom4j.Document;
import org.dom4j.DocumentException;
@ -52,80 +51,84 @@ import org.dom4j.Element;
import org.dom4j.io.DOMWriter;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.jboss.logging.Logger;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class EntitiesConfigurator {
private static final EnversMessageLogger LOG = Logger.getMessageLogger(
EnversMessageLogger.class,
EntitiesConfigurator.class.getName()
);
public EntitiesConfigurations configure(
Configuration cfg, ReflectionManager reflectionManager,
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy, ClassLoaderService classLoaderService,
Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) {
AuditConfiguration.AuditConfigurationContext context,
AuditStrategy auditStrategy,
Document revisionInfoXmlMapping,
Element revisionInfoRelationMapping) {
// Creating a name register to capture all audit entity names created.
final AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister();
final DOMWriter writer = new DOMWriter();
// Sorting the persistent class topologically - superclass always before subclass
final Iterator<PersistentClass> classes = GraphTopologicalSort.sort( new PersistentClassGraphDefiner( cfg ) )
.iterator();
// Sorting the entity bindings topologically - superclass always before subclass
final List<EntityBinding> entityBindings =
GraphTopologicalSort.sort( new EntityBindingGraphDefiner( context.getMetadata() ) );
final ClassesAuditingData classesAuditingData = new ClassesAuditingData();
final Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
final Map<EntityBinding, EntityXmlMappingData> xmlMappings = new HashMap<EntityBinding, EntityXmlMappingData>();
// Reading metadata from annotations
while ( classes.hasNext() ) {
final PersistentClass pc = classes.next();
final AnnotationsMetadataReader annotationsMetadataReader = new AnnotationsMetadataReader( context );
for ( EntityBinding entityBinding : entityBindings ) {
// Collecting information from annotations on the persistent class pc
final AnnotationsMetadataReader annotationsMetadataReader =
new AnnotationsMetadataReader( globalCfg, reflectionManager, pc );
final ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
final ClassAuditingData auditData = annotationsMetadataReader.getAuditData( entityBinding );
classesAuditingData.addClassAuditingData( pc, auditData );
classesAuditingData.addClassAuditingData( entityBinding, auditData );
}
// Now that all information is read we can update the calculated fields.
classesAuditingData.updateCalculatedFields();
final AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(
cfg, globalCfg, verEntCfg, auditStrategy,
classLoaderService, revisionInfoRelationMapping, auditEntityNameRegister
context, auditStrategy, revisionInfoRelationMapping, auditEntityNameRegister
);
// First pass
for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
final PersistentClass pc = pcDatasEntry.getKey();
for ( Map.Entry<EntityBinding, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllEntityBindingAuditedData() ) {
final EntityBinding entityBinding = pcDatasEntry.getKey();
final ClassAuditingData auditData = pcDatasEntry.getValue();
final EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
if ( auditData.isAudited() ) {
if ( !StringTools.isEmpty( auditData.getAuditTable().value() ) ) {
verEntCfg.addCustomAuditTableName( pc.getEntityName(), auditData.getAuditTable().value() );
context.getAuditEntitiesConfiguration().addCustomAuditTableName( entityBinding.getEntityName(), auditData.getAuditTable().value() );
}
auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, true );
auditMetaGen.generateFirstPass( entityBinding, auditData, xmlMappingData, true );
}
else {
auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, false );
auditMetaGen.generateFirstPass( entityBinding, auditData, xmlMappingData, false );
}
xmlMappings.put( pc, xmlMappingData );
xmlMappings.put( entityBinding, xmlMappingData );
}
// Second pass
for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) {
for ( Map.Entry<EntityBinding, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllEntityBindingAuditedData() ) {
final EntityXmlMappingData xmlMappingData = xmlMappings.get( pcDatasEntry.getKey() );
if ( pcDatasEntry.getValue().isAudited() ) {
auditMetaGen.generateSecondPass( pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData );
try {
cfg.addDocument( writer.write( xmlMappingData.getMainXmlMapping() ) );
//writeDocument(xmlMappingData.getMainXmlMapping());
logDocument( xmlMappingData.getMainXmlMapping() );
context.addDocument( writer.write( xmlMappingData.getMainXmlMapping() ) );
for ( Document additionalMapping : xmlMappingData.getAdditionalXmlMappings() ) {
cfg.addDocument( writer.write( additionalMapping ) );
//writeDocument(additionalMapping);
logDocument( additionalMapping );
context.addDocument( writer.write( additionalMapping ) );
}
}
catch (DocumentException e) {
@ -138,8 +141,8 @@ public class EntitiesConfigurator {
if ( auditMetaGen.getEntitiesConfigurations().size() > 0 ) {
try {
if ( revisionInfoXmlMapping != null ) {
//writeDocument(revisionInfoXmlMapping);
cfg.addDocument( writer.write( revisionInfoXmlMapping ) );
logDocument( revisionInfoXmlMapping );
context.addDocument( writer.write( revisionInfoXmlMapping ) );
}
}
catch (DocumentException e) {
@ -153,8 +156,10 @@ public class EntitiesConfigurator {
);
}
@SuppressWarnings({"UnusedDeclaration"})
private void writeDocument(Document e) {
private void logDocument(Document e) {
if ( !LOG.isDebugEnabled() ) {
return;
}
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Writer w = new PrintWriter( baos );
@ -167,8 +172,8 @@ public class EntitiesConfigurator {
e1.printStackTrace();
}
System.out.println( "-----------" );
System.out.println( baos.toString() );
System.out.println( "-----------" );
LOG.debug( "-----------" );
LOG.debug( baos.toString() );
LOG.debug( "-----------" );
}
}

View File

@ -27,10 +27,10 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hibernate.cfg.Configuration;
import org.hibernate.envers.internal.tools.Tools;
import org.hibernate.envers.internal.tools.graph.GraphDefiner;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.Metadata;
import org.hibernate.metamodel.spi.binding.EntityBinding;
/**
* Defines a graph, where the vertexes are all persistent classes, and there is an edge from
@ -38,45 +38,45 @@ import org.hibernate.mapping.PersistentClass;
*
* @author Adam Warski (adam at warski dot org)
*/
public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass, String> {
private Configuration cfg;
public class EntityBindingGraphDefiner implements GraphDefiner<EntityBinding, String> {
private Metadata metadata;
public PersistentClassGraphDefiner(Configuration cfg) {
this.cfg = cfg;
public EntityBindingGraphDefiner(Metadata metadata) {
this.metadata = metadata;
}
@Override
public String getRepresentation(PersistentClass pc) {
public String getRepresentation(EntityBinding pc) {
return pc.getEntityName();
}
@Override
public PersistentClass getValue(String entityName) {
return cfg.getClassMapping( entityName );
public EntityBinding getValue(String entityName) {
return metadata.getEntityBinding( entityName );
}
@SuppressWarnings({"unchecked"})
private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) {
private void addNeighbours(List<EntityBinding> neighbours, Iterator<EntityBinding> subclassIterator) {
while ( subclassIterator.hasNext() ) {
final PersistentClass subclass = subclassIterator.next();
final EntityBinding subclass = subclassIterator.next();
neighbours.add( subclass );
addNeighbours( neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator() );
addNeighbours( neighbours, subclass.getDirectSubEntityBindings().iterator() );
}
}
@Override
@SuppressWarnings({"unchecked"})
public List<PersistentClass> getNeighbours(PersistentClass pc) {
final List<PersistentClass> neighbours = new ArrayList<PersistentClass>();
public List<EntityBinding> getNeighbours(EntityBinding entityBinding) {
final List<EntityBinding> neighbours = new ArrayList<EntityBinding>();
addNeighbours( neighbours, (Iterator<PersistentClass>) pc.getSubclassIterator() );
addNeighbours( neighbours, entityBinding.getDirectSubEntityBindings().iterator() );
return neighbours;
}
@Override
@SuppressWarnings({"unchecked"})
public List<PersistentClass> getValues() {
return Tools.iteratorToList( cfg.getClassMappings() );
public List<EntityBinding> getValues() {
return Tools.iteratorToList( metadata.getEntityBindings().iterator() );
}
}

View File

@ -23,17 +23,17 @@
*/
package org.hibernate.envers.configuration.internal;
import java.util.Properties;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.envers.RevisionListener;
import org.hibernate.envers.configuration.EnversSettings;
import org.hibernate.envers.internal.tools.ReflectionTools;
import org.hibernate.internal.util.config.ConfigurationHelper;
/**
* @author Adam Warski (adam at warski dot org)
@ -89,46 +89,64 @@ public class GlobalConfiguration {
*/
private final String correlatedSubqueryOperator;
public GlobalConfiguration(Properties properties, ClassLoaderService classLoaderService) {
generateRevisionsForCollections = ConfigurationHelper.getBoolean(
EnversSettings.REVISION_ON_COLLECTION_CHANGE, properties, true
public GlobalConfiguration(StandardServiceRegistry serviceRegistry) {
final ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class );
generateRevisionsForCollections = configurationService.getSetting(
EnversSettings.REVISION_ON_COLLECTION_CHANGE, StandardConverters.BOOLEAN, true
);
doNotAuditOptimisticLockingField = ConfigurationHelper.getBoolean(
EnversSettings.DO_NOT_AUDIT_OPTIMISTIC_LOCKING_FIELD, properties, true
doNotAuditOptimisticLockingField = configurationService.getSetting(
EnversSettings.DO_NOT_AUDIT_OPTIMISTIC_LOCKING_FIELD, StandardConverters.BOOLEAN, true
);
storeDataAtDelete = ConfigurationHelper.getBoolean( EnversSettings.STORE_DATA_AT_DELETE, properties, false );
defaultSchemaName = properties.getProperty( EnversSettings.DEFAULT_SCHEMA, null );
defaultCatalogName = properties.getProperty( EnversSettings.DEFAULT_CATALOG, null );
correlatedSubqueryOperator = HSQLDialect.class.getName()
.equals( properties.get( Environment.DIALECT ) ) ? "in" : "=";
trackEntitiesChangedInRevision = ConfigurationHelper.getBoolean(
EnversSettings.TRACK_ENTITIES_CHANGED_IN_REVISION, properties, false
storeDataAtDelete = configurationService.getSetting(
EnversSettings.STORE_DATA_AT_DELETE, StandardConverters.BOOLEAN, false
);
cascadeDeleteRevision = ConfigurationHelper.getBoolean(
"org.hibernate.envers.cascade_delete_revision", properties, false );
useRevisionEntityWithNativeId = ConfigurationHelper.getBoolean(
EnversSettings.USE_REVISION_ENTITY_WITH_NATIVE_ID, properties, true
defaultSchemaName = configurationService.getSetting(
EnversSettings.DEFAULT_SCHEMA, StandardConverters.STRING
);
defaultCatalogName = configurationService.getSetting(
EnversSettings.DEFAULT_CATALOG, StandardConverters.STRING
);
hasGlobalSettingForWithModifiedFlag = properties.get( EnversSettings.GLOBAL_WITH_MODIFIED_FLAG ) != null;
globalWithModifiedFlag = ConfigurationHelper.getBoolean(
EnversSettings.GLOBAL_WITH_MODIFIED_FLAG, properties, false
);
modifiedFlagSuffix = ConfigurationHelper.getString(
EnversSettings.MODIFIED_FLAG_SUFFIX, properties, "_MOD"
// TODO: is this really needed??? Should be available in dialect...
final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
correlatedSubqueryOperator = HSQLDialect.class.equals( jdbcEnvironment.getDialect().getClass() ) ? "in" : "=";
trackEntitiesChangedInRevision = configurationService.getSetting(
EnversSettings.TRACK_ENTITIES_CHANGED_IN_REVISION, StandardConverters.BOOLEAN, false
);
final String revisionListenerClassName = properties.getProperty( EnversSettings.REVISION_LISTENER, null );
// TODO: shouldn't there be an Envers setting for "org.hibernate.envers.cascade_delete_revision"?
cascadeDeleteRevision = configurationService.getSetting(
"org.hibernate.envers.cascade_delete_revision", StandardConverters.BOOLEAN, false
);
useRevisionEntityWithNativeId = configurationService.getSetting(
EnversSettings.USE_REVISION_ENTITY_WITH_NATIVE_ID, StandardConverters.BOOLEAN, true
);
hasGlobalSettingForWithModifiedFlag = null != configurationService.getSetting(
EnversSettings.GLOBAL_WITH_MODIFIED_FLAG, StandardConverters.BOOLEAN
);
globalWithModifiedFlag = configurationService.getSetting(
EnversSettings.GLOBAL_WITH_MODIFIED_FLAG, StandardConverters.BOOLEAN, false
);
modifiedFlagSuffix = configurationService.getSetting(
EnversSettings.MODIFIED_FLAG_SUFFIX, StandardConverters.STRING, "_MOD"
);
final String revisionListenerClassName = configurationService.getSetting(
EnversSettings.REVISION_LISTENER,
StandardConverters.STRING
);
if ( revisionListenerClassName != null ) {
try {
revisionListenerClass = ReflectionTools.loadClass( revisionListenerClassName, classLoaderService );
revisionListenerClass =
serviceRegistry.getService( ClassLoaderService.class ).classForName( revisionListenerClassName );
}
catch (ClassLoadingException e) {
throw new MappingException(
@ -141,8 +159,8 @@ public class GlobalConfiguration {
revisionListenerClass = null;
}
allowIdentifierReuse = ConfigurationHelper.getBoolean(
EnversSettings.ALLOW_IDENTIFIER_REUSE, properties, false
allowIdentifierReuse = configurationService.getSetting(
EnversSettings.ALLOW_IDENTIFIER_REUSE, StandardConverters.BOOLEAN, false
);
}

View File

@ -23,28 +23,20 @@
*/
package org.hibernate.envers.configuration.internal;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import javax.persistence.Column;
import java.sql.Date;
import java.util.Collection;
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.cfg.Configuration;
import org.hibernate.envers.Audited;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.envers.DefaultRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.RevisionEntity;
import org.hibernate.envers.RevisionListener;
import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp;
import org.hibernate.envers.configuration.internal.metadata.AuditTableData;
import org.hibernate.envers.configuration.internal.metadata.MetadataTools;
import org.hibernate.envers.enhanced.SequenceIdRevisionEntity;
import org.hibernate.envers.enhanced.SequenceIdTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.event.spi.EnversDotNames;
import org.hibernate.envers.internal.entities.PropertyData;
import org.hibernate.envers.internal.revisioninfo.DefaultRevisionInfoGenerator;
import org.hibernate.envers.internal.revisioninfo.DefaultTrackingModifiedEntitiesRevisionInfoGenerator;
@ -53,14 +45,31 @@ import org.hibernate.envers.internal.revisioninfo.RevisionInfoGenerator;
import org.hibernate.envers.internal.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.internal.revisioninfo.RevisionInfoQueryCreator;
import org.hibernate.envers.internal.tools.MutableBoolean;
import org.hibernate.envers.internal.tools.Tools;
import org.hibernate.internal.util.xml.XMLHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.spi.InFlightMetadataCollector;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor;
import org.hibernate.metamodel.spi.binding.SetBinding;
import org.hibernate.type.IntegerType;
import org.hibernate.type.LongType;
import org.hibernate.type.Type;
import org.dom4j.Document;
import org.dom4j.Element;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.MethodInfo;
import static org.hibernate.metamodel.spi.AdditionalJaxbRootProducer.AdditionalJaxbRootProducerContext;
/**
* @author Adam Warski (adam at warski dot org)
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
@ -109,9 +118,9 @@ public class RevisionInfoConfiguration {
classMapping,
revisionInfoIdData.getName(),
revisionPropType,
globalCfg.isUseRevisionEntityWithNativeId()
globalCfg.isUseRevisionEntityWithNativeId(),
"REV"
);
MetadataTools.addColumn( idProperty, "REV", null, null, null, null, null, null, false );
final Element timestampProperty = MetadataTools.addProperty(
classMapping,
@ -178,8 +187,9 @@ public class RevisionInfoConfiguration {
private Element generateRevisionInfoRelationMapping() {
final Document document = XMLHelper.getDocumentFactory().createDocument();
final Element revRelMapping = document.addElement( "key-many-to-one" );
revRelMapping.addAttribute( "type", revisionPropType );
revRelMapping.addAttribute( "class", revisionInfoEntityName );
// TODO: this does not belong here; does it belong somewhere else????
//revRelMapping.addAttribute( "type", revisionPropType );
revRelMapping.addAttribute( "entity-name", revisionInfoEntityName );
if ( revisionPropSqlType != null ) {
// Putting a fake name to make Hibernate happy. It will be replaced later anyway.
@ -189,97 +199,161 @@ public class RevisionInfoConfiguration {
return revRelMapping;
}
private void searchForRevisionInfoCfgInProperties(
XClass clazz,
ReflectionManager reflectionManager,
MutableBoolean revisionNumberFound,
MutableBoolean revisionTimestampFound,
MutableBoolean modifiedEntityNamesFound,
String accessType) {
for ( XProperty property : clazz.getDeclaredProperties( accessType ) ) {
final RevisionNumber revisionNumber = property.getAnnotation( RevisionNumber.class );
final RevisionTimestamp revisionTimestamp = property.getAnnotation( RevisionTimestamp.class );
final ModifiedEntityNames modifiedEntityNames = property.getAnnotation( ModifiedEntityNames.class );
if ( revisionNumber != null ) {
private void searchForRevisionNumberCfg(
ClassInfo revisionInfoEntityClassInfo,
EntityBinding revisionInfoEntityBinding,
AdditionalJaxbRootProducerContext context,
MutableBoolean revisionNumberFound) {
for ( AnnotationInstance annotation : context.getJandexIndex().getAnnotations( EnversDotNames.REVISION_NUMBER ) ) {
final AnnotationTarget annotationTarget = annotation.target();
if ( !( annotationTarget instanceof FieldInfo || annotationTarget instanceof MethodInfo ) ) {
throw new MappingException( "@RevisionNumber is applicable only to fields or properties." );
}
if ( Tools.isFieldOrPropertyOfClass(
annotationTarget,
revisionInfoEntityClassInfo,
context.getJandexIndex() ) ) {
if ( revisionNumberFound.isSet() ) {
throw new MappingException( "Only one property may be annotated with @RevisionNumber!" );
throw new MappingException( "Only one property may be annotated with @RevisionNumber." );
}
final XClass revisionNumberClass = property.getType();
if ( reflectionManager.equals( revisionNumberClass, Integer.class ) ||
reflectionManager.equals( revisionNumberClass, Integer.TYPE ) ) {
revisionInfoIdData = new PropertyData( property.getName(), property.getName(), accessType, null );
revisionNumberFound.set();
final String revisionNumberProperty = JandexHelper.getPropertyName( annotationTarget );
final AttributeBinding revisionNumberAttribute = revisionInfoEntityBinding.locateAttributeBinding(
revisionNumberProperty
);
HibernateTypeDescriptor revisionNumberType = revisionNumberAttribute.getHibernateTypeDescriptor();
// TODO: Check whether it is required to verify HibernateTypeDescriptor#getJavaTypeName()?
if ( revisionNumberType.getResolvedTypeMapping() instanceof IntegerType ) {
revisionPropType = "integer";
}
else if ( reflectionManager.equals( revisionNumberClass, Long.class ) ||
reflectionManager.equals( revisionNumberClass, Long.TYPE ) ) {
revisionInfoIdData = new PropertyData( property.getName(), property.getName(), accessType, null );
revisionNumberFound.set();
// The default is integer
else if ( revisionNumberType.getResolvedTypeMapping() instanceof LongType ) {
// The default is integer.
revisionPropType = "long";
}
else {
throw new MappingException(
"The field annotated with @RevisionNumber must be of type " +
"int, Integer, long or Long"
"Field annotated with @RevisionNumber must be of type int, Integer, long or Long."
);
}
revisionInfoIdData = new PropertyData(
revisionNumberProperty,
revisionNumberProperty,
revisionNumberAttribute.getPropertyAccessorName(),
null
);
revisionNumberFound.set();
// Getting the @Column definition of the revision number property, to later use that info to
// generate the same mapping for the relation from an audit table's revision number to the
// revision entity revision number.
final Column revisionPropColumn = property.getAnnotation( Column.class );
if ( revisionPropColumn != null ) {
revisionPropSqlType = revisionPropColumn.columnDefinition();
final AnnotationInstance jpaColumnAnnotation = JandexHelper.getSingleAnnotation(
JandexHelper.getMemberAnnotations(
revisionInfoEntityClassInfo,
revisionNumberProperty,
context.getServiceRegistry()
),
JPADotNames.COLUMN
);
if ( jpaColumnAnnotation != null ) {
final ClassLoaderService classLoaderService =
context.getServiceRegistry().getService( ClassLoaderService.class );
revisionPropSqlType = JandexHelper.getValue(
jpaColumnAnnotation,
"columnDefinition",
String.class,
classLoaderService
);
}
}
}
}
if ( revisionTimestamp != null ) {
private void searchForRevisionTimestampCfg(
ClassInfo revisionInfoEntityClassInfo,
EntityBinding revisionInfoEntityBinding,
AdditionalJaxbRootProducerContext context,
MutableBoolean revisionTimestampFound) {
final IndexView jandexIndex = context.getJandexIndex();
for ( AnnotationInstance annotation : jandexIndex.getAnnotations( EnversDotNames.REVISION_TIMESTAMP ) ) {
AnnotationTarget annotationTarget = annotation.target();
if ( !( annotationTarget instanceof FieldInfo || annotationTarget instanceof MethodInfo ) ) {
throw new MappingException( "@RevisionTimestamp is applicable only to fields or properties." );
}
if ( Tools.isFieldOrPropertyOfClass( annotationTarget, revisionInfoEntityClassInfo, jandexIndex ) ) {
if ( revisionTimestampFound.isSet() ) {
throw new MappingException( "Only one property may be annotated with @RevisionTimestamp!" );
throw new MappingException( "Only one property may be annotated with @RevisionTimestamp." );
}
final XClass revisionTimestampClass = property.getType();
if ( reflectionManager.equals( revisionTimestampClass, Long.class ) ||
reflectionManager.equals( revisionTimestampClass, Long.TYPE ) ||
reflectionManager.equals( revisionTimestampClass, Date.class ) ||
reflectionManager.equals( revisionTimestampClass, java.sql.Date.class ) ) {
final String revisionTimestampProperty = JandexHelper.getPropertyName( annotationTarget );
final AttributeBinding revisionTimestampAttribute = revisionInfoEntityBinding.locateAttributeBinding(
revisionTimestampProperty
);
HibernateTypeDescriptor revisionTimestampType = revisionTimestampAttribute.getHibernateTypeDescriptor();
final String revisionTimestampClassName = revisionTimestampType.getJavaTypeDescriptor().getName().fullName();
if ( Long.TYPE.getName().equals( revisionTimestampClassName ) ||
java.util.Date.class.getName().equals( revisionTimestampClassName ) ||
Date.class.getName().equals( revisionTimestampClassName) ) {
revisionInfoTimestampData = new PropertyData(
property.getName(),
property.getName(),
accessType,
revisionTimestampProperty,
revisionTimestampProperty,
revisionTimestampAttribute.getPropertyAccessorName(),
null
);
revisionTimestampFound.set();
}
else {
throw new MappingException(
"The field annotated with @RevisionTimestamp must be of type " +
"long, Long, java.util.Date or java.sql.Date"
"Field annotated with @RevisionTimestamp must be of type long, Long, java.util.Date or java.sql.Date."
);
}
}
}
}
if ( modifiedEntityNames != null ) {
private void searchForModifiedEntityNamesCfg(
ClassInfo revisionInfoEntityClassInfo,
EntityBinding revisionInfoEntityBinding,
AdditionalJaxbRootProducerContext context,
MutableBoolean modifiedEntityNamesFound) {
final IndexView jandexIndex = context.getJandexIndex();
for ( AnnotationInstance annotation : jandexIndex.getAnnotations( EnversDotNames.MODIFIED_ENTITY_NAMES ) ) {
AnnotationTarget annotationTarget = annotation.target();
if ( !( annotationTarget instanceof FieldInfo || annotationTarget instanceof MethodInfo ) ) {
throw new MappingException( "@ModifiedEntityNames is applicable only to fields or properties." );
}
if ( Tools.isFieldOrPropertyOfClass( annotationTarget, revisionInfoEntityClassInfo, jandexIndex ) ) {
if ( modifiedEntityNamesFound.isSet() ) {
throw new MappingException( "Only one property may be annotated with @ModifiedEntityNames!" );
throw new MappingException( "Only one property may be annotated with @ModifiedEntityNames." );
}
final XClass modifiedEntityNamesClass = property.getType();
if ( reflectionManager.equals( modifiedEntityNamesClass, Set.class ) &&
reflectionManager.equals( property.getElementClass(), String.class ) ) {
modifiedEntityNamesData = new PropertyData(
property.getName(),
property.getName(),
accessType,
null
);
modifiedEntityNamesFound.set();
final String modifiedEntityNamesProperty = JandexHelper.getPropertyName( annotationTarget );
final AttributeBinding modifiedEntityNamesAttribute = revisionInfoEntityBinding.locateAttributeBinding(
modifiedEntityNamesProperty
);
if ( modifiedEntityNamesAttribute instanceof SetBinding ) {
final SetBinding collectionBinding = (SetBinding) modifiedEntityNamesAttribute;
final String elementType =
collectionBinding
.getPluralAttributeElementBinding()
.getHibernateTypeDescriptor()
.getJavaTypeDescriptor().getName().fullName();
if ( String.class.getName().equals( elementType ) ) {
modifiedEntityNamesData = new PropertyData(
modifiedEntityNamesProperty,
modifiedEntityNamesProperty,
modifiedEntityNamesAttribute.getPropertyAccessorName(),
null
);
modifiedEntityNamesFound.set();
}
}
else {
if ( !modifiedEntityNamesFound.isSet() ) {
throw new MappingException(
"The field annotated with @ModifiedEntityNames must be of Set<String> type."
"Field annotated with @ModifiedEntityNames must be of Set<String> type."
);
}
}
@ -287,135 +361,136 @@ public class RevisionInfoConfiguration {
}
private void searchForRevisionInfoCfg(
XClass clazz, ReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
ClassInfo revisionInfoEntityClassInfo,
EntityBinding revisionInfoEntityBinding,
AdditionalJaxbRootProducerContext context,
MutableBoolean revisionNumberFound,
MutableBoolean revisionTimestampFound,
MutableBoolean modifiedEntityNamesFound) {
final XClass superclazz = clazz.getSuperclass();
if ( !"java.lang.Object".equals( superclazz.getName() ) ) {
searchForRevisionNumberCfg( revisionInfoEntityClassInfo, revisionInfoEntityBinding, context, revisionNumberFound );
searchForRevisionTimestampCfg(
revisionInfoEntityClassInfo,
revisionInfoEntityBinding,
context,
revisionTimestampFound
);
searchForModifiedEntityNamesCfg(
revisionInfoEntityClassInfo,
revisionInfoEntityBinding,
context,
modifiedEntityNamesFound
);
}
public RevisionInfoConfigurationResult configure(
InFlightMetadataCollector metadataCollector,
AdditionalJaxbRootProducerContext context) {
final ClassLoaderService classLoaderService = context.getServiceRegistry().getService( ClassLoaderService.class );
boolean revisionEntityFound = false;
RevisionInfoGenerator revisionInfoGenerator = null;
Class<?> revisionInfoEntityClass = null;
// Locate @RevisionEntity provided by user and validate its mapping.
Collection<AnnotationInstance> revisionEntityAnnotations = context.getJandexIndex().getAnnotations(
EnversDotNames.REVISION_ENTITY
);
if ( revisionEntityAnnotations.size() > 1 ) {
throw new MappingException( "Only one entity may be annotated with @RevisionEntity." );
}
if ( revisionEntityAnnotations.size() == 1 ) {
final AnnotationInstance revisionEntityAnnotation = revisionEntityAnnotations.iterator().next();
final ClassInfo revisionInfoEntityClassInfo = (ClassInfo) revisionEntityAnnotation.target();
// TODO: Get rid of revisionInfoEntityClass (don't want to load the class).
revisionInfoEntityClass = classLoaderService.classForName( revisionInfoEntityClassInfo.name().toString() );
// TODO: get entity name from @Entity
revisionInfoEntityName = revisionInfoEntityClass.getName();
final EntityBinding revisionInfoEntityBinding = metadataCollector.getEntityBinding(
revisionInfoEntityName
);
if ( revisionInfoEntityClassInfo.annotations().containsKey( EnversDotNames.AUDITED ) ) {
throw new MappingException( "An entity annotated with @RevisionEntity cannot be audited." );
}
MutableBoolean revisionNumberFound = new MutableBoolean();
MutableBoolean revisionTimestampFound = new MutableBoolean();
MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
searchForRevisionInfoCfg(
superclazz,
reflectionManager,
revisionInfoEntityClassInfo,
revisionInfoEntityBinding,
context,
revisionNumberFound,
revisionTimestampFound,
modifiedEntityNamesFound
);
}
searchForRevisionInfoCfgInProperties(
clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityNamesFound, "field"
);
searchForRevisionInfoCfgInProperties(
clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityNamesFound, "property"
);
}
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
boolean revisionEntityFound = false;
RevisionInfoGenerator revisionInfoGenerator = null;
Class<?> revisionInfoClass = null;
final Iterator<PersistentClass> classes = cfg.getClassMappings();
while ( classes.hasNext() ) {
PersistentClass pc = classes.next();
XClass clazz;
try {
clazz = reflectionManager.classForName( pc.getClassName(), this.getClass() );
}
catch (ClassNotFoundException e) {
throw new MappingException( e );
}
final RevisionEntity revisionEntity = clazz.getAnnotation( RevisionEntity.class );
if ( revisionEntity != null ) {
if ( revisionEntityFound ) {
throw new MappingException( "Only one entity may be annotated with @RevisionEntity!" );
}
// Checking if custom revision entity isn't audited
if ( clazz.getAnnotation( Audited.class ) != null ) {
throw new MappingException( "An entity annotated with @RevisionEntity cannot be audited!" );
}
revisionEntityFound = true;
final MutableBoolean revisionNumberFound = new MutableBoolean();
final MutableBoolean revisionTimestampFound = new MutableBoolean();
final MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
searchForRevisionInfoCfg(
clazz,
reflectionManager,
revisionNumberFound,
revisionTimestampFound,
modifiedEntityNamesFound
if ( !revisionNumberFound.isSet() ) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated with @RevisionNumber!"
);
}
if ( !revisionNumberFound.isSet() ) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionNumber!"
);
}
if ( !revisionTimestampFound.isSet() ) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated with @RevisionTimestamp!"
);
}
if ( !revisionTimestampFound.isSet() ) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionTimestamp!"
);
}
revisionInfoEntityName = pc.getEntityName();
revisionInfoClass = pc.getMappedClass();
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( revisionEntity.value() );
revisionInfoTimestampType = pc.getProperty( revisionInfoTimestampData.getName() ).getType();
if ( globalCfg.isTrackEntitiesChangedInRevision()
|| (globalCfg.isUseRevisionEntityWithNativeId() && DefaultTrackingModifiedEntitiesRevisionEntity.class
.isAssignableFrom( revisionInfoClass ))
|| (!globalCfg.isUseRevisionEntityWithNativeId() && SequenceIdTrackingModifiedEntitiesRevisionEntity.class
.isAssignableFrom( revisionInfoClass ))
|| modifiedEntityNamesFound.isSet() ) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
revisionInfoEntityName,
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityNamesData
);
globalCfg.setTrackEntitiesChangedInRevision( true );
}
else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
}
Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(
classLoaderService,
revisionEntityAnnotation
);
revisionInfoTimestampType =
revisionInfoEntityBinding.locateAttributeBinding( revisionInfoTimestampData.getName() )
.getHibernateTypeDescriptor()
.getResolvedTypeMapping();
if ( globalCfg.isTrackEntitiesChangedInRevision()
|| ( globalCfg.isUseRevisionEntityWithNativeId() && DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom( revisionInfoEntityClass ) )
|| ( !globalCfg.isUseRevisionEntityWithNativeId() && SequenceIdTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom( revisionInfoEntityClass ) )
|| modifiedEntityNamesFound.isSet() ) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
revisionInfoEntityBinding.getEntity().getName(), revisionInfoEntityClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData
);
globalCfg.setTrackEntitiesChangedInRevision( true );
}
else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityBinding.getEntity().getName(), revisionInfoEntityClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
}
}
// In case of a custom revision info generator, the mapping will be null.
Document revisionInfoXmlMapping = null;
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( RevisionListener.class );
if ( revisionInfoGenerator == null ) {
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( classLoaderService, null );
if ( globalCfg.isTrackEntitiesChangedInRevision() ) {
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ?
DefaultTrackingModifiedEntitiesRevisionEntity.class
:
revisionInfoEntityClass = globalCfg.isUseRevisionEntityWithNativeId() ?
DefaultTrackingModifiedEntitiesRevisionEntity.class :
SequenceIdTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoEntityName = revisionInfoClass.getName();
revisionInfoEntityName = revisionInfoEntityClass.getName();
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionInfoEntityName, revisionInfoEntityClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData
);
}
else {
revisionInfoClass = globalCfg.isUseRevisionEntityWithNativeId() ? DefaultRevisionEntity.class
: SequenceIdRevisionEntity.class;
revisionInfoEntityClass = globalCfg.isUseRevisionEntityWithNativeId() ?
DefaultRevisionEntity.class :
SequenceIdRevisionEntity.class;
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionInfoEntityName, revisionInfoEntityClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
}
@ -429,13 +504,13 @@ public class RevisionInfoConfiguration {
revisionInfoTimestampData.getName(), isTimestampAsDate()
),
generateRevisionInfoRelationMapping(),
new RevisionInfoNumberReader( revisionInfoClass, revisionInfoIdData ),
new RevisionInfoNumberReader( revisionInfoEntityClass, revisionInfoIdData ),
globalCfg.isTrackEntitiesChangedInRevision() ? new ModifiedEntityNamesReader(
revisionInfoClass,
revisionInfoEntityClass,
modifiedEntityNamesData
)
: null,
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData
revisionInfoEntityName, revisionInfoEntityClass, revisionInfoTimestampData
);
}
@ -445,15 +520,21 @@ public class RevisionInfoConfiguration {
}
/**
* @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener}
* parameter has not been set.
*
* Method takes into consideration {@code org.hibernate.envers.revision_listener} parameter and custom
* {@link RevisionEntity} annotation.
* @param classLoaderService Class loading service.
* @param revisionEntityAnnotation User defined @RevisionEntity annotation, or {@code null} if none.
* @return Revision listener.
*/
private Class<? extends RevisionListener> getRevisionListenerClass(Class<? extends RevisionListener> defaultListener) {
private Class<? extends RevisionListener> getRevisionListenerClass(ClassLoaderService classLoaderService,
AnnotationInstance revisionEntityAnnotation) {
if ( globalCfg.getRevisionListenerClass() != null ) {
return globalCfg.getRevisionListenerClass();
}
return defaultListener;
if ( revisionEntityAnnotation != null && revisionEntityAnnotation.value() != null ) {
// User provided revision listener implementation in @RevisionEntity mapping.
return classLoaderService.classForName( revisionEntityAnnotation.value().asString() );
}
return RevisionListener.class;
}
}

View File

@ -23,18 +23,17 @@
*/
package org.hibernate.envers.configuration.internal.metadata;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.Configuration;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
import org.hibernate.envers.configuration.internal.metadata.reader.ClassAuditingData;
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.envers.internal.EnversMessageLogger;
import org.hibernate.envers.internal.entities.EntityConfiguration;
import org.hibernate.envers.internal.entities.IdMappingData;
@ -46,13 +45,16 @@ import org.hibernate.envers.internal.tools.StringTools;
import org.hibernate.envers.internal.tools.Triple;
import org.hibernate.envers.strategy.AuditStrategy;
import org.hibernate.envers.strategy.ValidityAuditStrategy;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.OneToOne;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.EntityDiscriminator;
import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.OneToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.type.CollectionType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.ManyToOneType;
@ -78,12 +80,8 @@ public final class AuditMetadataGenerator {
EnversMessageLogger.class,
AuditMetadataGenerator.class.getName()
);
private final Configuration cfg;
private final GlobalConfiguration globalCfg;
private final AuditEntitiesConfiguration verEntCfg;
private final AuditConfiguration.AuditConfigurationContext context;
private final AuditStrategy auditStrategy;
private final ClassLoaderService classLoaderService;
private final Element revisionInfoRelationMapping;
/*
@ -102,32 +100,31 @@ public final class AuditMetadataGenerator {
private final AuditEntityNameRegister auditEntityNameRegister;
// TODO: add support for secondary tables.
// Map entity name -> (join descriptor -> element describing the "versioned" join)
private final Map<String, Map<Join, Element>> entitiesJoins;
//private final Map<String, Map<Join, Element>> entitiesJoins;
public AuditMetadataGenerator(
Configuration cfg, GlobalConfiguration globalCfg,
AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy, ClassLoaderService classLoaderService,
AuditConfiguration.AuditConfigurationContext context,
AuditStrategy auditStrategy,
Element revisionInfoRelationMapping,
AuditEntityNameRegister auditEntityNameRegister) {
this.cfg = cfg;
this.globalCfg = globalCfg;
this.verEntCfg = verEntCfg;
this.context = context;
this.auditStrategy = auditStrategy;
this.classLoaderService = classLoaderService;
this.revisionInfoRelationMapping = revisionInfoRelationMapping;
this.basicMetadataGenerator = new BasicMetadataGenerator();
this.componentMetadataGenerator = new ComponentMetadataGenerator( this );
this.idMetadataGenerator = new IdMetadataGenerator( this );
this.componentMetadataGenerator = new ComponentMetadataGenerator( context, this );
this.idMetadataGenerator = new IdMetadataGenerator( context, this );
this.toOneRelationMetadataGenerator = new ToOneRelationMetadataGenerator( this );
this.auditEntityNameRegister = auditEntityNameRegister;
entitiesConfigurations = new HashMap<String, EntityConfiguration>();
notAuditedEntitiesConfigurations = new HashMap<String, EntityConfiguration>();
entitiesJoins = new HashMap<String, Map<Join, Element>>();
// TODO: add support for secondary tables.
//entitiesJoins = new HashMap<String, Map<SecondaryTable, Element>>();
}
/**
@ -138,12 +135,12 @@ public final class AuditMetadataGenerator {
*/
private Element cloneAndSetupRevisionInfoRelationMapping() {
final Element revMapping = (Element) revisionInfoRelationMapping.clone();
revMapping.addAttribute( "name", verEntCfg.getRevisionFieldName() );
if ( globalCfg.isCascadeDeleteRevision() ) {
revMapping.addAttribute( "name", context.getAuditEntitiesConfiguration().getRevisionFieldName() );
if ( context.getGlobalConfiguration().isCascadeDeleteRevision() ) {
revMapping.addAttribute( "on-delete", "cascade" );
}
MetadataTools.addOrModifyColumn( revMapping, verEntCfg.getRevisionFieldName() );
MetadataTools.addOrModifyColumn( revMapping, context.getAuditEntitiesConfiguration().getRevisionFieldName() );
return revMapping;
}
@ -152,13 +149,13 @@ public final class AuditMetadataGenerator {
anyMapping.add( cloneAndSetupRevisionInfoRelationMapping() );
}
void addRevisionType(Element anyMapping, Element anyMappingEnd) {
void addRevisionType(Element anyMapping, Element anyMappingEnd, boolean key) {
final Element revTypeProperty = MetadataTools.addProperty(
anyMapping,
verEntCfg.getRevisionTypePropName(),
verEntCfg.getRevisionTypePropType(),
context.getAuditEntitiesConfiguration().getRevisionTypePropName(),
context.getAuditEntitiesConfiguration().getRevisionTypePropType(),
true,
false
key
);
revTypeProperty.addAttribute( "type", "org.hibernate.envers.internal.entities.RevisionTypeType" );
@ -171,17 +168,17 @@ public final class AuditMetadataGenerator {
if ( auditStrategy instanceof ValidityAuditStrategy ) {
final Element endRevMapping = (Element) revisionInfoRelationMapping.clone();
endRevMapping.setName( "many-to-one" );
endRevMapping.addAttribute( "name", verEntCfg.getRevisionEndFieldName() );
MetadataTools.addOrModifyColumn( endRevMapping, verEntCfg.getRevisionEndFieldName() );
endRevMapping.addAttribute( "name", context.getAuditEntitiesConfiguration().getRevisionEndFieldName() );
MetadataTools.addOrModifyColumn( endRevMapping, context.getAuditEntitiesConfiguration().getRevisionEndFieldName() );
anyMapping.add( endRevMapping );
if ( verEntCfg.isRevisionEndTimestampEnabled() ) {
if ( context.getAuditEntitiesConfiguration().isRevisionEndTimestampEnabled() ) {
// add a column for the timestamp of the end revision
final String revisionInfoTimestampSqlType = TimestampType.INSTANCE.getName();
final Element timestampProperty = MetadataTools.addProperty(
anyMapping,
verEntCfg.getRevisionEndTimestampFieldName(),
context.getAuditEntitiesConfiguration().getRevisionEndTimestampFieldName(),
revisionInfoTimestampSqlType,
true,
true,
@ -189,7 +186,7 @@ public final class AuditMetadataGenerator {
);
MetadataTools.addColumn(
timestampProperty,
verEntCfg.getRevisionEndTimestampFieldName(),
context.getAuditEntitiesConfiguration().getRevisionEndTimestampFieldName(),
null,
null,
null,
@ -203,20 +200,33 @@ public final class AuditMetadataGenerator {
private void addValueInFirstPass(
Element parent,
Value value,
AttributeBinding attributeBinding,
CompositeMapperBuilder currentMapper,
String entityName,
EntityXmlMappingData xmlMappingData,
PropertyAuditingData propertyAuditingData,
boolean insertable,
boolean processModifiedFlag) {
final Type type = value.getType();
final Type type = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
final List<Value> values;
final boolean isInsertable;
if ( attributeBinding.getAttribute().isSingular() ) {
final SingularAttributeBinding singularAttributeBinding = (SingularAttributeBinding) attributeBinding;
values = singularAttributeBinding.getValues();
isInsertable = singularAttributeBinding.isIncludedInInsert();
}
else {
values = null;
isInsertable = false;
}
final boolean isBasic = basicMetadataGenerator.addBasic(
parent,
propertyAuditingData,
value,
attributeBinding.getHibernateTypeDescriptor(),
values,
isInsertable,
currentMapper,
insertable,
false
);
@ -225,8 +235,13 @@ public final class AuditMetadataGenerator {
}
else if ( type instanceof ComponentType ) {
componentMetadataGenerator.addComponent(
parent, propertyAuditingData, value, currentMapper,
entityName, xmlMappingData, true
parent,
propertyAuditingData,
(CompositeAttributeBinding) attributeBinding,
currentMapper,
entityName,
xmlMappingData,
true
);
}
else {
@ -247,20 +262,19 @@ public final class AuditMetadataGenerator {
private void addValueInSecondPass(
Element parent,
Value value,
AttributeBinding attributeBinding,
CompositeMapperBuilder currentMapper,
String entityName,
EntityXmlMappingData xmlMappingData,
PropertyAuditingData propertyAuditingData,
boolean insertable,
boolean processModifiedFlag) {
final Type type = value.getType();
final Type type = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
if ( type instanceof ComponentType ) {
componentMetadataGenerator.addComponent(
parent,
propertyAuditingData,
value,
(CompositeAttributeBinding) attributeBinding,
currentMapper,
entityName,
xmlMappingData,
@ -273,18 +287,17 @@ public final class AuditMetadataGenerator {
toOneRelationMetadataGenerator.addToOne(
parent,
propertyAuditingData,
value,
(ManyToOneAttributeBinding) attributeBinding,
currentMapper,
entityName,
insertable
entityName
);
}
else if ( type instanceof OneToOneType ) {
final OneToOne oneToOne = (OneToOne) value;
if ( oneToOne.getReferencedPropertyName() != null ) {
final OneToOneAttributeBinding oneToOneAttributeBinding = (OneToOneAttributeBinding) attributeBinding;
if ( oneToOneAttributeBinding.getReferencedAttributeBinding().getAttribute().getName() != null ) {
toOneRelationMetadataGenerator.addOneToOneNotOwning(
propertyAuditingData,
value,
oneToOneAttributeBinding,
currentMapper,
entityName
);
@ -293,17 +306,17 @@ public final class AuditMetadataGenerator {
// @OneToOne relation marked with @PrimaryKeyJoinColumn
toOneRelationMetadataGenerator.addOneToOnePrimaryKeyJoinColumn(
propertyAuditingData,
value,
oneToOneAttributeBinding,
currentMapper,
entityName,
insertable
entityName
);
}
}
else if ( type instanceof CollectionType ) {
final CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(
context,
this,
(Collection) value,
(PluralAttributeBinding) attributeBinding,
currentMapper,
entityName,
xmlMappingData,
@ -325,50 +338,53 @@ public final class AuditMetadataGenerator {
MetadataTools.addModifiedFlagProperty(
parent,
propertyAuditingData.getName(),
globalCfg.getModifiedFlagSuffix()
context.getGlobalConfiguration().getModifiedFlagSuffix()
);
}
}
void addValue(
Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
boolean insertable, boolean firstPass, boolean processModifiedFlag) {
Element parent,
AttributeBinding attributeBinding,
CompositeMapperBuilder currentMapper,
String entityName,
EntityXmlMappingData xmlMappingData,
PropertyAuditingData propertyAuditingData,
boolean firstPass,
boolean processModifiedFlag) {
if ( firstPass ) {
addValueInFirstPass(
parent, value, currentMapper, entityName,
xmlMappingData, propertyAuditingData, insertable, processModifiedFlag
parent, attributeBinding, currentMapper, entityName,
xmlMappingData, propertyAuditingData, processModifiedFlag
);
}
else {
addValueInSecondPass(
parent, value, currentMapper, entityName,
xmlMappingData, propertyAuditingData, insertable, processModifiedFlag
parent, attributeBinding, currentMapper, entityName,
xmlMappingData, propertyAuditingData, processModifiedFlag
);
}
}
private void addProperties(
Element parent,
Iterator<Property> properties,
AttributeBinding[] properties,
CompositeMapperBuilder currentMapper,
ClassAuditingData auditingData,
String entityName,
EntityXmlMappingData xmlMappingData,
boolean firstPass) {
while ( properties.hasNext() ) {
final Property property = properties.next();
final String propertyName = property.getName();
for ( AttributeBinding property : properties ) {
final String propertyName = property.getAttribute().getName();
final PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData( propertyName );
if ( propertyAuditingData != null ) {
addValue(
parent,
property.getValue(),
property,
currentMapper,
entityName,
xmlMappingData,
propertyAuditingData,
property.isInsertable(),
firstPass,
true
);
@ -376,10 +392,10 @@ public final class AuditMetadataGenerator {
}
}
private boolean checkPropertiesAudited(Iterator<Property> properties, ClassAuditingData auditingData) {
private boolean checkPropertiesAudited(Iterator<AttributeBinding> properties, ClassAuditingData auditingData) {
while ( properties.hasNext() ) {
final Property property = properties.next();
final String propertyName = property.getName();
final AttributeBinding property = properties.next();
final String propertyName = property.getAttribute().getName();
final PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData( propertyName );
if ( propertyAuditingData == null ) {
return false;
@ -389,151 +405,193 @@ public final class AuditMetadataGenerator {
return true;
}
protected String getSchema(String schemaFromAnnotation, Table table) {
protected String getSchema(String schemaFromAnnotation, TableSpecification table) {
// Get the schema from the annotation ...
String schema = schemaFromAnnotation;
// ... if empty, try using the default ...
if ( StringTools.isEmpty( schema ) ) {
schema = globalCfg.getDefaultSchemaName();
schema = context.getGlobalConfiguration().getDefaultSchemaName();
// ... if still empty, use the same as the normal table.
if ( StringTools.isEmpty( schema ) ) {
schema = table.getSchema();
if ( StringTools.isEmpty( schema ) && table.getSchema().getName().getSchema() != null) {
schema = table.getSchema().getName().getSchema().getText();
}
}
return schema;
}
protected String getCatalog(String catalogFromAnnotation, Table table) {
protected String getCatalog(String catalogFromAnnotation, TableSpecification table) {
// Get the catalog from the annotation ...
String catalog = catalogFromAnnotation;
// ... if empty, try using the default ...
if ( StringTools.isEmpty( catalog ) ) {
catalog = globalCfg.getDefaultCatalogName();
catalog = context.getGlobalConfiguration().getDefaultCatalogName();
// ... if still empty, use the same as the normal table.
if ( StringTools.isEmpty( catalog ) ) {
catalog = table.getCatalog();
if ( StringTools.isEmpty( catalog ) && table.getSchema().getName().getCatalog() != null ) {
catalog = table.getSchema().getName().getCatalog().getText();
}
}
return catalog;
}
@SuppressWarnings({"unchecked"})
private void createJoins(PersistentClass pc, Element parent, ClassAuditingData auditingData) {
final Iterator<Join> joins = pc.getJoinIterator();
final Map<Join, Element> joinElements = new HashMap<Join, Element>();
entitiesJoins.put( pc.getEntityName(), joinElements );
// TODO: add support for secondary tables
// private void createJoins(EntityBinding entityBinding, Element parent, ClassAuditingData auditingData) {
// final Iterator<SecondaryTable> joins = entityBinding.getSecondaryTables();
// final Map<SecondaryTable, Element> joinElements = new HashMap<SecondaryTable, Element>();
// entitiesJoins.put( entityBinding.getEntityName(), joinElements );
while ( joins.hasNext() ) {
Join join = joins.next();
// while ( joins.hasNext() ) {
// SecondaryTable join = joins.next();
// Checking if all of the join properties are audited
if ( !checkPropertiesAudited( join.getPropertyIterator(), auditingData ) ) {
continue;
}
// if ( !checkPropertiesAudited( join.getPropertyIterator(), auditingData ) ) {
// continue;
// }
// Determining the table name. If there is no entry in the dictionary, just constructing the table name
// as if it was an entity (by appending/prepending configured strings).
final String originalTableName = join.getTable().getName();
String auditTableName = auditingData.getSecondaryTableDictionary().get( originalTableName );
if ( auditTableName == null ) {
auditTableName = verEntCfg.getAuditEntityName( originalTableName );
}
// final String originalTableName = join.getSecondaryTableReference().getLogicalName().getText();
// String auditTableName = auditingData.getSecondaryTableDictionary().get( originalTableName );
// if ( auditTableName == null ) {
// auditTableName = context.getAuditEntitiesConfiguration().getAuditEntityName( originalTableName );
// }
final String schema = getSchema( auditingData.getAuditTable().schema(), join.getTable() );
final String catalog = getCatalog( auditingData.getAuditTable().catalog(), join.getTable() );
// final String schema = getSchema( auditingData.getAuditTable().schema(), join.getSecondaryTableReference() );
// final String catalog = getCatalog( auditingData.getAuditTable().catalog(), join.getSecondaryTableReference() );
final Element joinElement = MetadataTools.createJoin( parent, auditTableName, schema, catalog );
joinElements.put( join, joinElement );
// final Element joinElement = MetadataTools.createJoin( parent, auditTableName, schema, catalog );
// joinElements.put( join, joinElement );
final Element joinKey = joinElement.addElement( "key" );
MetadataTools.addColumns( joinKey, join.getKey().getColumnIterator() );
MetadataTools.addColumn( joinKey, verEntCfg.getRevisionFieldName(), null, null, null, null, null, null );
}
}
// final Element joinKey = joinElement.addElement( "key" );
// MetadataTools.addColumns( joinKey, join.getForeignKeyReference().getColumns() );
// MetadataTools.addColumn( joinKey, context.getAuditEntitiesConfiguration().getRevisionFieldName(), null, null, null, null, null, null );
// }
// }
@SuppressWarnings({"unchecked"})
private void addJoins(
PersistentClass pc,
CompositeMapperBuilder currentMapper,
ClassAuditingData auditingData,
String entityName,
EntityXmlMappingData xmlMappingData,
boolean firstPass) {
final Iterator<Join> joins = pc.getJoinIterator();
// @SuppressWarnings({"unchecked"})
// private void createJoins(PersistentClass pc, Element parent, ClassAuditingData auditingData) {
// final Iterator<Join> joins = pc.getJoinIterator();
// final Map<Join, Element> joinElements = new HashMap<Join, Element>();
// entitiesJoins.put( pc.getEntityName(), joinElements );
//
// while ( joins.hasNext() ) {
// Join join = joins.next();
while ( joins.hasNext() ) {
final Join join = joins.next();
final Element joinElement = entitiesJoins.get( entityName ).get( join );
// Checking if all of the join properties are audited
// if ( !checkPropertiesAudited( join.getPropertyIterator(), auditingData ) ) {
// continue;
// }
if ( joinElement != null ) {
addProperties(
joinElement,
join.getPropertyIterator(),
currentMapper,
auditingData,
entityName,
xmlMappingData,
firstPass
);
}
}
}
// Determining the table name. If there is no entry in the dictionary, just constructing the table name
// as if it was an entity (by appending/prepending configured strings).
// final String originalTableName = join.getTable().getName();
// String auditTableName = auditingData.getSecondaryTableDictionary().get( originalTableName );
// if ( auditTableName == null ) {
// auditTableName = verEntCfg.getAuditEntityName( originalTableName );
// }
// final String schema = getSchema( auditingData.getAuditTable().schema(), join.getTable() );
// final String catalog = getCatalog( auditingData.getAuditTable().catalog(), join.getTable() );
// final Element joinElement = MetadataTools.createJoin( parent, auditTableName, schema, catalog );
// joinElements.put( join, joinElement );
// final Element joinKey = joinElement.addElement( "key" );
// MetadataTools.addColumns( joinKey, join.getKey().getColumnIterator() );
// MetadataTools.addColumn( joinKey, verEntCfg.getRevisionFieldName(), null, null, null, null, null, null );
// }
// }
// @SuppressWarnings({"unchecked"})
// private void addJoins(
// PersistentClass pc,
// CompositeMapperBuilder currentMapper,
// ClassAuditingData auditingData,
// String entityName,
// EntityXmlMappingData xmlMappingData,
// boolean firstPass) {
// final Iterator<Join> joins = pc.getJoinIterator();
// while ( joins.hasNext() ) {
// final Join join = joins.next();
// final Element joinElement = entitiesJoins.get( entityName ).get( join );
// if ( joinElement != null ) {
// addProperties(
// joinElement,
// join.getPropertyIterator(),
// currentMapper,
// auditingData,
// entityName,
// xmlMappingData,
// firstPass
// );
// }
// }
// }
@SuppressWarnings({"unchecked"})
private Triple<Element, ExtendedPropertyMapper, String> generateMappingData(
PersistentClass pc, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
EntityBinding entityBinding, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
IdMappingData idMapper) {
final Element classMapping = MetadataTools.createEntity(
xmlMappingData.getMainXmlMapping(),
auditTableData,
pc.getDiscriminatorValue(),
pc.isAbstract()
entityBinding.getDiscriminatorMatchValue(),
entityBinding.isAbstract()
);
final ExtendedPropertyMapper propertyMapper = new MultiPropertyMapper();
// Checking if there is a discriminator column
if ( pc.getDiscriminator() != null ) {
final Element discriminatorElement = classMapping.addElement( "discriminator" );
// Database column or SQL formula allowed to distinguish entity types
MetadataTools.addColumnsOrFormulas( discriminatorElement, pc.getDiscriminator().getColumnIterator() );
discriminatorElement.addAttribute( "type", pc.getDiscriminator().getType().getName() );
}
// Adding the id mapping
classMapping.add( (Element) idMapper.getXmlMapping().clone() );
// Checking if there is a discriminator column
if ( entityBinding.getHierarchyDetails().getEntityDiscriminator() != null ) {
final EntityDiscriminator discriminator = entityBinding.getHierarchyDetails().getEntityDiscriminator();
final Element discriminatorElement = classMapping.addElement( "discriminator" );
// Database column or SQL formula allowed to distinguish entity types
MetadataTools.addColumnsOrFormulas(
discriminatorElement,
Collections.singletonList( discriminator.getRelationalValue() )
);
discriminatorElement.addAttribute(
"type",
discriminator.getExplicitHibernateTypeDescriptor().getExplicitTypeName()
);
}
// Adding the "revision type" property
addRevisionType( classMapping, classMapping );
addRevisionType( classMapping, classMapping, false );
return Triple.make( classMapping, propertyMapper, null );
}
private Triple<Element, ExtendedPropertyMapper, String> generateInheritanceMappingData(
PersistentClass pc, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
EntityBinding entityBinding,
EntityXmlMappingData xmlMappingData,
AuditTableData auditTableData,
String inheritanceMappingType) {
final String extendsEntityName = verEntCfg.getAuditEntityName( pc.getSuperclass().getEntityName() );
final String parentEntityName = entityBinding.getSuperEntityBinding().getEntityName();
final String extendsEntityName = context.getAuditEntitiesConfiguration().getAuditEntityName( parentEntityName );
final Element classMapping = MetadataTools.createSubclassEntity(
xmlMappingData.getMainXmlMapping(),
inheritanceMappingType,
auditTableData,
extendsEntityName,
pc.getDiscriminatorValue(),
pc.isAbstract()
entityBinding.getDiscriminatorMatchValue(),
entityBinding.isAbstract()
);
// The id and revision type is already mapped in the parent
// Getting the property mapper of the parent - when mapping properties, they need to be included
final String parentEntityName = pc.getSuperclass().getEntityName();
final EntityConfiguration parentConfiguration = entitiesConfigurations.get( parentEntityName );
if ( parentConfiguration == null ) {
throw new MappingException(
"Entity '" + pc.getEntityName() + "' is audited, but its superclass: '" +
"Entity '" + entityBinding.getEntityName() + "' is audited, but its superclass: '" +
parentEntityName + "' is not."
);
}
@ -549,16 +607,16 @@ public final class AuditMetadataGenerator {
@SuppressWarnings({"unchecked"})
public void generateFirstPass(
PersistentClass pc,
EntityBinding entityBinding,
ClassAuditingData auditingData,
EntityXmlMappingData xmlMappingData,
boolean isAudited) {
final String schema = getSchema( auditingData.getAuditTable().schema(), pc.getTable() );
final String catalog = getCatalog( auditingData.getAuditTable().catalog(), pc.getTable() );
final String schema = getSchema( auditingData.getAuditTable().schema(), entityBinding.getPrimaryTable() );
final String catalog = getCatalog( auditingData.getAuditTable().catalog(), entityBinding.getPrimaryTable() );
if ( !isAudited ) {
final String entityName = pc.getEntityName();
final IdMappingData idMapper = idMetadataGenerator.addId( pc, false );
final String entityName = entityBinding.getEntityName();
final IdMappingData idMapper = idMetadataGenerator.addId( entityBinding, false );
if ( idMapper == null ) {
// Unsupported id mapping, e.g. key-many-to-one. If the entity is used in auditing, an exception
@ -574,7 +632,7 @@ public final class AuditMetadataGenerator {
final String parentEntityName = null;
final EntityConfiguration entityCfg = new EntityConfiguration(
entityName,
pc.getClassName(),
entityBinding.getEntity().getDescriptor().getName().fullName(),
idMapper,
propertyMapper,
parentEntityName
@ -583,11 +641,14 @@ public final class AuditMetadataGenerator {
return;
}
final String entityName = pc.getEntityName();
final String entityName = entityBinding.getEntityName();
LOG.debugf( "Generating first-pass auditing mapping for entity %s", entityName );
final String auditEntityName = verEntCfg.getAuditEntityName( entityName );
final String auditTableName = verEntCfg.getAuditTableName( entityName, pc.getTable().getName() );
final String auditEntityName = context.getAuditEntitiesConfiguration().getAuditEntityName( entityName );
final String auditTableName = context.getAuditEntitiesConfiguration().getAuditTableName(
entityName,
entityBinding.getPrimaryTableName()
);
// Registering the audit entity name, now that it is known
auditEntityNameRegister.register( auditEntityName );
@ -595,9 +656,9 @@ public final class AuditMetadataGenerator {
final AuditTableData auditTableData = new AuditTableData( auditEntityName, auditTableName, schema, catalog );
// Generating a mapping for the id
final IdMappingData idMapper = idMetadataGenerator.addId( pc, true );
final IdMappingData idMapper = idMetadataGenerator.addId( entityBinding, true );
final InheritanceType inheritanceType = InheritanceType.get( pc );
final InheritanceType inheritanceType = InheritanceType.get( entityBinding );
// These properties will be read from the mapping data
final Element classMapping;
@ -609,26 +670,26 @@ public final class AuditMetadataGenerator {
// Reading the mapping data depending on inheritance type (if any)
switch ( inheritanceType ) {
case NONE:
mappingData = generateMappingData( pc, xmlMappingData, auditTableData, idMapper );
mappingData = generateMappingData( entityBinding, xmlMappingData, auditTableData, idMapper );
break;
case SINGLE:
mappingData = generateInheritanceMappingData( pc, xmlMappingData, auditTableData, "subclass" );
mappingData = generateInheritanceMappingData( entityBinding, xmlMappingData, auditTableData, "subclass" );
break;
case JOINED:
mappingData = generateInheritanceMappingData( pc, xmlMappingData, auditTableData, "joined-subclass" );
mappingData = generateInheritanceMappingData( entityBinding, xmlMappingData, auditTableData, "joined-subclass" );
// Adding the "key" element with all id columns...
final Element keyMapping = mappingData.getFirst().addElement( "key" );
MetadataTools.addColumns( keyMapping, pc.getTable().getPrimaryKey().columnIterator() );
MetadataTools.addColumns( keyMapping, entityBinding.getPrimaryTable().getPrimaryKey().getColumns() );
// ... and the revision number column, read from the revision info relation mapping.
keyMapping.add( (Element) cloneAndSetupRevisionInfoRelationMapping().element( "column" ).clone() );
break;
case TABLE_PER_CLASS:
mappingData = generateInheritanceMappingData( pc, xmlMappingData, auditTableData, "union-subclass" );
mappingData = generateInheritanceMappingData( entityBinding, xmlMappingData, auditTableData, "union-subclass" );
break;
default:
@ -643,32 +704,38 @@ public final class AuditMetadataGenerator {
// Mapping unjoined properties
addProperties(
classMapping, pc.getUnjoinedPropertyIterator(), propertyMapper,
auditingData, pc.getEntityName(), xmlMappingData,
classMapping,
entityBinding.getNonIdAttributeBindingClosure(), // TODO: this needs to be corrected to only get non-joined attribute bindings.
//entityBinding.getUnjoinedPropertyIterator(),
propertyMapper,
auditingData,
entityBinding.getEntityName(),
xmlMappingData,
true
);
// TODO: add support for joins
// Creating and mapping joins (first pass)
createJoins( pc, classMapping, auditingData );
addJoins( pc, propertyMapper, auditingData, pc.getEntityName(), xmlMappingData, true );
//createJoins( entityBinding, classMapping, auditingData );
//addJoins( entityBinding, propertyMapper, auditingData, entityBinding.getEntityName(), xmlMappingData, true );
// Storing the generated configuration
final EntityConfiguration entityCfg = new EntityConfiguration(
auditEntityName,
pc.getClassName(),
entityBinding.getEntity().getDescriptor().getName().fullName(),
idMapper,
propertyMapper,
parentEntityName
);
entitiesConfigurations.put( pc.getEntityName(), entityCfg );
entitiesConfigurations.put( entityBinding.getEntityName(), entityCfg );
}
@SuppressWarnings({"unchecked"})
public void generateSecondPass(
PersistentClass pc,
EntityBinding entityBinding,
ClassAuditingData auditingData,
EntityXmlMappingData xmlMappingData) {
final String entityName = pc.getEntityName();
final String entityName = entityBinding.getEntityName();
LOG.debugf( "Generating second-pass auditing mapping for entity %s", entityName );
final CompositeMapperBuilder propertyMapper = entitiesConfigurations.get( entityName ).getPropertyMapper();
@ -678,7 +745,8 @@ public final class AuditMetadataGenerator {
addProperties(
parent,
pc.getUnjoinedPropertyIterator(),
entityBinding.getNonIdAttributeBindingClosure(), // TODO: this needs to be corrected to only get non-joined attribute bindings.
//entityBinding.getUnjoinedPropertyIterator(),
propertyMapper,
auditingData,
entityName,
@ -686,8 +754,9 @@ public final class AuditMetadataGenerator {
false
);
// TODO: add suuport for joins
// Mapping joins (second pass)
addJoins( pc, propertyMapper, auditingData, entityName, xmlMappingData, false );
//addJoins( entityBinding, propertyMapper, auditingData, entityName, xmlMappingData, false );
}
public Map<String, EntityConfiguration> getEntitiesConfigurations() {
@ -700,26 +769,10 @@ public final class AuditMetadataGenerator {
return basicMetadataGenerator;
}
Configuration getCfg() {
return cfg;
}
GlobalConfiguration getGlobalCfg() {
return globalCfg;
}
AuditEntitiesConfiguration getVerEntCfg() {
return verEntCfg;
}
AuditStrategy getAuditStrategy() {
return auditStrategy;
}
ClassLoaderService getClassLoaderService() {
return classLoaderService;
}
AuditEntityNameRegister getAuditEntityNameRegister() {
return auditEntityNameRegister;
}

View File

@ -23,16 +23,19 @@
*/
package org.hibernate.envers.configuration.internal.metadata;
import java.util.Properties;
import java.util.List;
import java.util.Map;
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor;
import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.EnumType;
import org.hibernate.type.SerializableToBlobType;
import org.hibernate.type.Type;
import org.hibernate.usertype.DynamicParameterizedType;
@ -46,18 +49,23 @@ import org.dom4j.Element;
public final class BasicMetadataGenerator {
@SuppressWarnings({"unchecked"})
boolean addBasic(
Element parent, PropertyAuditingData propertyAuditingData,
Value value, SimpleMapperBuilder mapper, boolean insertable, boolean key) {
final Type type = value.getType();
if ( type instanceof BasicType
|| type instanceof SerializableToBlobType
|| "org.hibernate.type.PrimitiveByteArrayBlobType".equals( type.getClass().getName() ) ) {
Element parent,
PropertyAuditingData propertyAuditingData,
HibernateTypeDescriptor hibernateTypeDescriptor,
List<Value> values,
boolean insertable,
SimpleMapperBuilder mapper,
boolean key) {
if ( hibernateTypeDescriptor.getResolvedTypeMapping() instanceof BasicType
|| "org.hibernate.type.PrimitiveByteArrayBlobType".equals(
hibernateTypeDescriptor.getJavaTypeDescriptor()
.getName()
.fullName()
) ) {
if ( parent != null ) {
final boolean addNestedType = (value instanceof SimpleValue)
&& ((SimpleValue) value).getTypeParameters() != null;
final boolean addNestedType = !hibernateTypeDescriptor.getTypeParameters().isEmpty();
final String typeName = resolveType( value );
final String typeName = resolveTypeName( hibernateTypeDescriptor );
final Element propMapping = MetadataTools.addProperty(
parent,
@ -66,22 +74,22 @@ public final class BasicMetadataGenerator {
propertyAuditingData.isForceInsertable() || insertable,
key
);
MetadataTools.addColumns( propMapping, value.getColumnIterator() );
MetadataTools.addValuesAsColumns( propMapping, values );
if ( addNestedType ) {
final Properties typeParameters = ((SimpleValue) value).getTypeParameters();
final Map<String, String> typeParameters = hibernateTypeDescriptor.getTypeParameters();
final Element typeMapping = propMapping.addElement( "type" );
typeMapping.addAttribute( "name", typeName );
if ( "org.hibernate.type.EnumType".equals( typeName ) ) {
// Proper handling of enumeration type
mapEnumerationType( typeMapping, type, typeParameters );
mapEnumerationType( typeMapping, hibernateTypeDescriptor.getResolvedTypeMapping(), typeParameters );
}
else {
// By default copying all Hibernate properties
for ( Object object : typeParameters.keySet() ) {
final String keyType = (String) object;
final String property = typeParameters.getProperty( keyType );
final String property = typeParameters.get( keyType );
if ( property != null ) {
typeMapping.addElement( "param" ).addAttribute( "name", keyType ).setText( property );
@ -103,26 +111,23 @@ public final class BasicMetadataGenerator {
return true;
}
private String resolveType(Value value) {
final Type type = value.getType();
String typeName = null;
if ( value instanceof SimpleValue ) {
typeName = ( (SimpleValue) value ).getTypeName();
}
private String resolveTypeName(HibernateTypeDescriptor hibernateTypeDescriptor) {
final Type type = hibernateTypeDescriptor.getResolvedTypeMapping();
String typeName = hibernateTypeDescriptor.getExplicitTypeName();
if ( typeName == null ) {
typeName = type.getName();
}
if ( typeName == null ) {
typeName = type.getClass().getName();
typeName = hibernateTypeDescriptor.getJavaTypeDescriptor().getName().fullName();
}
return typeName;
}
private void mapEnumerationType(Element parent, Type type, Properties parameters) {
if ( parameters.getProperty( EnumType.ENUM ) != null ) {
private void mapEnumerationType(Element parent, Type type, Map<String,String> parameters) {
if ( parameters.get( EnumType.ENUM ) != null ) {
parent.addElement( "param" )
.addAttribute( "name", EnumType.ENUM )
.setText( parameters.getProperty( EnumType.ENUM ) );
.setText( parameters.get( EnumType.ENUM ) );
}
else {
parent.addElement( "param" ).addAttribute( "name", EnumType.ENUM ).setText(
@ -130,9 +135,9 @@ public final class BasicMetadataGenerator {
.getName()
);
}
if ( parameters.getProperty( EnumType.NAMED ) != null ) {
if ( parameters.get( EnumType.NAMED ) != null ) {
parent.addElement( "param" ).addAttribute( "name", EnumType.NAMED ).setText(
parameters.getProperty(
parameters.get(
EnumType.NAMED
)
);
@ -151,15 +156,15 @@ public final class BasicMetadataGenerator {
boolean addManyToOne(
Element parent,
PropertyAuditingData propertyAuditingData,
Value value,
ManyToOneAttributeBinding attributeBinding,
SimpleMapperBuilder mapper) {
final Type type = value.getType();
final Type type = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
// A null mapper occurs when adding to composite-id element
final Element manyToOneElement = parent.addElement( mapper != null ? "many-to-one" : "key-many-to-one" );
manyToOneElement.addAttribute( "name", propertyAuditingData.getName() );
manyToOneElement.addAttribute( "class", type.getName() );
MetadataTools.addColumns( manyToOneElement, value.getColumnIterator() );
MetadataTools.addValuesAsColumns( manyToOneElement, attributeBinding.getValues() );
// A null mapper means that we only want to add xml mappings
if ( mapper != null ) {

View File

@ -26,7 +26,6 @@ package org.hibernate.envers.configuration.internal.metadata;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -34,14 +33,15 @@ import java.util.TreeMap;
import java.util.TreeSet;
import javax.persistence.JoinColumn;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.internal.metadata.reader.AuditedPropertiesReader;
import org.hibernate.envers.configuration.internal.metadata.reader.ComponentAuditedPropertiesReader;
import org.hibernate.envers.configuration.internal.metadata.reader.ComponentAuditingData;
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.envers.internal.EnversMessageLogger;
import org.hibernate.envers.internal.entities.EntityConfiguration;
import org.hibernate.envers.internal.entities.IdMappingData;
@ -78,17 +78,24 @@ import org.hibernate.envers.internal.tools.MappingTools;
import org.hibernate.envers.internal.tools.ReflectionTools;
import org.hibernate.envers.internal.tools.StringTools;
import org.hibernate.envers.internal.tools.Tools;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBindingContainer;
import org.hibernate.metamodel.spi.binding.CompositePluralAttributeElementBinding;
import org.hibernate.metamodel.spi.binding.CompositePluralAttributeIndexBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor;
import org.hibernate.metamodel.spi.binding.IndexedPluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeAssociationElementBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeIndexBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.domain.PluralAttribute;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.type.BagType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ListType;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.MapType;
@ -113,9 +120,10 @@ public final class CollectionMetadataGenerator {
CollectionMetadataGenerator.class.getName()
);
private final AuditConfiguration.AuditConfigurationContext context;
private final AuditMetadataGenerator mainGenerator;
private final String propertyName;
private final Collection propertyValue;
private final PluralAttributeBinding pluralAttributeBinding;
private final CompositeMapperBuilder currentMapper;
private final String referencingEntityName;
private final EntityXmlMappingData xmlMappingData;
@ -129,7 +137,7 @@ public final class CollectionMetadataGenerator {
/**
* @param mainGenerator Main generator, giving access to configuration and the basic mapper.
* @param propertyValue Value of the collection, as mapped by Hibernate.
* @param pluralAttributeBinding Value of the collection, as mapped by Hibernate.
* @param currentMapper Mapper, to which the appropriate {@link PropertyMapper} will be added.
* @param referencingEntityName Name of the entity that owns this collection.
* @param xmlMappingData In case this collection requires a middle table, additional mapping documents will
@ -139,12 +147,15 @@ public final class CollectionMetadataGenerator {
* table and the value of the <code>@MapKey</code> annotation, if there was one.
*/
public CollectionMetadataGenerator(
AuditConfiguration.AuditConfigurationContext context,
AuditMetadataGenerator mainGenerator,
Collection propertyValue, CompositeMapperBuilder currentMapper,
PluralAttributeBinding pluralAttributeBinding,
CompositeMapperBuilder currentMapper,
String referencingEntityName, EntityXmlMappingData xmlMappingData,
PropertyAuditingData propertyAuditingData) {
this.context = context;
this.mainGenerator = mainGenerator;
this.propertyValue = propertyValue;
this.pluralAttributeBinding = pluralAttributeBinding;
this.currentMapper = currentMapper;
this.referencingEntityName = referencingEntityName;
this.xmlMappingData = xmlMappingData;
@ -157,17 +168,24 @@ public final class CollectionMetadataGenerator {
throw new MappingException( "Unable to read auditing configuration for " + referencingEntityName + "!" );
}
referencedEntityName = MappingTools.getReferencedEntityName( propertyValue.getElement() );
referencedEntityName = MappingTools.getReferencedEntityName( pluralAttributeBinding );
}
void addCollection() {
final Type type = propertyValue.getType();
final Value value = propertyValue.getElement();
final Type type = pluralAttributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
final PluralAttributeElementBinding.Nature elementNature =
pluralAttributeBinding.getPluralAttributeElementBinding().getNature();
final boolean oneToManyAttachedType = type instanceof BagType || type instanceof SetType || type instanceof MapType || type instanceof ListType;
final boolean inverseOneToMany = (value instanceof OneToMany) && (propertyValue.isInverse());
final boolean owningManyToOneWithJoinTableBidirectional = (value instanceof ManyToOne) && (propertyAuditingData.getRelationMappedBy() != null);
final boolean fakeOneToManyBidirectional = (value instanceof OneToMany) && (propertyAuditingData.getAuditMappedBy() != null);
final boolean inverseOneToMany =
(elementNature == PluralAttributeElementBinding.Nature.ONE_TO_MANY) &&
( pluralAttributeBinding.getPluralAttributeKeyBinding().isInverse() );
final boolean owningManyToOneWithJoinTableBidirectional =
(elementNature == PluralAttributeAssociationElementBinding.Nature.MANY_TO_MANY) &&
(propertyAuditingData.getRelationMappedBy() != null);
final boolean fakeOneToManyBidirectional =
(elementNature == PluralAttributeElementBinding.Nature.ONE_TO_MANY)
&& (propertyAuditingData.getAuditMappedBy() != null);
if ( oneToManyAttachedType && (inverseOneToMany || fakeOneToManyBidirectional || owningManyToOneWithJoinTableBidirectional) ) {
// A one-to-many relation mapped using @ManyToOne and @OneToMany(mappedBy="...")
@ -181,7 +199,7 @@ public final class CollectionMetadataGenerator {
private MiddleIdData createMiddleIdData(IdMappingData idMappingData, String prefix, String entityName) {
return new MiddleIdData(
mainGenerator.getVerEntCfg(), idMappingData, prefix, entityName,
context.getAuditEntitiesConfiguration(), idMappingData, prefix, entityName,
mainGenerator.getEntitiesConfigurations().containsKey( entityName )
);
}
@ -194,7 +212,9 @@ public final class CollectionMetadataGenerator {
propertyName
);
final String mappedBy = getMappedBy( propertyValue );
final String mappedBy = getMappedBy(
(PluralAttributeAssociationElementBinding) pluralAttributeBinding.getPluralAttributeElementBinding()
);
final IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(
referencingEntityName,
@ -230,8 +250,8 @@ public final class CollectionMetadataGenerator {
// Generating the query generator - it should read directly from the related entity.
final RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator(
mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(),
context.getGlobalConfiguration(),
context.getAuditEntitiesConfiguration(),
mainGenerator.getAuditStrategy(),
referencingIdData,
referencedEntityName,
@ -241,7 +261,7 @@ public final class CollectionMetadataGenerator {
// Creating common mapper data.
final CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(), referencedEntityName,
context.getAuditEntitiesConfiguration(), referencedEntityName,
propertyAuditingData.getPropertyData(),
referencingIdData, queryGenerator
);
@ -327,19 +347,19 @@ public final class CollectionMetadataGenerator {
}
}
private String getMiddleTableName(Collection value, String entityName) {
private String getMiddleTableName(PluralAttributeBinding attributeBinding, String entityName) {
// We check how Hibernate maps the collection.
if ( value.getElement() instanceof OneToMany && !value.isInverse() ) {
if ( attributeBinding.getPluralAttributeElementBinding().getNature() ==
PluralAttributeElementBinding.Nature.ONE_TO_MANY &&
!attributeBinding.getPluralAttributeKeyBinding().isInverse() ) {
// This must be a @JoinColumn+@OneToMany mapping. Generating the table name, as Hibernate doesn't use a
// middle table for mapping this relation.
return StringTools.getLastComponent( entityName ) + "_" + StringTools.getLastComponent(
MappingTools.getReferencedEntityName(
value.getElement()
)
MappingTools.getReferencedEntityName( attributeBinding )
);
}
// Hibernate uses a middle table for mapping this relation, so we get it's name directly.
return value.getCollectionTable().getName();
return attributeBinding.getPluralAttributeKeyBinding().getCollectionTable().getLogicalName().getName();
}
@SuppressWarnings({"unchecked"})
@ -359,9 +379,9 @@ public final class CollectionMetadataGenerator {
auditMiddleEntityName = propertyAuditingData.getJoinTable().name();
}
else {
final String middleTableName = getMiddleTableName( propertyValue, referencingEntityName );
auditMiddleTableName = mainGenerator.getVerEntCfg().getAuditTableName( null, middleTableName );
auditMiddleEntityName = mainGenerator.getVerEntCfg().getAuditEntityName( middleTableName );
final String middleTableName = getMiddleTableName( pluralAttributeBinding, referencingEntityName );
auditMiddleTableName = context.getAuditEntitiesConfiguration().getAuditTableName( null, middleTableName );
auditMiddleEntityName = context.getAuditEntitiesConfiguration().getAuditEntityName( middleTableName );
}
LOG.debugf( "Using join table name: %s", auditMiddleTableName );
@ -369,7 +389,7 @@ public final class CollectionMetadataGenerator {
// Generating the XML mapping for the middle entity, only if the relation isn't inverse.
// If the relation is inverse, will be later checked by comparing middleEntityXml with null.
Element middleEntityXml;
if ( !propertyValue.isInverse() ) {
if ( !pluralAttributeBinding.getPluralAttributeKeyBinding().isInverse() ) {
// Generating a unique middle entity name
auditMiddleEntityName = mainGenerator.getAuditEntityNameRegister().createUnique( auditMiddleEntityName );
@ -379,7 +399,7 @@ public final class CollectionMetadataGenerator {
middleEntityXml = createMiddleEntityXml(
auditMiddleTableName,
auditMiddleEntityName,
propertyValue.getWhere()
pluralAttributeBinding.getWhere()
);
}
else {
@ -399,11 +419,11 @@ public final class CollectionMetadataGenerator {
String referencingPrefixRelated;
String referencedPrefix;
if ( propertyValue.isInverse() ) {
if ( pluralAttributeBinding.getPluralAttributeKeyBinding().isInverse() ) {
// If the relation is inverse, then referencedEntityName is not null.
mappedBy = getMappedBy(
propertyValue.getCollectionTable(),
mainGenerator.getCfg().getClassMapping( referencedEntityName )
pluralAttributeBinding.getPluralAttributeKeyBinding().getCollectionTable(),
context.getEntityBinding( referencedEntityName )
);
referencingPrefixRelated = mappedBy + "_";
@ -427,8 +447,8 @@ public final class CollectionMetadataGenerator {
// references some entities (either from the element or index). At the end, this will be used to build
// a query generator to read the raw data collection from the middle table.
final QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(
mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(),
context.getGlobalConfiguration(),
context.getAuditEntitiesConfiguration(),
mainGenerator.getAuditStrategy(),
referencingIdData,
auditMiddleEntityName,
@ -440,7 +460,9 @@ public final class CollectionMetadataGenerator {
// Adding related-entity (in this case: the referencing's entity id) id mapping to the xml.
addRelatedToXmlMapping(
middleEntityXml, referencingPrefixRelated,
MetadataTools.getColumnNameIterator( propertyValue.getKey().getColumnIterator() ),
MetadataTools.getColumnNameIterator(
pluralAttributeBinding.getPluralAttributeKeyBinding().getValues().iterator()
),
referencingIdMapping
);
}
@ -449,11 +471,11 @@ public final class CollectionMetadataGenerator {
// Generating the element mapping.
// ******
final MiddleComponentData elementComponentData = addValueToMiddleTable(
propertyValue.getElement(),
middleEntityXml,
queryGeneratorBuilder,
referencedPrefix,
propertyAuditingData.getJoinTable().inverseJoinColumns()
propertyAuditingData.getJoinTable().inverseJoinColumns(),
false
);
// ******
@ -469,7 +491,7 @@ public final class CollectionMetadataGenerator {
// Creating common data
final CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(),
context.getAuditEntitiesConfiguration(),
auditMiddleEntityName,
propertyAuditingData.getPropertyData(),
referencingIdData,
@ -486,17 +508,18 @@ public final class CollectionMetadataGenerator {
}
private MiddleComponentData addIndex(Element middleEntityXml, QueryGeneratorBuilder queryGeneratorBuilder) {
if ( propertyValue instanceof IndexedCollection ) {
final IndexedCollection indexedValue = (IndexedCollection) propertyValue;
if ( pluralAttributeBinding.getAttribute().getNature().isIndexable() ) {
final PluralAttributeIndexBinding indexBinding =
( (IndexedPluralAttributeBinding) pluralAttributeBinding ).getPluralAttributeIndexBinding();
final 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,
queryGeneratorBuilder,
"mapkey",
null
null,
true
);
}
else {
@ -507,7 +530,7 @@ public final class CollectionMetadataGenerator {
// The key of the map is the id of the entity.
return new MiddleComponentData(
new MiddleMapKeyIdComponentMapper(
mainGenerator.getVerEntCfg(),
context.getAuditEntitiesConfiguration(),
referencedIdMapping.getIdMapper()
),
currentIndex
@ -531,29 +554,46 @@ public final class CollectionMetadataGenerator {
}
}
private PluralAttributeIndexBinding getPluralAttributeIndexBinding() {
if ( !pluralAttributeBinding.getAttribute().getNature().isIndexable() ) {
throw new AssertionFailure( "This method is only valid for an indexed plural attribute binding." );
}
return ( (IndexedPluralAttributeBinding) pluralAttributeBinding ).getPluralAttributeIndexBinding();
}
/**
* @param value Value, which should be mapped to the middle-table, either as a relation to another entity,
* or as a simple value.
* @param xmlMapping If not <code>null</code>, xml mapping for this value is added to this element.
* @param queryGeneratorBuilder In case <code>value</code> is a relation to another entity, information about it
* should be added to the given.
* @param prefix Prefix for proeprty names of related entities identifiers.
* @param joinColumns Names of columns to use in the xml mapping, if this array isn't null and has any elements.
* @param isIndex true, if the value is for the collection index; false, if the value is for the collection element.
*
* @return Data for mapping this component.
*/
@SuppressWarnings({"unchecked"})
private MiddleComponentData addValueToMiddleTable(
Value value,
Element xmlMapping,
QueryGeneratorBuilder queryGeneratorBuilder,
String prefix,
JoinColumn[] joinColumns) {
final Type type = value.getType();
if ( type instanceof ManyToOneType ) {
JoinColumn[] joinColumns,
boolean isIndex) {
final HibernateTypeDescriptor hibernateTypeDescriptor;
final List<Value> values;
if ( isIndex ) {
hibernateTypeDescriptor = getPluralAttributeIndexBinding().getHibernateTypeDescriptor();
values = getPluralAttributeIndexBinding().getValues();
}
else {
hibernateTypeDescriptor = pluralAttributeBinding.getPluralAttributeElementBinding().getHibernateTypeDescriptor();
values = pluralAttributeBinding.getPluralAttributeElementBinding().getValues();
} ;
if ( hibernateTypeDescriptor.getResolvedTypeMapping() instanceof ManyToOneType ) {
final String prefixRelated = prefix + "_";
final String referencedEntityName = MappingTools.getReferencedEntityName( value );
final String referencedEntityName = MappingTools.getReferencedEntityName( pluralAttributeBinding );
final IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(
referencingEntityName,
@ -569,7 +609,7 @@ public final class CollectionMetadataGenerator {
xmlMapping, prefixRelated,
joinColumns != null && joinColumns.length > 0
? MetadataTools.getColumnNameIterator( joinColumns )
: MetadataTools.getColumnNameIterator( value.getColumnIterator() ),
: MetadataTools.getColumnNameIterator( values.iterator() ),
referencedIdMapping
);
}
@ -588,12 +628,20 @@ public final class CollectionMetadataGenerator {
queryGeneratorBuilder.getCurrentIndex()
);
}
else if ( type instanceof ComponentType ) {
else if ( hibernateTypeDescriptor.getResolvedTypeMapping() instanceof ComponentType ) {
final CompositeAttributeBindingContainer compositeAttributeBindingContainer;
if ( isIndex ) {
compositeAttributeBindingContainer =
( ( CompositePluralAttributeIndexBinding ) getPluralAttributeIndexBinding() ).getCompositeAttributeBindingContainer();
}
else {
compositeAttributeBindingContainer =
( (CompositePluralAttributeElementBinding) pluralAttributeBinding.getPluralAttributeElementBinding() ).getCompositeAttributeBindingContainer();
}
// Collection of embeddable elements.
final Component component = (Component) value;
final Class componentClass = ReflectionTools.loadClass(
component.getComponentClassName(),
mainGenerator.getClassLoaderService()
hibernateTypeDescriptor.getJavaTypeDescriptor().getName().fullName(),
context.getClassLoaderService()
);
final MiddleEmbeddableComponentMapper componentMapper = new MiddleEmbeddableComponentMapper(
new MultiPropertyMapper(),
@ -602,12 +650,15 @@ public final class CollectionMetadataGenerator {
final Element parentXmlMapping = xmlMapping.getParent();
final ComponentAuditingData auditData = new ComponentAuditingData();
final ReflectionManager reflectionManager = mainGenerator.getCfg().getReflectionManager();
new ComponentAuditedPropertiesReader(
ModificationStore.FULL,
new AuditedPropertiesReader.ComponentPropertiesSource( reflectionManager, component ),
auditData, mainGenerator.getGlobalCfg(), reflectionManager, ""
context,
auditData,
new AuditedPropertiesReader.ComponentPropertiesSource(
context.getClassInfo( compositeAttributeBindingContainer.getAttributeContainer() ),
compositeAttributeBindingContainer
),
""
).read();
// Emulating first pass.
@ -615,12 +666,11 @@ public final class CollectionMetadataGenerator {
final PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData( auditedPropertyName );
mainGenerator.addValue(
parentXmlMapping,
component.getProperty( auditedPropertyName ).getValue(),
compositeAttributeBindingContainer.locateAttributeBinding( auditedPropertyName ),
componentMapper,
prefix, xmlMappingData,
nestedAuditingData,
true,
true,
true
);
}
@ -630,12 +680,11 @@ public final class CollectionMetadataGenerator {
final PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData( auditedPropertyName );
mainGenerator.addValue(
parentXmlMapping,
component.getProperty( auditedPropertyName ).getValue(),
compositeAttributeBindingContainer.locateAttributeBinding( auditedPropertyName ),
componentMapper,
referencingEntityName,
xmlMappingData,
nestedAuditingData,
true,
false,
true
);
@ -643,8 +692,8 @@ public final class CollectionMetadataGenerator {
// Add an additional column holding a number to make each entry unique within the set.
// Embeddable properties may contain null values, so cannot be stored within composite primary key.
if ( propertyValue.isSet() ) {
final String setOrdinalPropertyName = mainGenerator.getVerEntCfg()
if ( ( pluralAttributeBinding.getAttribute() ).getNature() == PluralAttribute.Nature.SET ) {
final String setOrdinalPropertyName = context.getAuditEntitiesConfiguration()
.getEmbeddableSetOrdinalPropertyName();
final Element ordinalProperty = MetadataTools.addProperty(
xmlMapping, setOrdinalPropertyName, "integer", true, true
@ -669,21 +718,24 @@ public final class CollectionMetadataGenerator {
null,
false
),
value,
hibernateTypeDescriptor,
values,
true, // TODO: is this correct for collection element?
null,
true,
true
);
if ( mapped ) {
// Simple values are always stored in the first item of the array returned by the query generator.
return new MiddleComponentData(
new MiddleSimpleComponentMapper( mainGenerator.getVerEntCfg(), prefix ),
new MiddleSimpleComponentMapper( context.getAuditEntitiesConfiguration(), prefix ),
0
);
}
else {
mainGenerator.throwUnsupportedTypeException( type, referencingEntityName, propertyName );
mainGenerator.throwUnsupportedTypeException(
hibernateTypeDescriptor.getResolvedTypeMapping(), referencingEntityName, propertyName
);
// Impossible to get here.
throw new AssertionError();
}
@ -694,7 +746,7 @@ public final class CollectionMetadataGenerator {
CommonCollectionMapperData commonCollectionMapperData,
MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) {
final Type type = propertyValue.getType();
final Type type = pluralAttributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
final boolean embeddableElementType = isEmbeddableElementType();
if ( type instanceof SortedSetType ) {
currentMapper.addComposite(
@ -704,7 +756,7 @@ public final class CollectionMetadataGenerator {
TreeSet.class,
SortedSetProxy.class,
elementComponentData,
propertyValue.getComparator(),
pluralAttributeBinding.getComparator(),
embeddableElementType,
embeddableElementType
)
@ -733,7 +785,7 @@ public final class CollectionMetadataGenerator {
SortedMapProxy.class,
elementComponentData,
indexComponentData,
propertyValue.getComparator(),
pluralAttributeBinding.getComparator(),
embeddableElementType
)
);
@ -785,7 +837,7 @@ public final class CollectionMetadataGenerator {
private void storeMiddleEntityRelationInformation(String mappedBy) {
// Only if this is a relation (when there is a referenced entity).
if ( referencedEntityName != null ) {
if ( propertyValue.isInverse() ) {
if ( pluralAttributeBinding.getPluralAttributeKeyBinding().isInverse() ) {
referencingEntityConfiguration.addToManyMiddleNotOwningRelation(
propertyName,
mappedBy,
@ -801,11 +853,11 @@ public final class CollectionMetadataGenerator {
private Element createMiddleEntityXml(String auditMiddleTableName, String auditMiddleEntityName, String where) {
final String schema = mainGenerator.getSchema(
propertyAuditingData.getJoinTable().schema(),
propertyValue.getCollectionTable()
pluralAttributeBinding.getPluralAttributeKeyBinding().getCollectionTable()
);
final String catalog = mainGenerator.getCatalog(
propertyAuditingData.getJoinTable().catalog(),
propertyValue.getCollectionTable()
pluralAttributeBinding.getPluralAttributeKeyBinding().getCollectionTable()
);
final Element middleEntityXml = MetadataTools.createEntity(
@ -819,7 +871,7 @@ public final class CollectionMetadataGenerator {
middleEntityXml.addAttribute( "where", where );
}
middleEntityXmlId.addAttribute( "name", mainGenerator.getVerEntCfg().getOriginalIdPropName() );
middleEntityXmlId.addAttribute( "name", context.getAuditEntitiesConfiguration().getOriginalIdPropName() );
// Adding the revision number as a foreign key to the revision info entity to the composite id of the
// middle table.
@ -828,7 +880,8 @@ public final class CollectionMetadataGenerator {
// Adding the revision type property to the entity xml.
mainGenerator.addRevisionType(
isEmbeddableElementType() ? middleEntityXmlId : middleEntityXml,
middleEntityXml
middleEntityXml,
isEmbeddableElementType()
);
// All other properties should also be part of the primary key of the middle entity.
@ -839,20 +892,15 @@ public final class CollectionMetadataGenerator {
* Checks if the collection element is of {@link ComponentType} type.
*/
private boolean isEmbeddableElementType() {
return propertyValue.getElement().getType() instanceof ComponentType;
return pluralAttributeBinding.getPluralAttributeElementBinding()
.getHibernateTypeDescriptor().getResolvedTypeMapping().isComponentType();
}
private String getMappedBy(Collection collectionValue) {
PersistentClass referencedClass = null;
if ( collectionValue.getElement() instanceof OneToMany ) {
final OneToMany oneToManyValue = (OneToMany) collectionValue.getElement();
referencedClass = oneToManyValue.getAssociatedClass();
}
else if ( collectionValue.getElement() instanceof ManyToOne ) {
// Case for bi-directional relation with @JoinTable on the owning @ManyToOne side.
final ManyToOne manyToOneValue = (ManyToOne) collectionValue.getElement();
referencedClass = manyToOneValue.getMappings().getClass( manyToOneValue.getReferencedEntityName() );
}
private String getMappedBy(PluralAttributeAssociationElementBinding elementBinding) {
EntityBinding referencedEntityBinding = null;
final EntityType entityType =
(EntityType) elementBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
referencedEntityBinding = context.getEntityBinding( entityType.getAssociatedEntityName() );
// If there's an @AuditMappedBy specified, returning it directly.
final String auditMappedBy = propertyAuditingData.getAuditMappedBy();
@ -861,27 +909,30 @@ public final class CollectionMetadataGenerator {
}
// searching in referenced class
String mappedBy = this.searchMappedBy( referencedClass, collectionValue );
String mappedBy = this.searchMappedBy( referencedEntityBinding );
if ( mappedBy == null ) {
LOG.debugf(
"Going to search the mapped by attribute for %s in superclasses of entity: %s",
propertyName,
referencedClass.getClassName()
referencedEntityBinding.getEntityName()
);
PersistentClass tempClass = referencedClass;
while ( (mappedBy == null) && (tempClass.getSuperclass() != null) ) {
LOG.debugf( "Searching in superclass: %s", tempClass.getSuperclass().getClassName() );
mappedBy = this.searchMappedBy( tempClass.getSuperclass(), collectionValue );
tempClass = tempClass.getSuperclass();
EntityBinding tempEntityBinding = referencedEntityBinding;
while ( (mappedBy == null) && (tempEntityBinding.getSuperEntityBinding() != null) ) {
LOG.debugf(
"Searching in superclass: %s",
tempEntityBinding.getSuperEntityBinding().getEntity().getDescriptor().getName()
);
mappedBy = this.searchMappedBy( tempEntityBinding.getSuperEntityBinding() );
tempEntityBinding = tempEntityBinding.getSuperEntityBinding();
}
}
if ( mappedBy == null ) {
throw new MappingException(
"Unable to read the mapped by attribute for " + propertyName + " in "
+ referencedClass.getClassName() + "!"
+ referencedEntityBinding.getEntity().getDescriptor().getName() + "!"
);
}
@ -889,22 +940,30 @@ public final class CollectionMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
private String searchMappedBy(PersistentClass referencedClass, Collection collectionValue) {
final Iterator<Property> assocClassProps = referencedClass.getPropertyIterator();
while ( assocClassProps.hasNext() ) {
final Property property = assocClassProps.next();
private String searchMappedBy(EntityBinding referencedEntityBinding) {
for ( AttributeBinding attributeBinding : referencedEntityBinding.attributeBindings() ) {
if ( !attributeBinding.isAssociation() ) {
continue;
}
final List<Value> attributeValues;
if ( attributeBinding.getAttribute().isSingular() ) {
attributeValues = ( (SingularAttributeBinding) attributeBinding ).getValues();
}
else {
attributeValues = ( (PluralAttributeBinding) attributeBinding ).getPluralAttributeElementBinding().getValues();
}
if ( Tools.iteratorsContentEqual(
property.getValue().getColumnIterator(),
collectionValue.getKey().getColumnIterator()
attributeValues.iterator(),
pluralAttributeBinding.getPluralAttributeKeyBinding().getValues().iterator()
) ) {
return property.getName();
return attributeBinding.getAttribute().getName();
}
}
return null;
}
private String getMappedBy(Table collectionTable, PersistentClass referencedClass) {
private String getMappedBy(TableSpecification collectionTable, EntityBinding referencedClass) {
// If there's an @AuditMappedBy specified, returning it directly.
final String auditMappedBy = propertyAuditingData.getAuditMappedBy();
if ( auditMappedBy != null ) {
@ -919,21 +978,24 @@ public final class CollectionMetadataGenerator {
LOG.debugf(
"Going to search the mapped by attribute for %s in superclasses of entity: %s",
propertyName,
referencedClass.getClassName()
referencedClass.getEntity().getDescriptor().getName()
);
PersistentClass tempClass = referencedClass;
while ( (mappedBy == null) && (tempClass.getSuperclass() != null) ) {
LOG.debugf( "Searching in superclass: %s", tempClass.getSuperclass().getClassName() );
mappedBy = this.searchMappedBy( tempClass.getSuperclass(), collectionTable );
tempClass = tempClass.getSuperclass();
EntityBinding tempClass = referencedClass;
while ( (mappedBy == null) && (tempClass.getSuperEntityBinding() != null) ) {
LOG.debugf(
"Searching in superclass: %s",
tempClass.getSuperEntityBinding().getEntity().getDescriptor().getName()
);
mappedBy = this.searchMappedBy( tempClass.getSuperEntityBinding(), collectionTable );
tempClass = tempClass.getSuperEntityBinding();
}
}
if ( mappedBy == null ) {
throw new MappingException(
"Unable to read the mapped by attribute for " + propertyName + " in "
+ referencedClass.getClassName() + "!"
+ referencedClass.getEntity().getDescriptor().getName() + "!"
);
}
@ -941,15 +1003,14 @@ public final class CollectionMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
private String searchMappedBy(PersistentClass referencedClass, Table collectionTable) {
final Iterator<Property> properties = referencedClass.getPropertyIterator();
while ( properties.hasNext() ) {
final Property property = properties.next();
if ( property.getValue() instanceof Collection ) {
private String searchMappedBy(EntityBinding referencedClass, TableSpecification collectionTable) {
for ( AttributeBinding attributeBinding : referencedClass.attributeBindings() ) {
if ( !attributeBinding.getAttribute().isSingular() ) {
// The equality is intentional. We want to find a collection property with the same collection table.
//noinspection ObjectEquality
if ( ((Collection) property.getValue()).getCollectionTable() == collectionTable ) {
return property.getName();
if ( ((PluralAttributeBinding) attributeBinding ).getPluralAttributeKeyBinding().getCollectionTable() ==
collectionTable ) {
return attributeBinding.getAttribute().getName();
}
}
}

View File

@ -23,16 +23,16 @@
*/
package org.hibernate.envers.configuration.internal.metadata;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.EntityMode;
import org.hibernate.envers.configuration.internal.metadata.reader.ComponentAuditingData;
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.envers.internal.entities.mapper.CompositeMapperBuilder;
import org.hibernate.envers.internal.tools.ReflectionTools;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.dom4j.Element;
@ -43,29 +43,29 @@ import org.dom4j.Element;
* @author Lukasz Zuchowski (author at zuchos dot com)
*/
public final class ComponentMetadataGenerator {
private final AuditMetadataGenerator mainGenerator;
private final AuditConfiguration.AuditConfigurationContext context;
ComponentMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
private final AuditMetadataGenerator mainGenerator;
ComponentMetadataGenerator(AuditConfiguration.AuditConfigurationContext context, AuditMetadataGenerator auditMetadataGenerator) {
this.context = context;
mainGenerator = auditMetadataGenerator;
}
@SuppressWarnings({"unchecked"})
public void addComponent(
Element parent, PropertyAuditingData propertyAuditingData,
Value value, CompositeMapperBuilder mapper, String entityName,
CompositeAttributeBinding compositeAttributeBinding, CompositeMapperBuilder mapper, String entityName,
EntityXmlMappingData xmlMappingData, boolean firstPass) {
final Component propComponent = (Component) value;
final Class componentClass;
if (propComponent.isDynamic()) {
componentClass = ReflectionTools.loadClass(
Map.class.getCanonicalName(),
mainGenerator.getClassLoaderService());
final EntityMode entityMode = compositeAttributeBinding.seekEntityBinding().getHierarchyDetails().getEntityMode();
if ( entityMode == EntityMode.MAP ) {
componentClass = context.getClassLoaderService().classForName( Map.class.getCanonicalName() );
} else {
componentClass = ReflectionTools.loadClass(
propComponent.getComponentClassName(),
mainGenerator.getClassLoaderService()
// TODO: get rid of classloading.
componentClass = context.getClassLoaderService().classForName(
compositeAttributeBinding.getHibernateTypeDescriptor().getJavaTypeDescriptor().getName().fullName()
);
}
final CompositeMapperBuilder componentMapper = mapper.addComponent(
@ -77,18 +77,16 @@ public final class ComponentMetadataGenerator {
final ComponentAuditingData componentAuditingData = (ComponentAuditingData) propertyAuditingData;
// Adding all properties of the component
final Iterator<Property> properties = (Iterator<Property>) propComponent.getPropertyIterator();
while (properties.hasNext()) {
final Property property = properties.next();
for ( AttributeBinding attributeBinding : compositeAttributeBinding.attributeBindings() ) {
final PropertyAuditingData componentPropertyAuditingData =
componentAuditingData.getPropertyAuditingData(property.getName());
componentAuditingData.getPropertyAuditingData( attributeBinding.getAttribute().getName() );
// Checking if that property is audited
if (componentPropertyAuditingData != null) {
mainGenerator.addValue(
parent, property.getValue(), componentMapper, entityName, xmlMappingData,
componentPropertyAuditingData, property.isInsertable(), firstPass, false
parent, attributeBinding, componentMapper, entityName, xmlMappingData,
componentPropertyAuditingData, firstPass, false
);
}
}

View File

@ -23,12 +23,11 @@
*/
package org.hibernate.envers.configuration.internal.metadata;
import java.util.Iterator;
import org.hibernate.MappingException;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.envers.internal.entities.IdMappingData;
import org.hibernate.envers.internal.entities.PropertyData;
import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
@ -36,10 +35,14 @@ import org.hibernate.envers.internal.entities.mapper.id.EmbeddedIdMapper;
import org.hibernate.envers.internal.entities.mapper.id.MultipleIdMapper;
import org.hibernate.envers.internal.entities.mapper.id.SimpleIdMapperBuilder;
import org.hibernate.envers.internal.entities.mapper.id.SingleIdMapper;
import org.hibernate.envers.internal.tools.ReflectionTools;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.id.EntityIdentifierNature;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.EntityIdentifier;
import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularNonAssociationAttributeBinding;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.Type;
@ -52,53 +55,57 @@ import org.dom4j.tree.DefaultElement;
* @author Adam Warski (adam at warski dot org)
*/
public final class IdMetadataGenerator {
private final AuditConfiguration.AuditConfigurationContext context;
private final AuditMetadataGenerator mainGenerator;
IdMetadataGenerator(AuditMetadataGenerator auditMetadataGenerator) {
IdMetadataGenerator(AuditConfiguration.AuditConfigurationContext context, AuditMetadataGenerator auditMetadataGenerator) {
this.context = context;
mainGenerator = auditMetadataGenerator;
}
@SuppressWarnings({"unchecked"})
private boolean addIdProperties(
Element parent,
Iterator<Property> properties,
CompositeAttributeBinding compositeAttributeBinding,
SimpleMapperBuilder mapper,
boolean key,
boolean audited) {
while ( properties.hasNext() ) {
final Property property = properties.next();
final Type propertyType = property.getType();
if ( !"_identifierMapper".equals( property.getName() ) ) {
boolean added = false;
if ( propertyType instanceof ManyToOneType ) {
added = mainGenerator.getBasicMetadataGenerator().addManyToOne(
parent,
getIdPersistentPropertyAuditingData( property ),
property.getValue(),
mapper
);
//if ( compositeAttributeBinding.getAttribute().isSynthetic() ) {
// return true;
//}
for ( AttributeBinding attributeBinding : compositeAttributeBinding.attributeBindings() ) {
final Type propertyType = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
final boolean added;
if ( propertyType instanceof ManyToOneType ) {
added = mainGenerator.getBasicMetadataGenerator().addManyToOne(
parent,
getIdPersistentPropertyAuditingData( attributeBinding ),
(ManyToOneAttributeBinding) attributeBinding,
mapper
);
}
else {
final SingularAttributeBinding singularAttributeBinding = (SingularAttributeBinding) attributeBinding;
// Last but one parameter: ids are always insertable
added = mainGenerator.getBasicMetadataGenerator().addBasic(
parent,
getIdPersistentPropertyAuditingData( singularAttributeBinding ),
singularAttributeBinding.getHibernateTypeDescriptor(),
singularAttributeBinding.getValues(),
singularAttributeBinding.isIncludedInInsert(),
mapper,
key
);
}
if ( !added ) {
// If the entity is audited, and a non-supported id component is used, throwing an exception.
// If the entity is not audited, then we simply don't support this entity, even in
// target relation mode not audited.
if ( audited ) {
throw new MappingException( "Type not supported: " + propertyType.getClass().getName() );
}
else {
// Last but one parameter: ids are always insertable
added = mainGenerator.getBasicMetadataGenerator().addBasic(
parent,
getIdPersistentPropertyAuditingData( property ),
property.getValue(),
mapper,
true,
key
);
}
if ( !added ) {
// If the entity is audited, and a non-supported id component is used, throwing an exception.
// If the entity is not audited, then we simply don't support this entity, even in
// target relation mode not audited.
if ( audited ) {
throw new MappingException( "Type not supported: " + propertyType.getClass().getName() );
}
else {
return false;
}
return false;
}
}
}
@ -107,31 +114,30 @@ public final class IdMetadataGenerator {
}
@SuppressWarnings({"unchecked"})
IdMappingData addId(PersistentClass pc, boolean audited) {
IdMappingData addId(EntityBinding entityBinding, boolean audited) {
// Xml mapping which will be used for relations
final Element relIdMapping = new DefaultElement( "properties" );
// Xml mapping which will be used for the primary key of the versions table
final Element origIdMapping = new DefaultElement( "composite-id" );
final Property idProp = pc.getIdentifierProperty();
final Component idMapper = pc.getIdentifierMapper();
//final Property idProp = pc.getIdentifierProperty();
//final Component idMapper = pc.getIdentifierMapper();
// Checking if the id mapping is supported
if ( idMapper == null && idProp == null ) {
return null;
}
//if ( idMapper == null && idProp == null ) {
// return null;
//}
final EntityIdentifier entityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier();
SimpleIdMapperBuilder mapper;
if ( idMapper != null ) {
if ( entityIdentifier.getLookupClassBinding().definedIdClass() ) {
// Multiple id
final Class componentClass = ReflectionTools.loadClass(
( (Component) pc.getIdentifier() ).getComponentClassName(),
mainGenerator.getClassLoaderService()
);
final Class componentClass = entityIdentifier.getLookupClassBinding().getIdClassType();
mapper = new MultipleIdMapper( componentClass );
if ( !addIdProperties(
relIdMapping,
(Iterator<Property>) idMapper.getPropertyIterator(),
(CompositeAttributeBinding) entityIdentifier.getAttributeBinding(),
mapper,
false,
audited
@ -142,7 +148,7 @@ public final class IdMetadataGenerator {
// null mapper - the mapping where already added the first time, now we only want to generate the xml
if ( !addIdProperties(
origIdMapping,
(Iterator<Property>) idMapper.getPropertyIterator(),
(CompositeAttributeBinding) entityIdentifier.getAttributeBinding(),
null,
true,
audited
@ -150,17 +156,16 @@ public final class IdMetadataGenerator {
return null;
}
}
else if ( idProp.isComposite() ) {
// Embedded id
final Component idComponent = (Component) idProp.getValue();
final Class embeddableClass = ReflectionTools.loadClass(
idComponent.getComponentClassName(),
mainGenerator.getClassLoaderService()
else if ( entityIdentifier.getNature() == EntityIdentifierNature.AGGREGATED_COMPOSITE ) {
// Embeddable id
// TODO: get rid of classloading.
final Class embeddableClass = context.getClassLoaderService().classForName(
entityIdentifier.getAttributeBinding().getHibernateTypeDescriptor().getJavaTypeDescriptor().getName().fullName()
);
mapper = new EmbeddedIdMapper( getIdPropertyData( idProp ), embeddableClass );
mapper = new EmbeddedIdMapper( getIdPropertyData( entityIdentifier.getAttributeBinding() ), embeddableClass );
if ( !addIdProperties(
relIdMapping,
(Iterator<Property>) idComponent.getPropertyIterator(),
(CompositeAttributeBinding) entityIdentifier.getAttributeBinding(),
mapper,
false,
audited
@ -171,7 +176,7 @@ public final class IdMetadataGenerator {
// null mapper - the mapping where already added the first time, now we only want to generate the xml
if ( !addIdProperties(
origIdMapping,
(Iterator<Property>) idComponent.getPropertyIterator(),
(CompositeAttributeBinding) entityIdentifier.getAttributeBinding(),
null,
true,
audited
@ -186,25 +191,27 @@ public final class IdMetadataGenerator {
// Last but one parameter: ids are always insertable
mainGenerator.getBasicMetadataGenerator().addBasic(
relIdMapping,
getIdPersistentPropertyAuditingData( idProp ),
idProp.getValue(),
getIdPersistentPropertyAuditingData( entityIdentifier.getAttributeBinding() ),
entityIdentifier.getAttributeBinding().getHibernateTypeDescriptor(),
entityIdentifier.getAttributeBinding().getValues(),
entityIdentifier.getAttributeBinding().isIncludedInInsert(),
mapper,
true,
false
);
// null mapper - the mapping where already added the first time, now we only want to generate the xml
mainGenerator.getBasicMetadataGenerator().addBasic(
origIdMapping,
getIdPersistentPropertyAuditingData( idProp ),
idProp.getValue(),
getIdPersistentPropertyAuditingData( entityIdentifier.getAttributeBinding() ),
entityIdentifier.getAttributeBinding().getHibernateTypeDescriptor(),
entityIdentifier.getAttributeBinding().getValues(),
entityIdentifier.getAttributeBinding().isIncludedInInsert(),
null,
true,
true
);
}
origIdMapping.addAttribute( "name", mainGenerator.getVerEntCfg().getOriginalIdPropName() );
origIdMapping.addAttribute( "name", context.getAuditEntitiesConfiguration().getOriginalIdPropName() );
// Adding a relation to the revision entity (effectively: the "revision number" property)
mainGenerator.addRevisionInfoRelation( origIdMapping );
@ -212,16 +219,18 @@ public final class IdMetadataGenerator {
return new IdMappingData( mapper, origIdMapping, relIdMapping );
}
private PropertyData getIdPropertyData(Property property) {
private PropertyData getIdPropertyData(SingularNonAssociationAttributeBinding idAttributeBinding) {
return new PropertyData(
property.getName(), property.getName(), property.getPropertyAccessorName(),
idAttributeBinding.getAttribute().getName(),
idAttributeBinding.getAttribute().getName(),
idAttributeBinding.getPropertyAccessorName(),
ModificationStore.FULL
);
}
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
private PropertyAuditingData getIdPersistentPropertyAuditingData(AttributeBinding property) {
return new PropertyAuditingData(
property.getName(), property.getPropertyAccessorName(),
property.getAttribute().getName(), property.getPropertyAccessorName(),
ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false
);
}

View File

@ -24,11 +24,7 @@
package org.hibernate.envers.configuration.internal.metadata;
import org.hibernate.MappingException;
import org.hibernate.mapping.JoinedSubclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.SingleTableSubclass;
import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.UnionSubclass;
import org.hibernate.metamodel.spi.binding.EntityBinding;
/**
* @author Adam Warski (adam at warski dot org)
@ -40,30 +36,30 @@ public enum InheritanceType {
TABLE_PER_CLASS;
/**
* @param pc The class for which to get the inheritance type.
* @param entityBinding The class for which to get the inheritance type.
*
* @return The inheritance type of this class. NONE, if this class does not inherit from
* another persistent class.
*/
public static InheritanceType get(PersistentClass pc) {
final PersistentClass superclass = pc.getSuperclass();
if ( superclass == null ) {
public static InheritanceType get(EntityBinding entityBinding) {
final EntityBinding superEntityBinding = entityBinding.getSuperEntityBinding();
if ( superEntityBinding == null ) {
return InheritanceType.NONE;
}
// We assume that every subclass is of the same type.
final Subclass subclass = (Subclass) superclass.getSubclassIterator().next();
final EntityBinding subEntityBinding = superEntityBinding.getDirectSubEntityBindings().get( 0 );
if ( subclass instanceof SingleTableSubclass ) {
if ( subEntityBinding.getHierarchyDetails().getInheritanceType() == org.hibernate.metamodel.spi.binding.InheritanceType.SINGLE_TABLE ) {
return InheritanceType.SINGLE;
}
else if ( subclass instanceof JoinedSubclass ) {
else if ( subEntityBinding.getHierarchyDetails().getInheritanceType() == org.hibernate.metamodel.spi.binding.InheritanceType.JOINED ) {
return InheritanceType.JOINED;
}
else if ( subclass instanceof UnionSubclass ) {
else if ( subEntityBinding.getHierarchyDetails().getInheritanceType() == org.hibernate.metamodel.spi.binding.InheritanceType.TABLE_PER_CLASS ) {
return InheritanceType.TABLE_PER_CLASS;
}
throw new MappingException( "Unknown subclass class: " + subclass.getClass() );
throw new MappingException( "Unknown subclass class: " + subEntityBinding.getClass() );
}
}

View File

@ -24,12 +24,14 @@
package org.hibernate.envers.configuration.internal.metadata;
import java.util.Iterator;
import java.util.List;
import javax.persistence.JoinColumn;
import org.hibernate.AssertionFailure;
import org.hibernate.envers.internal.tools.StringTools;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.Selectable;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.relational.Value;
import org.dom4j.Attribute;
import org.dom4j.Document;
@ -46,9 +48,11 @@ public final class MetadataTools {
public static Element addNativelyGeneratedId(
Element parent, String name, String type,
boolean useRevisionEntityWithNativeId) {
boolean useRevisionEntityWithNativeId,
String idColumnName) {
final Element idMapping = parent.addElement( "id" );
idMapping.addAttribute( "name", name ).addAttribute( "type", type );
MetadataTools.addColumn( idMapping, idColumnName, null, null, null, null, null, null, false );
final Element generatorMapping = idMapping.addElement( "generator" );
if ( useRevisionEntityWithNativeId ) {
@ -87,9 +91,11 @@ public final class MetadataTools {
}
propMapping.addAttribute( "name", name );
propMapping.addAttribute( "insert", Boolean.toString( insertable ) );
propMapping.addAttribute( "update", Boolean.toString( updateable ) );
if ( !key ) {
propMapping.addAttribute( "insert", Boolean.toString( insertable ) );
propMapping.addAttribute( "update", Boolean.toString( updateable ) );
}
if ( type != null ) {
propMapping.addAttribute( "type", type );
}
@ -151,7 +157,7 @@ public final class MetadataTools {
public static Element addColumn(
Element parent,
String name,
Integer length,
Long length,
Integer scale,
Integer precision,
String sqlType,
@ -163,7 +169,7 @@ public final class MetadataTools {
public static Element addColumn(
Element parent,
String name,
Integer length,
Long length,
Integer scale,
Integer precision,
String sqlType,
@ -215,16 +221,18 @@ public final class MetadataTools {
classMapping.addAttribute( "discriminator-value", discriminatorValue );
}
if ( !StringTools.isEmpty( auditTableData.getAuditTableName() ) ) {
classMapping.addAttribute( "table", auditTableData.getAuditTableName() );
}
if ( !"subclass".equals( type ) ) {
if ( !StringTools.isEmpty( auditTableData.getAuditTableName() ) ) {
classMapping.addAttribute( "table", auditTableData.getAuditTableName() );
}
if ( !StringTools.isEmpty( auditTableData.getSchema() ) ) {
classMapping.addAttribute( "schema", auditTableData.getSchema() );
}
if ( !StringTools.isEmpty( auditTableData.getSchema() ) ) {
classMapping.addAttribute( "schema", auditTableData.getSchema() );
}
if ( !StringTools.isEmpty( auditTableData.getCatalog() ) ) {
classMapping.addAttribute( "catalog", auditTableData.getCatalog() );
if ( !StringTools.isEmpty( auditTableData.getCatalog() ) ) {
classMapping.addAttribute( "catalog", auditTableData.getCatalog() );
}
}
if ( isAbstract != null ) {
@ -282,13 +290,18 @@ public final class MetadataTools {
return joinMapping;
}
public static void addColumns(Element anyMapping, Iterator selectables) {
while ( selectables.hasNext() ) {
final Selectable selectable = (Selectable) selectables.next();
if ( selectable.isFormula() ) {
public static void addColumns(Element anyMapping, List<Column> columns) {
for ( Column column : columns ) {
addColumn( anyMapping, column );
}
}
public static void addValuesAsColumns(Element anyMapping, List<Value> values) {
for ( Value value : values ) {
if ( Value.ValueType.DERIVED_VALUE.equals( value.getValueType() ) ) {
throw new FormulaNotSupportedException();
}
addColumn( anyMapping, (Column) selectable );
addColumn( anyMapping, (Column) value );
}
}
@ -303,14 +316,14 @@ public final class MetadataTools {
public static void addColumn(Element anyMapping, Column column) {
addColumn(
anyMapping,
column.getName(),
column.getLength(),
column.getScale(),
column.getPrecision(),
column.getColumnName().getText(),
column.getSize().getLength(),
column.getSize().getScale(),
column.getSize().getPrecision(),
column.getSqlType(),
column.getCustomRead(),
column.getCustomWrite(),
column.isQuoted()
column.getReadFragment(),
column.getWriteFragment(),
column.getColumnName().isQuoted()
);
}
@ -350,9 +363,11 @@ public final class MetadataTools {
if ( changeToKey ) {
property.setName( "key-" + property.getName() );
// "insert" and "update" attributes are not allowed on key-many-to-one or key-property elements.
property.remove( property.attribute( "insert" ) );
property.remove( property.attribute( "update" ) );
}
if ( "property".equals( property.getName() ) ) {
else if ( "property".equals( property.getName() ) ) {
final Attribute insert = property.attribute( "insert" );
insert.setText( Boolean.toString( insertable ) );
}
@ -366,25 +381,28 @@ public final class MetadataTools {
* @param element Parent element.
* @param formula Formula descriptor.
*/
public static void addFormula(Element element, Formula formula) {
element.addElement( "formula" ).setText( formula.getText() );
public static void addFormula(Element element, DerivedValue formula) {
element.addElement( "formula" ).setText( formula.getExpression() );
}
/**
* Adds all <code>column</code> or <code>formula</code> elements.
*
* @param element Parent element.
* @param columnIterator Iterator pointing at {@link org.hibernate.mapping.Column} and/or
* {@link org.hibernate.mapping.Formula} objects.
* @param values List of {@link Column} and/or {@link DerivedValue} objects.
*/
public static void addColumnsOrFormulas(Element element, Iterator columnIterator) {
while ( columnIterator.hasNext() ) {
final Object o = columnIterator.next();
if ( o instanceof Column ) {
addColumn( element, (Column) o );
public static void addColumnsOrFormulas(Element element, List<Value> values) {
for ( Value value : values ) {
if ( value.getValueType() == Value.ValueType.COLUMN ) {
addColumn( element, (Column) value );
}
else if ( o instanceof Formula ) {
addFormula( element, (Formula) o );
else if ( value.getValueType() == Value.ValueType.DERIVED_VALUE ) {
addFormula( element, (DerivedValue) value );
}
else {
throw new AssertionFailure(
String.format( "unknown type of value: %s", value.getValueType() )
);
}
}
}
@ -395,18 +413,18 @@ public final class MetadataTools {
public static abstract class ColumnNameIterator implements Iterator<String> {
}
public static ColumnNameIterator getColumnNameIterator(final Iterator<Selectable> selectableIterator) {
public static ColumnNameIterator getColumnNameIterator(final Iterator<Value> selectableIterator) {
return new ColumnNameIterator() {
public boolean hasNext() {
return selectableIterator.hasNext();
}
public String next() {
final Selectable next = selectableIterator.next();
if ( next.isFormula() ) {
final Value next = selectableIterator.next();
if ( next.getValueType() == Value.ValueType.DERIVED_VALUE ) {
throw new FormulaNotSupportedException();
}
return ((Column) next).getName();
return ((Column) next).getColumnName().getText();
}
public void remove() {

View File

@ -37,6 +37,9 @@ import org.hibernate.envers.internal.tools.MappingTools;
import org.hibernate.mapping.OneToOne;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.internal.source.annotations.attribute.SingularAssociationAttribute;
import org.hibernate.metamodel.spi.binding.OneToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding;
import org.dom4j.Element;
@ -57,11 +60,10 @@ public final class ToOneRelationMetadataGenerator {
void addToOne(
Element parent,
PropertyAuditingData propertyAuditingData,
Value value,
SingularAssociationAttributeBinding attributeBinding,
CompositeMapperBuilder mapper,
String entityName,
boolean insertable) {
final String referencedEntityName = ((ToOne) value).getReferencedEntityName();
String entityName) {
final String referencedEntityName = attributeBinding.getReferencedEntityName();
final IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(
entityName,
@ -76,9 +78,10 @@ public final class ToOneRelationMetadataGenerator {
final IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
// Storing information about this relation
boolean insertable = attributeBinding.isIncludedInInsert();
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
propertyAuditingData.getName(), referencedEntityName, relMapper,
insertable, MappingTools.ignoreNotFound( value )
insertable, MappingTools.ignoreNotFound( attributeBinding )
);
// If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
@ -104,7 +107,7 @@ public final class ToOneRelationMetadataGenerator {
MetadataTools.prefixNamesInPropertyElement(
properties,
lastPropertyPrefix,
MetadataTools.getColumnNameIterator( value.getColumnIterator() ),
MetadataTools.getColumnNameIterator( attributeBinding.getValues().iterator() ),
false,
insertable
);
@ -127,11 +130,11 @@ public final class ToOneRelationMetadataGenerator {
@SuppressWarnings({"unchecked"})
void addOneToOneNotOwning(
PropertyAuditingData propertyAuditingData,
Value value,
OneToOneAttributeBinding attributeBinding,
CompositeMapperBuilder mapper,
String entityName) {
final OneToOne propertyValue = (OneToOne) value;
final String owningReferencePropertyName = propertyValue.getReferencedPropertyName();
final String owningReferencePropertyName =
attributeBinding.getReferencedAttributeBinding().getAttribute().getName();
final EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get( entityName );
if ( configuration == null ) {
@ -145,7 +148,7 @@ public final class ToOneRelationMetadataGenerator {
}
final String lastPropertyPrefix = MappingTools.createToOneRelationPrefix( owningReferencePropertyName );
final String referencedEntityName = propertyValue.getReferencedEntityName();
final String referencedEntityName = attributeBinding.getReferencedEntityName();
// Generating the id mapper for the relation
final IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties( lastPropertyPrefix );
@ -153,7 +156,7 @@ public final class ToOneRelationMetadataGenerator {
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneNotOwningRelation(
propertyAuditingData.getName(), owningReferencePropertyName, referencedEntityName,
ownedIdMapper, MappingTools.ignoreNotFound( value )
ownedIdMapper, MappingTools.ignoreNotFound( attributeBinding )
);
// Adding mapper for the id
@ -167,11 +170,10 @@ public final class ToOneRelationMetadataGenerator {
@SuppressWarnings({"unchecked"})
void addOneToOnePrimaryKeyJoinColumn(
PropertyAuditingData propertyAuditingData,
Value value,
OneToOneAttributeBinding attributeBinding,
CompositeMapperBuilder mapper,
String entityName,
boolean insertable) {
final String referencedEntityName = ((ToOne) value).getReferencedEntityName();
String entityName) {
final String referencedEntityName = attributeBinding.getReferencedEntityName();
final IdMappingData idMapping = mainGenerator.getReferencedIdMappingData(
entityName,
@ -187,8 +189,8 @@ public final class ToOneRelationMetadataGenerator {
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
propertyAuditingData.getName(), referencedEntityName, relMapper, insertable,
MappingTools.ignoreNotFound( value )
propertyAuditingData.getName(), referencedEntityName, relMapper, attributeBinding.isIncludedInInsert(),
MappingTools.ignoreNotFound( attributeBinding )
);
// Adding mapper for the id

View File

@ -24,19 +24,18 @@
package org.hibernate.envers.configuration.internal.metadata.reader;
import java.lang.annotation.Annotation;
import java.util.Iterator;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.hibernate.envers.AuditTable;
import org.hibernate.envers.Audited;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.SecondaryAuditTable;
import org.hibernate.envers.SecondaryAuditTables;
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.envers.event.spi.EnversDotNames;
import org.hibernate.metamodel.source.internal.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
import org.hibernate.metamodel.spi.binding.EntityBinding;
/**
* A helper class to read versioning meta-data from annotations on a persistent class.
@ -45,101 +44,8 @@ import org.hibernate.mapping.Property;
* @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) {
final Audited defaultAudited = clazz.getAnnotation( Audited.class );
if ( defaultAudited != null ) {
return defaultAudited.modStore();
}
else {
return null;
}
}
private void addAuditTable(XClass clazz) {
final 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
final SecondaryAuditTable secondaryVersionsTable1 = clazz.getAnnotation( SecondaryAuditTable.class );
if ( secondaryVersionsTable1 != null ) {
auditData.getSecondaryTableDictionary().put(
secondaryVersionsTable1.secondaryTableName(),
secondaryVersionsTable1.secondaryAuditTableName()
);
}
final 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 {
final XClass xclass = reflectionManager.classForName( pc.getClassName(), this.getClass() );
final ModificationStore defaultStore = getDefaultAudited( xclass );
if ( defaultStore != null ) {
auditData.setDefaultAudited( true );
}
new AuditedPropertiesReader(
defaultStore,
new PersistentClassPropertiesSource( xclass ),
auditData,
globalCfg,
reflectionManager,
""
).read();
addAuditTable( xclass );
addAuditSecondaryTables( xclass );
}
catch (ClassNotFoundException e) {
throw new MappingException( e );
}
return auditData;
}
private AuditTable defaultAuditTable = new AuditTable() {
private static final AuditTable DEFAULT_AUDIT_TABLE = new AuditTable() {
public String value() {
return "";
}
@ -157,28 +63,136 @@ public final class AnnotationsMetadataReader {
}
};
private final AuditConfiguration.AuditConfigurationContext context;
public AnnotationsMetadataReader(AuditConfiguration.AuditConfigurationContext context) {
this.context = context;
}
private ModificationStore getDefaultAudited(ClassInfo classInfo) {
final AnnotationInstance audited = JandexHelper.getSingleAnnotation(
classInfo.annotations(),
EnversDotNames.AUDITED,
classInfo
);
if ( audited != null ) {
return JandexHelper.getValue( audited, "modStore", ModificationStore.class, context.getClassLoaderService() );
}
return null;
}
private void addAuditTable(ClassInfo classInfo, ClassAuditingData auditData) {
final AnnotationInstance auditTable = JandexHelper.getSingleAnnotation( classInfo, EnversDotNames.AUDIT_TABLE );
if ( auditTable != null ) {
auditData.setAuditTable(
context.getAnnotationProxy(
auditTable,
AuditTable.class
)
);
}
else {
auditData.setAuditTable( getDefaultAuditTable() );
}
}
private void addAuditSecondaryTables(ClassInfo classInfo, ClassAuditingData auditData) {
// Getting information on secondary tables
final AnnotationInstance secondaryAuditTable1 = JandexHelper.getSingleAnnotation(
classInfo, EnversDotNames.SECONDARY_AUDIT_TABLE
);
if ( secondaryAuditTable1 != null ) {
auditData.getSecondaryTableDictionary().put(
JandexHelper.getValue(
secondaryAuditTable1, "secondaryTableName", String.class, context.getClassLoaderService()
),
JandexHelper.getValue(
secondaryAuditTable1, "secondaryAuditTableName", String.class, context.getClassLoaderService()
)
);
}
final AnnotationInstance secondaryAuditTables = JandexHelper.getSingleAnnotation( classInfo, EnversDotNames.SECONDARY_AUDIT_TABLES );
if ( secondaryAuditTables != null ) {
final AnnotationInstance[] secondaryAuditTableValues =
JandexHelper.getValue( secondaryAuditTables, "value", AnnotationInstance[].class, context.getClassLoaderService() );
for ( AnnotationInstance secondaryAuditTable : secondaryAuditTableValues ) {
auditData.getSecondaryTableDictionary().put(
JandexHelper.getValue(
secondaryAuditTable, "secondaryTableName", String.class, context.getClassLoaderService()
),
JandexHelper.getValue(
secondaryAuditTable, "secondaryAuditTableName", String.class, context.getClassLoaderService()
)
);
}
}
}
public ClassAuditingData getAuditData(EntityBinding entityBinding) {
/**
* This object is filled with information read from annotations and returned by the <code>getVersioningData</code>
* method.
*/
final ClassAuditingData auditData = new ClassAuditingData();
if ( entityBinding.getEntity().getDescriptor() == null ) {
// TODO: What is the case here? Test by throwing exception.
return auditData;
}
final PersistentClassPropertiesSource persistentClassPropertiesSource = new PersistentClassPropertiesSource(
entityBinding,
context.getClassInfo(
entityBinding.getEntity().getDescriptor().getName().toString()
)
);
ModificationStore defaultStore = getDefaultAudited( persistentClassPropertiesSource.getClassInfo() );
auditData.setDefaultAudited( defaultStore != null );
new AuditedPropertiesReader(
context,
auditData,
persistentClassPropertiesSource,
""
).read();
addAuditTable( persistentClassPropertiesSource.getClassInfo(), auditData );
addAuditSecondaryTables( persistentClassPropertiesSource.getClassInfo(), auditData );
return auditData;
}
private AuditTable getDefaultAuditTable() {
return defaultAuditTable;
return DEFAULT_AUDIT_TABLE;
}
private class PersistentClassPropertiesSource implements PersistentPropertiesSource {
private final XClass xclass;
private final EntityBinding entityBinding;
private final ClassInfo classInfo;
private PersistentClassPropertiesSource(XClass xclass) {
this.xclass = xclass;
private PersistentClassPropertiesSource(EntityBinding entityBinding, ClassInfo classInfo) {
this.entityBinding = entityBinding;
this.classInfo = classInfo;
}
@SuppressWarnings({"unchecked"})
public Iterator<Property> getPropertyIterator() {
return pc.getPropertyIterator();
public Iterable<AttributeBinding> getNonIdAttributeBindings() {
return entityBinding.getNonIdAttributeBindings();
}
public Property getProperty(String propertyName) {
return pc.getProperty( propertyName );
public AttributeBinding getAttributeBinding(String attributeName) {
return entityBinding.locateAttributeBinding( attributeName );
}
public XClass getXClass() {
return xclass;
@Override
public AttributeBindingContainer getAttributeBindingContainer() {
return entityBinding;
}
public ClassInfo getClassInfo() {
return classInfo;
}
}
}

View File

@ -25,6 +25,8 @@ package org.hibernate.envers.configuration.internal.metadata.reader;
import java.util.Map;
import org.jboss.jandex.AnnotationInstance;
import org.hibernate.envers.AuditTable;
import static org.hibernate.envers.internal.tools.Tools.newHashMap;

View File

@ -23,11 +23,17 @@
*/
package org.hibernate.envers.configuration.internal.metadata.reader;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XProperty;
import java.util.List;
import java.util.Map;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.DotName;
import org.hibernate.envers.Audited;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.envers.event.spi.EnversDotNames;
import org.hibernate.metamodel.spi.domain.Attribute;
/**
* Reads the audited properties for components.
@ -38,25 +44,29 @@ import org.hibernate.envers.configuration.internal.GlobalConfiguration;
public class ComponentAuditedPropertiesReader extends AuditedPropertiesReader {
public ComponentAuditedPropertiesReader(
ModificationStore defaultStore,
PersistentPropertiesSource persistentPropertiesSource,
AuditConfiguration.AuditConfigurationContext context,
AuditedPropertiesHolder auditedPropertiesHolder,
GlobalConfiguration globalCfg, ReflectionManager reflectionManager,
PersistentPropertiesSource persistentPropertiesSource,
String propertyNamePrefix) {
super(
defaultStore, persistentPropertiesSource, auditedPropertiesHolder,
globalCfg, reflectionManager, propertyNamePrefix
context, auditedPropertiesHolder, persistentPropertiesSource, propertyNamePrefix
);
}
@Override
protected boolean checkAudited(
XProperty property,
Attribute attribute,
PropertyAuditingData propertyData,
Audited allClassAudited) {
// Checking if this property is explicitly audited or if all properties are.
final Audited aud = property.getAnnotation( Audited.class );
if ( aud != null ) {
final Map<DotName, List<AnnotationInstance>> attributeAnnotations =
getContext().locateAttributeAnnotations( attribute );
// Checking if this property is explicitly audited or if all properties are.
if ( attributeAnnotations.containsKey( EnversDotNames.AUDITED ) ) {
final Audited aud = getContext().getAnnotationProxy(
attributeAnnotations.get( EnversDotNames.AUDITED ).get( 0 ),
Audited.class
);
propertyData.setStore( aud.modStore() );
propertyData.setRelationTargetAuditMode( aud.targetAuditMode() );
propertyData.setUsingModifiedFlag( checkUsingModifiedFlag( aud ) );

View File

@ -1,102 +0,0 @@
package org.hibernate.envers.configuration.internal.metadata.reader;
import java.lang.annotation.Annotation;
import java.util.Collection;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
/**
* This class prenteds to be property but in fact it represents entry in the map (for dynamic component)
*
* @author Lukasz Zuchowski (author at zuchos dot com)
*/
public class DynamicProperty implements XProperty {
private AuditedPropertiesReader.DynamicComponentSource source;
private String propertyName;
public DynamicProperty(AuditedPropertiesReader.DynamicComponentSource source, String propertyName) {
this.source = source;
this.propertyName = propertyName;
}
@Override
public XClass getDeclaringClass() {
return source.getXClass();
}
@Override
public String getName() {
return propertyName;
}
@Override
public boolean isCollection() {
return false;
}
@Override
public boolean isArray() {
return false;
}
@Override
public Class<? extends Collection> getCollectionClass() {
return null;
}
@Override
public XClass getType() {
return source.getXClass();
}
@Override
public XClass getElementClass() {
return null;
}
@Override
public XClass getClassOrElementClass() {
return null;
}
@Override
public XClass getMapKey() {
return null;
}
@Override
public int getModifiers() {
return 0;
}
@Override
public void setAccessible(boolean accessible) {
}
@Override
public Object invoke(Object target, Object... parameters) {
return null;
}
@Override
public boolean isTypeResolved() {
return false;
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return null;
}
@Override
public <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) {
return false;
}
@Override
public Annotation[] getAnnotations() {
return new Annotation[0];
}
}

View File

@ -24,9 +24,15 @@
package org.hibernate.envers.configuration.internal.metadata.reader;
import java.util.Iterator;
import java.util.List;
import org.jboss.jandex.ClassInfo;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
import org.hibernate.metamodel.spi.domain.AttributeContainer;
/**
* A source of data on persistent properties of a class or component.
@ -34,9 +40,11 @@ import org.hibernate.mapping.Property;
* @author Adam Warski (adam at warski dot org)
*/
public interface PersistentPropertiesSource {
Iterator<Property> getPropertyIterator();
Iterable<AttributeBinding> getNonIdAttributeBindings();
Property getProperty(String propertyName);
AttributeBinding getAttributeBinding(String attributeName);
XClass getXClass();
AttributeBindingContainer getAttributeBindingContainer();
ClassInfo getClassInfo();
}

View File

@ -24,18 +24,21 @@
package org.hibernate.envers.configuration.spi;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.WeakHashMap;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.Configuration;
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
import org.hibernate.envers.configuration.internal.EntitiesConfigurator;
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
import org.hibernate.envers.configuration.internal.RevisionInfoConfiguration;
import org.hibernate.envers.configuration.internal.RevisionInfoConfigurationResult;
import org.hibernate.envers.internal.entities.EntitiesConfigurations;
import org.hibernate.envers.internal.entities.PropertyData;
@ -46,8 +49,13 @@ import org.hibernate.envers.internal.synchronization.AuditProcessManager;
import org.hibernate.envers.internal.tools.ReflectionTools;
import org.hibernate.envers.strategy.AuditStrategy;
import org.hibernate.envers.strategy.ValidityAuditStrategy;
import org.hibernate.internal.util.ClassLoaderHelper;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.metamodel.Metadata;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.domain.Attribute;
import org.hibernate.metamodel.spi.domain.AttributeContainer;
import org.hibernate.property.Getter;
/**
@ -101,45 +109,37 @@ public class AuditConfiguration {
return classLoaderService;
}
public AuditConfiguration(Configuration cfg) {
this( cfg, null );
}
//public AuditConfiguration(Configuration cfg) {
// this( cfg, null );
//}
public AuditConfiguration(Configuration cfg, ClassLoaderService classLoaderService) {
// TODO: Temporarily allow Envers to continuing using
// hibernate-commons-annotations' for reflection and class loading.
final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader( ClassLoaderHelper.getContextClassLoader() );
public AuditConfiguration(AuditConfigurationContext context) {
this.globalCfg = context.getGlobalConfiguration();
this.auditEntCfg = context.getAuditEntitiesConfiguration();
final Properties properties = cfg.getProperties();
this.auditProcessManager = new AuditProcessManager( context.getRevisionInfoConfigurationResult().getRevisionInfoGenerator() );
this.revisionInfoQueryCreator = context.getRevisionInfoConfigurationResult().getRevisionInfoQueryCreator();
this.revisionInfoNumberReader = context.getRevisionInfoConfigurationResult().getRevisionInfoNumberReader();
this.modifiedEntityNamesReader = context.getRevisionInfoConfigurationResult().getModifiedEntityNamesReader();
final ReflectionManager reflectionManager = cfg.getReflectionManager();
this.globalCfg = new GlobalConfiguration( properties, classLoaderService );
final RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration( globalCfg );
final RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure( cfg, reflectionManager );
this.auditEntCfg = new AuditEntitiesConfiguration( properties, revInfoCfgResult.getRevisionInfoEntityName() );
this.auditProcessManager = new AuditProcessManager( revInfoCfgResult.getRevisionInfoGenerator() );
this.revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
this.revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
this.modifiedEntityNamesReader = revInfoCfgResult.getModifiedEntityNamesReader();
this.classLoaderService = classLoaderService;
this.auditStrategy = initializeAuditStrategy(
revInfoCfgResult.getRevisionInfoClass(),
revInfoCfgResult.getRevisionInfoTimestampData()
context.getRevisionInfoConfigurationResult().getRevisionInfoClass(),
context.getRevisionInfoConfigurationResult().getRevisionInfoTimestampData()
);
this.entCfg = new EntitiesConfigurator().configure(
cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy, classLoaderService,
revInfoCfgResult.getRevisionInfoXmlMapping(), revInfoCfgResult.getRevisionInfoRelationMapping()
context,
auditStrategy,
context.getRevisionInfoConfigurationResult().getRevisionInfoXmlMapping(),
context.getRevisionInfoConfigurationResult().getRevisionInfoRelationMapping()
);
Thread.currentThread().setContextClassLoader( tccl );
}
private AuditStrategy initializeAuditStrategy(Class<?> revisionInfoClass, PropertyData revisionInfoTimestampData) {
AuditStrategy strategy;
try {
Class<?> auditStrategyClass = null;
Class<?> auditStrategyClass;
try {
auditStrategyClass = this.getClass().getClassLoader().loadClass( auditEntCfg.getAuditStrategyName() );
}
@ -167,20 +167,19 @@ public class AuditConfiguration {
return strategy;
}
private static final Map<Configuration, AuditConfiguration> CFGS = new WeakHashMap<Configuration, AuditConfiguration>();
private static final Map<UUID, AuditConfiguration> CFGS = new WeakHashMap<UUID, AuditConfiguration>();
public synchronized static AuditConfiguration getFor(Configuration cfg) {
return getFor( cfg, null );
}
//public synchronized static AuditConfiguration register(MetadataImplementor metadata) {
// return register( metadata, null );
//}
public synchronized static AuditConfiguration getFor(Configuration cfg, ClassLoaderService classLoaderService) {
AuditConfiguration verCfg = CFGS.get( cfg );
public synchronized static AuditConfiguration register(
AuditConfigurationContext context, Metadata metadata) {
AuditConfiguration verCfg = CFGS.get( metadata.getUUID() );
if ( verCfg == null ) {
verCfg = new AuditConfiguration( cfg, classLoaderService );
CFGS.put( cfg, verCfg );
cfg.buildMappings();
verCfg = new AuditConfiguration( context );
CFGS.put( metadata.getUUID(), verCfg );
}
return verCfg;
@ -188,7 +187,7 @@ public class AuditConfiguration {
public void destroy() {
synchronized (AuditConfiguration.class) {
for ( Map.Entry<Configuration, AuditConfiguration> c : new HashSet<Map.Entry<Configuration, AuditConfiguration>>(
for ( Map.Entry<UUID, AuditConfiguration> c : new HashSet<Map.Entry<UUID, AuditConfiguration>>(
CFGS.entrySet() ) ) {
if ( c.getValue() == this ) { // this is nasty cleanup fix, whole static CFGS should be reworked
CFGS.remove( c.getKey() );
@ -197,4 +196,41 @@ public class AuditConfiguration {
}
classLoaderService = null;
}
public interface AuditConfigurationContext {
//InFlightMetadataCollector metadataCollector,
//AdditionalJaxbRootProducer.AdditionalJaxbRootProducerContext context,
//GlobalConfiguration globalCfg,
//AuditEntitiesConfiguration verEntCfg,
//AuditStrategy auditStrategy,
Metadata getMetadata();
EntityBinding getEntityBinding(String entityName);
EntityBinding getEntityBinding(ClassInfo classInfo);
IndexView getJandexIndex();
ClassInfo getClassInfo(String className);
ClassInfo getClassInfo(DotName classDotName);
ClassInfo getClassInfo(AttributeContainer attributeContainer);
ClassLoaderService getClassLoaderService();
<T> T getAnnotationProxy(AnnotationInstance annotationInstance, Class<T> annotationClass);
Map<DotName, List<AnnotationInstance>> locateAttributeAnnotations(Attribute attribute);
// return coreConfiguration.locateAttributeAnnotations;
GlobalConfiguration getGlobalConfiguration();
AuditEntitiesConfiguration getAuditEntitiesConfiguration();
public RevisionInfoConfigurationResult getRevisionInfoConfigurationResult();
void addDocument(org.w3c.dom.Document document);
}
}

View File

@ -25,11 +25,11 @@ package org.hibernate.envers.enhanced;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.MappedSuperclass;
import org.hibernate.annotations.Fetch;
@ -46,7 +46,7 @@ import org.hibernate.envers.ModifiedEntityNames;
@MappedSuperclass
public class SequenceIdTrackingModifiedEntitiesRevisionEntity extends SequenceIdRevisionEntity {
@ElementCollection(fetch = FetchType.EAGER)
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@CollectionTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME")
@Fetch(FetchMode.JOIN)
@ModifiedEntityNames

View File

@ -0,0 +1,36 @@
package org.hibernate.envers.event.spi;
import org.jboss.jandex.DotName;
import org.hibernate.envers.AuditJoinTable;
import org.hibernate.envers.AuditMappedBy;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.AuditOverrides;
import org.hibernate.envers.AuditTable;
import org.hibernate.envers.Audited;
import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.NotAudited;
import org.hibernate.envers.RevisionEntity;
import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp;
import org.hibernate.envers.SecondaryAuditTable;
import org.hibernate.envers.SecondaryAuditTables;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public interface EnversDotNames {
DotName AUDITED = DotName.createSimple( Audited.class.getName() );
DotName AUDIT_JOIN_TABLE = DotName.createSimple( AuditJoinTable.class.getName() );
DotName AUDIT_MAPPED_BY = DotName.createSimple( AuditMappedBy.class.getName() );
DotName AUDIT_OVERRIDE = DotName.createSimple( AuditOverride.class.getName() );
DotName AUDIT_OVERRIDES = DotName.createSimple( AuditOverrides.class.getName() );
DotName AUDIT_TABLE = DotName.createSimple( AuditTable.class.getName() );
DotName MODIFIED_ENTITY_NAMES = DotName.createSimple( ModifiedEntityNames.class.getName() );
DotName NOT_AUDITED = DotName.createSimple( NotAudited.class.getName() );
DotName REVISION_ENTITY = DotName.createSimple( RevisionEntity.class.getName() );
DotName REVISION_NUMBER = DotName.createSimple( RevisionNumber.class.getName() );
DotName REVISION_TIMESTAMP = DotName.createSimple( RevisionTimestamp.class.getName() );
DotName SECONDARY_AUDIT_TABLE = DotName.createSimple( SecondaryAuditTable.class.getName() );
DotName SECONDARY_AUDIT_TABLES = DotName.createSimple( SecondaryAuditTables.class.getName() );
}

View File

@ -23,8 +23,10 @@
*/
package org.hibernate.envers.event.spi;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.AssertionFailure;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.event.service.spi.EventListenerRegistry;
@ -73,11 +75,72 @@ public class EnversIntegrator implements Integrator {
final EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
listenerRegistry.addDuplicationStrategy( EnversListenerDuplicationStrategy.INSTANCE );
enversConfiguration = AuditConfiguration.getFor(
configuration,
serviceRegistry.getService(
ClassLoaderService.class
)
if ( enversConfiguration.getEntCfg().hasAuditedEntities() ) {
listenerRegistry.appendListeners(
EventType.POST_DELETE, new EnversPostDeleteEventListenerImpl(
enversConfiguration
)
);
listenerRegistry.appendListeners(
EventType.POST_INSERT, new EnversPostInsertEventListenerImpl(
enversConfiguration
)
);
listenerRegistry.appendListeners(
EventType.POST_UPDATE, new EnversPostUpdateEventListenerImpl(
enversConfiguration
)
);
listenerRegistry.appendListeners(
EventType.POST_COLLECTION_RECREATE,
new EnversPostCollectionRecreateEventListenerImpl( enversConfiguration )
);
listenerRegistry.appendListeners(
EventType.PRE_COLLECTION_REMOVE,
new EnversPreCollectionRemoveEventListenerImpl( enversConfiguration )
);
listenerRegistry.appendListeners(
EventType.PRE_COLLECTION_UPDATE,
new EnversPreCollectionUpdateEventListenerImpl( enversConfiguration )
);
throw new AssertionFailure( "No longer implemented." );
}
}
@Override
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
if ( enversConfiguration != null ) {
enversConfiguration.destroy();
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.spi.MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry)
*/
@Override
public void integrate(
MetadataImplementor metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
final ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class );
final boolean autoRegister = configurationService.getSetting(
AUTO_REGISTER,
StandardConverters.BOOLEAN,
true
);
if ( !autoRegister ) {
LOG.debug( "Skipping Envers listener auto registration" );
return;
}
final EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
listenerRegistry.addDuplicationStrategy( EnversListenerDuplicationStrategy.INSTANCE );
enversConfiguration = AuditConfiguration.register(
null,
metadata
);
if ( enversConfiguration.getEntCfg().hasAuditedEntities() ) {
@ -110,24 +173,4 @@ public class EnversIntegrator implements Integrator {
);
}
}
@Override
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
if ( enversConfiguration != null ) {
enversConfiguration.destroy();
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source.MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry)
*/
@Override
public void integrate(
MetadataImplementor metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// TODO: implement
}
}

View File

@ -0,0 +1,200 @@
package org.hibernate.envers.event.spi;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.jboss.logging.Logger;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.envers.configuration.internal.AnnotationProxyBuilder;
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
import org.hibernate.envers.configuration.internal.RevisionInfoConfiguration;
import org.hibernate.envers.configuration.internal.RevisionInfoConfigurationResult;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.Metadata;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.AdditionalJaxbRootProducer;
import org.hibernate.metamodel.spi.InFlightMetadataCollector;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.domain.Attribute;
import org.hibernate.metamodel.spi.domain.AttributeContainer;
import org.hibernate.xml.internal.jaxb.MappingXmlBinder;
import org.hibernate.xml.spi.BindResult;
import org.hibernate.xml.spi.Origin;
import org.hibernate.xml.spi.SourceType;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class EnversJaxbRootProducer implements AdditionalJaxbRootProducer {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
EnversJaxbRootProducer.class.getName()
);
@Override
public List<BindResult> produceRoots(
final InFlightMetadataCollector metadataCollector,
final AdditionalJaxbRootProducerContext additionalJaxbRootProducerContext) {
final AuditConfigurationContextImpl context = new AuditConfigurationContextImpl(
metadataCollector,
additionalJaxbRootProducerContext
);
final AuditConfiguration configuration = AuditConfiguration.register( context, metadataCollector);
return Collections.unmodifiableList( context.getBindResults() );
}
private class AuditConfigurationContextImpl implements AuditConfiguration.AuditConfigurationContext {
private final InFlightMetadataCollector metadataCollector;
private final AdditionalJaxbRootProducerContext additionalJaxbRootProducerContext;
private final AnnotationProxyBuilder annotationProxyBuilder = new AnnotationProxyBuilder();
private final MappingXmlBinder jaxbProcessor;
private final List<BindResult> bindResults = new ArrayList<BindResult>();
private final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH );
private final GlobalConfiguration globalCfg;
private final AuditEntitiesConfiguration auditEntCfg;
private final RevisionInfoConfigurationResult revInfoCfgResult;
AuditConfigurationContextImpl(
final InFlightMetadataCollector metadataCollector,
final AdditionalJaxbRootProducerContext additionalJaxbRootProducerContext) {
this.metadataCollector = metadataCollector;
this.additionalJaxbRootProducerContext = additionalJaxbRootProducerContext;
this.globalCfg = new GlobalConfiguration( additionalJaxbRootProducerContext.getServiceRegistry() );
final RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration( globalCfg );
this.revInfoCfgResult = revInfoCfg.configure( metadataCollector, additionalJaxbRootProducerContext );
this.auditEntCfg = new AuditEntitiesConfiguration( additionalJaxbRootProducerContext.getServiceRegistry(), revInfoCfgResult.getRevisionInfoEntityName() );
jaxbProcessor = new MappingXmlBinder(
additionalJaxbRootProducerContext.getServiceRegistry()
);
}
@Override
public Metadata getMetadata() {
return metadataCollector;
}
@Override
public EntityBinding getEntityBinding(String entityName) {
return metadataCollector.getEntityBinding( entityName );
}
@Override
public EntityBinding getEntityBinding(final ClassInfo clazz) {
// TODO: Is there a better way?
// final AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( clazz, JPADotNames.ENTITY );
// String entityName = JandexHelper.getValue( jpaEntityAnnotation, "name", String.class );
// if ( entityName == null ) {
// entityName = clazz.name().toString();
// }
return getEntityBinding( clazz.name().toString() );
}
@Override
public IndexView getJandexIndex() {
return additionalJaxbRootProducerContext.getJandexIndex();
}
@Override
public ClassInfo getClassInfo(AttributeContainer attributeContainer) {
return getClassInfo(
attributeContainer.getDescriptor().getName().fullName()
);
}
@Override
public ClassInfo getClassInfo(String className) {
return getClassInfo( DotName.createSimple( className ) );
}
@Override
public ClassInfo getClassInfo(DotName classDotName) {
return getJandexIndex().getClassByName( classDotName );
}
@Override
public ClassLoaderService getClassLoaderService() {
return additionalJaxbRootProducerContext.getServiceRegistry().getService( ClassLoaderService.class );
}
@Override
public <T> T getAnnotationProxy(AnnotationInstance annotationInstance, Class<T> annotationClass) {
return annotationProxyBuilder.getAnnotationProxy(
annotationInstance, annotationClass, getClassLoaderService()
);
}
@Override
public Map<DotName, List<AnnotationInstance>> locateAttributeAnnotations(final Attribute attribute) {
final ClassInfo classInfo = getClassInfo( attribute.getAttributeContainer() );
return JandexHelper.getMemberAnnotations(
classInfo,
attribute.getName(),
additionalJaxbRootProducerContext.getServiceRegistry()
);
}
@Override
public GlobalConfiguration getGlobalConfiguration() {
return globalCfg;
}
@Override
public AuditEntitiesConfiguration getAuditEntitiesConfiguration() {
return auditEntCfg;
}
@Override
public RevisionInfoConfigurationResult getRevisionInfoConfigurationResult() {
return revInfoCfgResult;
}
@Override
public void addDocument(org.w3c.dom.Document document) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource( document );
Result outputTarget = new StreamResult( outputStream );
try {
TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
}
catch ( TransformerConfigurationException ex ){
throw new MappingException( ex );
}
catch ( TransformerException ex ) {
throw new MappingException( ex );
}
InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
bindResults.add( jaxbProcessor.bind( is, origin ) );
}
private List<BindResult> getBindResults() {
return bindResults;
}
}
}

View File

@ -23,11 +23,14 @@
*/
package org.hibernate.envers.internal.tools;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeAssociationElementBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding;
import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.type.EntityType;
/**
* @author Adam Warski (adam at warski dot org)
@ -51,30 +54,43 @@ public abstract class MappingTools {
return referencePropertyName + "_";
}
public static String getReferencedEntityName(Value value) {
if ( value instanceof ToOne ) {
return ((ToOne) value).getReferencedEntityName();
public static String getReferencedEntityName(AttributeBinding attributeBinding) {
if ( attributeBinding.getAttribute().isSingular() ) {
final SingularAttributeBinding singularAttributeBinding = (SingularAssociationAttributeBinding) attributeBinding;
if ( singularAttributeBinding.isAssociation() ) {
return SingularAssociationAttributeBinding.class.cast( singularAttributeBinding ).getReferencedEntityName();
}
}
else if ( value instanceof OneToMany ) {
return ((OneToMany) value).getReferencedEntityName();
else {
final PluralAttributeBinding pluralAttributeBinding = (PluralAttributeBinding) attributeBinding;
if ( pluralAttributeBinding.getPluralAttributeElementBinding().getNature().isAssociation() ) {
final PluralAttributeAssociationElementBinding associationPluralAttributeElementBinding =
(PluralAttributeAssociationElementBinding) pluralAttributeBinding.getPluralAttributeElementBinding();
final EntityType entityType =
(EntityType) associationPluralAttributeElementBinding
.getHibernateTypeDescriptor()
.getResolvedTypeMapping();
return entityType.getAssociatedEntityName();
}
}
else if ( value instanceof Collection ) {
return getReferencedEntityName( ((Collection) value).getElement() );
}
return null;
}
/**
* @param value Persistent property.
* @param attributeBinding Persistent property.
* @return {@code false} if lack of associated entity shall raise an exception, {@code true} otherwise.
*/
public static boolean ignoreNotFound(Value value) {
if ( value instanceof ManyToOne ) {
return ( (ManyToOne) value ).isIgnoreNotFound();
public static boolean ignoreNotFound(AttributeBinding attributeBinding) {
if ( ManyToOneAttributeBinding.class.isInstance( attributeBinding )) {
return ! ( (ManyToOneAttributeBinding) attributeBinding ).isNotFoundAnException();
}
else if ( value instanceof OneToMany ) {
return ( (OneToMany) value ).isIgnoreNotFound();
else if ( attributeBinding instanceof PluralAttributeBinding ) {
final PluralAttributeBinding pluralAttributeBinding = (PluralAttributeBinding) attributeBinding;
final PluralAttributeElementBinding elementBinding = pluralAttributeBinding.getPluralAttributeElementBinding();
if ( elementBinding.getNature() == PluralAttributeElementBinding.Nature.ONE_TO_MANY ) {
// TODO: FIX THIS!!!
//return !( (OneToManyPluralAttributeElementBinding) elementBinding ).isNotFoundAnException();
}
}
return false;
}

View File

@ -126,7 +126,7 @@ public abstract class ReflectionTools {
*
* @param name Fully qualified class name.
* @param classLoaderService Class loading service. Passing {@code null} reference
* in case of {@link AuditConfiguration#getFor(Configuration)} usage.
* in case of {@link AuditConfiguration#register(Configuration)} usage.
*
* @return The cass reference.
*

View File

@ -32,6 +32,13 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.MethodInfo;
import org.hibernate.AssertionFailure;
import org.hibernate.envers.tools.Pair;
/**
@ -100,4 +107,21 @@ public abstract class Tools {
return ret;
}
public static boolean isFieldOrPropertyOfClass(AnnotationTarget target, ClassInfo clazz, IndexView jandexIndex) {
final ClassInfo enclosingClass;
if ( target instanceof FieldInfo ) {
final FieldInfo field = (FieldInfo) target;
enclosingClass = field.declaringClass();
}
else if ( target instanceof MethodInfo ) {
final MethodInfo method = (MethodInfo) target;
enclosingClass = method.declaringClass();
}
else {
throw new AssertionFailure( "Unexpected annotation target " + target.toString() );
}
return enclosingClass.equals( clazz ) || jandexIndex.getAllKnownSubclasses( clazz.name() ).contains( enclosingClass );
}
}

View File

@ -24,11 +24,27 @@
package org.hibernate.envers.tools.hbm2ddl;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.w3c.dom.Document;
import org.hibernate.HibernateException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.Configuration;
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
import org.hibernate.envers.configuration.internal.RevisionInfoConfigurationResult;
import org.hibernate.envers.configuration.spi.AuditConfiguration;
import org.hibernate.metamodel.Metadata;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.SchemaExport;
@ -38,33 +54,11 @@ import org.hibernate.tool.hbm2ddl.SchemaExport;
public class EnversSchemaGenerator {
private final SchemaExport export;
public EnversSchemaGenerator(ServiceRegistry serviceRegistry, Configuration configuration) {
configuration = configureAuditing( configuration );
export = new SchemaExport( serviceRegistry, configuration );
}
public EnversSchemaGenerator(Configuration configuration) {
configuration = configureAuditing( configuration );
export = new SchemaExport( configuration );
}
public EnversSchemaGenerator(Configuration configuration, Properties properties) throws HibernateException {
configuration = configureAuditing( configuration );
export = new SchemaExport( configuration, properties );
}
public EnversSchemaGenerator(Configuration configuration, Connection connection) throws HibernateException {
configuration = configureAuditing( configuration );
export = new SchemaExport( configuration, connection );
public EnversSchemaGenerator(MetadataImplementor metadata) {
export = new SchemaExport( metadata );
}
public SchemaExport export() {
return export;
}
private Configuration configureAuditing(Configuration configuration) {
configuration.buildMappings();
AuditConfiguration.getFor( configuration );
return configuration;
}
}

View File

@ -0,0 +1 @@
org.hibernate.envers.event.spi.EnversJaxbRootProducer

View File

@ -52,6 +52,7 @@ import org.hibernate.jpa.test.PersistenceUnitDescriptorAdapter;
import org.junit.After;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.testing.AfterClassOnce;
import org.hibernate.testing.BeforeClassOnce;
import org.hibernate.testing.jta.TestingJtaPlatformImpl;
@ -85,8 +86,8 @@ public abstract class BaseEnversJPAFunctionalTestCase extends AbstractEnversTest
return serviceRegistry;
}
protected Configuration getCfg() {
return entityManagerFactoryBuilder.getHibernateConfiguration();
protected MetadataImplementor getMetadata() {
return entityManagerFactoryBuilder.getMetadata();
}
@BeforeClassOnce

View File

@ -2,6 +2,7 @@ package org.hibernate.envers.test.entities.collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@ -9,7 +10,6 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Version;
import org.hibernate.annotations.ForeignKey;
import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;
@ -29,8 +29,7 @@ public class MultipleCollectionRefEntity1 {
private String text;
@ManyToOne
@JoinColumn(name = "MCE_ID", nullable = false, insertable = false, updatable = false)
@ForeignKey(name = "FK_RE1_MCE")
@JoinColumn(name = "MCE_ID", nullable = false, insertable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_RE1_MCE") )
@NotAudited
private MultipleCollectionEntity multipleCollectionEntity;

View File

@ -2,6 +2,7 @@ package org.hibernate.envers.test.entities.collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@ -9,7 +10,6 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Version;
import org.hibernate.annotations.ForeignKey;
import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;
@ -29,8 +29,7 @@ public class MultipleCollectionRefEntity2 {
private String text;
@ManyToOne
@JoinColumn(name = "MCE_ID", nullable = false, insertable = false, updatable = false)
@ForeignKey(name = "FK_RE2_MCE")
@JoinColumn(name = "MCE_ID", nullable = false, insertable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_RE2_MCE") )
@NotAudited
private MultipleCollectionEntity multipleCollectionEntity;

View File

@ -27,10 +27,10 @@ import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OrderColumn;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.annotations.IndexColumn;
import org.hibernate.envers.Audited;
/**
@ -44,7 +44,7 @@ public class StringListEntity {
@Audited
@ElementCollection
@IndexColumn(name = "list_index")
@OrderColumn(name = "list_index")
private List<String> strings;
public StringListEntity() {

View File

@ -1,10 +1,12 @@
package org.hibernate.envers.test.entities.components;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
/**
* @author Erik-Berndt Scheper
*/
@Embeddable
public class DefaultValueComponent1 {
private String str1;

View File

@ -1,9 +1,12 @@
package org.hibernate.envers.test.entities.components;
import javax.persistence.Embeddable;
/**
* @author Erik-Berndt Scheper
*/
@Embeddable
public class DefaultValueComponent2 {
private String str1 = "defaultValue";

View File

@ -33,8 +33,7 @@ import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;
import org.hibernate.annotations.SortComparator;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.entities.StrTestEntityComparator;
@ -54,12 +53,12 @@ public class SortedSetEntity {
@Audited
@ManyToMany
@Sort(type = SortType.COMPARATOR, comparator = StrTestEntityComparator.class)
@SortComparator(value = StrTestEntityComparator.class)
private SortedSet<StrTestEntity> sortedSet = new TreeSet<StrTestEntity>( StrTestEntityComparator.INSTANCE );
@Audited
@ElementCollection
@MapKeyJoinColumn
@Sort(type = SortType.COMPARATOR, comparator = StrTestEntityComparator.class)
@SortComparator(value = StrTestEntityComparator.class)
private SortedMap<StrTestEntity, String> sortedMap = new TreeMap<StrTestEntity, String>( StrTestEntityComparator.INSTANCE );
public SortedSetEntity() {

View File

@ -5,12 +5,12 @@ import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.persistence.Table;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hibernate.annotations.IndexColumn;
import org.hibernate.envers.AuditMappedBy;
import org.hibernate.envers.Audited;
@ -32,7 +32,7 @@ public class IndexedListJoinColumnBidirectionalRefIngEntity {
@OneToMany
@JoinColumn(name = "indexed_join_column")
@IndexColumn(name = "indexed_index")
@OrderColumn(name = "indexed_index")
@AuditMappedBy(mappedBy = "owner", positionMappedBy = "position")
private List<IndexedListJoinColumnBidirectionalRefEdEntity> references;

View File

@ -7,12 +7,12 @@ import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.persistence.Table;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hibernate.annotations.IndexColumn;
import org.hibernate.envers.AuditMappedBy;
import org.hibernate.envers.Audited;
@ -35,7 +35,7 @@ public abstract class ParentIndexedListJoinColumnBidirectionalRefIngEntity {
@OneToMany
@JoinColumn(name = "indexed_join_column")
@IndexColumn(name = "indexed_index")
@OrderColumn(name = "indexed_index")
@AuditMappedBy(mappedBy = "owner", positionMappedBy = "position")
private List<ParentOwnedIndexedListJoinColumnBidirectionalRefEdEntity> references;

View File

@ -1,12 +1,12 @@
package org.hibernate.envers.test.entities.reventity.trackmodifiedentities;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Table;
import java.util.Set;
@ -44,7 +44,7 @@ public class AnnotatedTrackingRevisionEntity {
private long customTimestamp;
@ElementCollection
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@CollectionTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME")
@ModifiedEntityNames
private Set<String> entityNames;

View File

@ -23,12 +23,13 @@
*/
package org.hibernate.envers.test.integration.accesstype;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Transient;
import org.hibernate.annotations.AccessType;
import org.hibernate.envers.Audited;
/**
@ -40,7 +41,7 @@ public class MixedAccessTypeEntity {
@GeneratedValue
private Integer id;
@AccessType("property")
@Access(value = AccessType.PROPERTY)
private String data;
@Transient

View File

@ -5,12 +5,12 @@ import java.util.Arrays;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.testing.TestForIssue;
/**
@ -18,8 +18,8 @@ import org.hibernate.testing.TestForIssue;
*/
@TestForIssue(jiraKey = "HHH-7003")
public class ColumnScalePrecisionTest extends BaseEnversJPAFunctionalTestCase {
private Table auditTable = null;
private Table originalTable = null;
private TableSpecification auditTable = null;
private TableSpecification originalTable = null;
private Long id = null;
@Override
@ -39,21 +39,29 @@ public class ColumnScalePrecisionTest extends BaseEnversJPAFunctionalTestCase {
em.getTransaction().commit();
id = entity.getId();
auditTable = getCfg().getClassMapping( "org.hibernate.envers.test.integration.basic.ScalePrecisionEntity_AUD" )
.getTable();
originalTable = getCfg().getClassMapping( "org.hibernate.envers.test.integration.basic.ScalePrecisionEntity" )
.getTable();
auditTable = getMetadata().getEntityBinding(
"org.hibernate.envers.test.integration.basic.ScalePrecisionEntity_AUD"
)
.getPrimaryTable();
originalTable = getMetadata().getEntityBinding(
"org.hibernate.envers.test.integration.basic.ScalePrecisionEntity"
)
.getPrimaryTable();
}
@Test
public void testColumnScalePrecision() {
Column testColumn = new Column( "wholeNumber" );
Column scalePrecisionAuditColumn = auditTable.getColumn( testColumn );
Column scalePrecisionColumn = originalTable.getColumn( testColumn );
String columnName = "wholeNumber";
Column scalePrecisionAuditColumn = auditTable.locateColumn( columnName );
Column scalePrecisionColumn = originalTable.locateColumn( columnName );
Assert.assertNotNull( scalePrecisionAuditColumn );
Assert.assertEquals( scalePrecisionColumn.getPrecision(), scalePrecisionAuditColumn.getPrecision() );
Assert.assertEquals( scalePrecisionColumn.getScale(), scalePrecisionAuditColumn.getScale() );
Assert.assertNotNull( scalePrecisionAuditColumn.getSize() );
Assert.assertEquals(
scalePrecisionColumn.getSize().getPrecision(),
scalePrecisionAuditColumn.getSize().getPrecision()
);
Assert.assertEquals( scalePrecisionColumn.getSize().getScale(), scalePrecisionAuditColumn.getSize().getScale() );
}
@Test

View File

@ -28,7 +28,7 @@ import java.util.Iterator;
import java.util.List;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.junit.Assert;
import org.junit.Test;
@ -44,9 +44,12 @@ public class NoneAudited extends BaseEnversJPAFunctionalTestCase {
@Test
public void testRevisionInfoTableNotCreated() {
@SuppressWarnings({"unchecked"}) List<PersistentClass> pcs = iteratorToList( getCfg().getClassMappings() );
@SuppressWarnings({"unchecked"}) List<EntityBinding> pcs = iteratorToList(
getMetadata().getEntityBindings()
.iterator()
);
Assert.assertEquals( 1, pcs.size() );
Assert.assertTrue( pcs.get( 0 ).getClassName().contains( "BasicTestEntity3" ) );
Assert.assertTrue( pcs.get( 0 ).getEntityName().contains( "BasicTestEntity3" ) );
}
private <T> List<T> iteratorToList(Iterator<T> it) {

View File

@ -53,7 +53,7 @@ public class EmbeddableList1 extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {EmbeddableListEntity1.class};
return new Class<?>[] {EmbeddableListEntity1.class, Component3.class, Component4.class};
}
@Test

View File

@ -62,7 +62,7 @@ public class EmbeddableList2 extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {EmbeddableListEntity2.class, StrTestNoProxyEntity.class};
return new Class<?>[] {EmbeddableListEntity2.class, StrTestNoProxyEntity.class, ManyToOneEagerComponent.class};
}
@Test

View File

@ -54,7 +54,7 @@ public class EmbeddableMap extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {EmbeddableMapEntity.class};
return new Class<?>[] {EmbeddableMapEntity.class, Component3.class, Component4.class};
}
@Test

View File

@ -55,7 +55,7 @@ public class EmbeddableSet extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {EmbeddableSetEntity.class};
return new Class<?>[] {EmbeddableSetEntity.class, Component3.class, Component4.class};
}
@Test

View File

@ -32,12 +32,14 @@ import org.hibernate.envers.test.entities.components.Component1;
import org.hibernate.envers.test.entities.components.Component2;
import org.hibernate.envers.test.entities.components.ComponentTestEntity;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.junit.Test;
/**
* @author Adam Warski (adam at warski dot org)
*/
@FailureExpectedWithNewMetamodel( message = " Plural attribute index that is an attribute of the referenced entity is not supported yet." )
public class ComponentMapKey extends BaseEnversJPAFunctionalTestCase {
private Integer cmke_id;
@ -46,7 +48,7 @@ public class ComponentMapKey extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {ComponentMapKeyEntity.class, ComponentTestEntity.class};
return new Class[] {ComponentMapKeyEntity.class, ComponentTestEntity.class, Component1.class, Component2.class};
}
@Test

View File

@ -30,12 +30,14 @@ import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.junit.Test;
/**
* @author Adam Warski (adam at warski dot org)
*/
@FailureExpectedWithNewMetamodel( message = " Plural attribute index that is an attribute of the referenced entity is not supported yet." )
public class IdMapKey extends BaseEnversJPAFunctionalTestCase {
private Integer imke_id;

View File

@ -45,7 +45,7 @@ public class Components extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {ComponentTestEntity.class};
return new Class[] {ComponentTestEntity.class, Component1.class, Component2.class};
}
@Test

View File

@ -57,7 +57,7 @@ public class DefaultValueComponents extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {DefaultValueComponentTestEntity.class};
return new Class[] {DefaultValueComponentTestEntity.class, DefaultValueComponent1.class, DefaultValueComponent2.class};
}
@Test

View File

@ -5,21 +5,22 @@ import org.hibernate.envers.test.BaseEnversFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.components.UniquePropsEntity;
import org.hibernate.envers.test.entities.components.UniquePropsNotAuditedEntity;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.TestForIssue;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@TestForIssue(jiraKey = "HHH-6636")
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class PropertiesGroupTest extends BaseEnversFunctionalTestCase {
private PersistentClass uniquePropsAudit = null;
private PersistentClass uniquePropsNotAuditedAudit = null;
private EntityBinding uniquePropsAudit = null;
private EntityBinding uniquePropsNotAuditedAudit = null;
private UniquePropsEntity entityRev1 = null;
private UniquePropsNotAuditedEntity entityNotAuditedRev2 = null;
@ -34,10 +35,10 @@ public class PropertiesGroupTest extends BaseEnversFunctionalTestCase {
@Test
@Priority(10)
public void initData() {
uniquePropsAudit = configuration().getClassMapping(
uniquePropsAudit = metadata().getEntityBinding(
"org.hibernate.envers.test.entities.components.UniquePropsEntity_AUD"
);
uniquePropsNotAuditedAudit = configuration().getClassMapping(
uniquePropsNotAuditedAudit = metadata().getEntityBinding(
"org.hibernate.envers.test.entities.components.UniquePropsNotAuditedEntity_AUD"
);
@ -65,11 +66,11 @@ public class PropertiesGroupTest extends BaseEnversFunctionalTestCase {
@Test
public void testAuditTableColumns() {
Assert.assertNotNull( uniquePropsAudit.getTable().getColumn( new Column( "DATA1" ) ) );
Assert.assertNotNull( uniquePropsAudit.getTable().getColumn( new Column( "DATA2" ) ) );
Assert.assertNotNull( uniquePropsAudit.getPrimaryTable().locateColumn( "DATA1" ) );
Assert.assertNotNull( uniquePropsAudit.getPrimaryTable().locateColumn( "DATA2" ) );
Assert.assertNotNull( uniquePropsNotAuditedAudit.getTable().getColumn( new Column( "DATA1" ) ) );
Assert.assertNull( uniquePropsNotAuditedAudit.getTable().getColumn( new Column( "DATA2" ) ) );
Assert.assertNotNull( uniquePropsNotAuditedAudit.getPrimaryTable().locateColumn( "DATA1" ) );
Assert.assertNull( uniquePropsNotAuditedAudit.getPrimaryTable().locateColumn( "DATA2" ) );
}
@Test

View File

@ -18,6 +18,7 @@ import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.test.BaseEnversFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.ServiceRegistryBuilder;
import org.hibernate.testing.TestForIssue;
@ -26,6 +27,7 @@ import org.hibernate.testing.TestForIssue;
* @author Lukasz Zuchowski (author at zuchos dot com)
*/
@TestForIssue(jiraKey = "HHH-8049")
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class AuditedDynamicComponentTest extends BaseEnversFunctionalTestCase {
@Override

View File

@ -17,6 +17,7 @@ import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.test.BaseEnversFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.TestForIssue;
/**
@ -24,6 +25,7 @@ import org.hibernate.testing.TestForIssue;
* More advanced tests for dynamic component.
*/
@TestForIssue(jiraKey = "HHH-8049")
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class AuditedDynamicComponentsAdvancedCasesTest extends BaseEnversFunctionalTestCase {
public static final String PROP_BOOLEAN = "propBoolean";

View File

@ -8,12 +8,14 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.envers.test.BaseEnversFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.TestForIssue;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@TestForIssue(jiraKey = "HHH-8049")
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class NotAuditedDynamicComponentTest extends BaseEnversFunctionalTestCase {
@Override
protected String[] getMappings() {

View File

@ -12,7 +12,9 @@ import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.test.BaseEnversFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class SanityCheckTest extends BaseEnversFunctionalTestCase {
@Override

View File

@ -44,7 +44,7 @@ public class ManyToOneInComponent extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {ManyToOneComponentTestEntity.class, StrTestEntity.class};
return new Class[] {ManyToOneComponentTestEntity.class, StrTestEntity.class, ManyToOneComponent.class};
}

View File

@ -42,7 +42,11 @@ public class NotAuditedManyToOneInComponent extends BaseEnversJPAFunctionalTestC
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {NotAuditedManyToOneComponentTestEntity.class, UnversionedStrTestEntity.class};
return new Class[] {
NotAuditedManyToOneComponentTestEntity.class,
UnversionedStrTestEntity.class,
NotAuditedManyToOneComponent.class
};
}
@Test

View File

@ -44,7 +44,7 @@ public class OneToManyInComponent extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {OneToManyComponentTestEntity.class, StrTestEntity.class};
return new Class[] {OneToManyComponentTestEntity.class, StrTestEntity.class, OneToManyComponent.class};
}
@Test

View File

@ -14,6 +14,7 @@ import org.hibernate.envers.test.entities.customtype.UnspecifiedEnumTypeEntity;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
@ -22,6 +23,7 @@ import org.hibernate.testing.TestForIssue;
*/
@TestForIssue(jiraKey = "HHH-7780")
@RequiresDialect(value = H2Dialect.class)
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class UnspecifiedEnumTypeTest extends BaseEnversFunctionalTestCase {
private Long id = null;

View File

@ -8,12 +8,14 @@ import java.util.List;
import org.hibernate.MappingException;
import org.hibernate.envers.test.AbstractOneSessionTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.junit.Test;
/**
* @author Hern&aacute;n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class ReadEntityWhitEntityNameTest extends AbstractOneSessionTest {
private long id_pers1;
@ -36,6 +38,7 @@ public class ReadEntityWhitEntityNameTest extends AbstractOneSessionTest {
@Test
@Priority(10)
//@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public void initData() {
initializeSession();
@ -79,6 +82,7 @@ public class ReadEntityWhitEntityNameTest extends AbstractOneSessionTest {
@Test
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public void testRetrieveRevisionsWithEntityName() {
List<Number> pers1Revs = getAuditReader().getRevisions( Person.class, "Personaje", id_pers1 );
List<Number> pers2Revs = getAuditReader().getRevisions( Person.class, "Personaje", id_pers2 );
@ -90,6 +94,7 @@ public class ReadEntityWhitEntityNameTest extends AbstractOneSessionTest {
}
@Test
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public void testRetrieveAuditedEntityWithEntityName() {
person1_1 = getAuditReader().find( Person.class, "Personaje", id_pers1, 1 );
person1_2 = getAuditReader().find( Person.class, "Personaje", id_pers1, 2 );
@ -102,6 +107,7 @@ public class ReadEntityWhitEntityNameTest extends AbstractOneSessionTest {
}
@Test
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public void testObtainEntityNameAuditedEntityWithEntityName() {
person1_1 = getAuditReader().find( Person.class, "Personaje", id_pers1, 1 );
person1_2 = getAuditReader().find( Person.class, "Personaje", id_pers1, 2 );
@ -121,6 +127,7 @@ public class ReadEntityWhitEntityNameTest extends AbstractOneSessionTest {
}
@Test
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public void testRetrieveAuditedEntityWithEntityNameWithNewSession() {
// force a new session and AR

View File

@ -9,12 +9,14 @@ import java.util.List;
import org.hibernate.MappingException;
import org.hibernate.envers.test.AbstractOneSessionTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.junit.Test;
/**
* @author Hern&aacute;n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class ReadEntityWithAuditedManyToManyTest extends AbstractOneSessionTest {
private long id_car1;

View File

@ -9,12 +9,14 @@ import java.util.List;
import org.hibernate.MappingException;
import org.hibernate.envers.test.AbstractOneSessionTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.junit.Test;
/**
* @author Hern&aacute;n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class ReadEntityWithAuditedCollectionTest extends AbstractOneSessionTest {
private long id_car1;

View File

@ -7,12 +7,14 @@ import java.net.URL;
import org.hibernate.MappingException;
import org.hibernate.envers.test.AbstractOneSessionTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.junit.Test;
/**
* @author Hern&aacute;n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class ReadEntityAssociatedAuditedTest extends AbstractOneSessionTest {
private long id_car1;

View File

@ -11,11 +11,13 @@ import org.hibernate.envers.test.Priority;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.TestForIssue;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class SingleDomainObjectToMultipleTablesTest extends AbstractOneSessionTest {
private long carId = 0;
private long ownerId = 0;

View File

@ -7,12 +7,14 @@ import java.net.URL;
import org.hibernate.MappingException;
import org.hibernate.envers.test.AbstractOneSessionTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.junit.Test;
/**
* @author Hern&aacute;n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class ReadEntityAssociatedNotAuditedTest extends AbstractOneSessionTest {
private long id_car1;

View File

@ -42,7 +42,7 @@ public class CompositeDateId extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {CompositeDateIdTestEntity.class};
return new Class[] {CompositeDateIdTestEntity.class, DateEmbId.class};
}
@Test

View File

@ -51,7 +51,13 @@ public class CompositeIds extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {EmbIdTestEntity.class, MulIdTestEntity.class, EmbIdWithCustomTypeTestEntity.class};
return new Class[] {
EmbIdTestEntity.class,
MulIdTestEntity.class,
EmbIdWithCustomTypeTestEntity.class,
EmbId.class,
EmbIdWithCustomType.class
};
}
@Test

View File

@ -22,7 +22,12 @@ public class ManyToOneIdNotAudited extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {ManyToOneIdNotAuditedTestEntity.class, UnversionedStrTestEntity.class, StrTestEntity.class};
return new Class[] {
ManyToOneIdNotAuditedTestEntity.class,
UnversionedStrTestEntity.class,
StrTestEntity.class,
ManyToOneNotAuditedEmbId.class
};
}
@Test

View File

@ -9,12 +9,14 @@ import org.hibernate.envers.test.Priority;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.TestForIssue;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@TestForIssue(jiraKey = "HHH-7690")
@FailureExpectedWithNewMetamodel( message = "Associations with non-envers entities not supported yet." )
public class RelationInsideEmbeddableTest extends BaseEnversJPAFunctionalTestCase {
private Integer orderId = null;
private ItemId itemId = null;

View File

@ -30,7 +30,7 @@ import java.util.Arrays;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.integration.inheritance.joined.ParentEntity;
import org.hibernate.mapping.Column;
import org.hibernate.metamodel.spi.relational.Column;
import org.junit.Assert;
import org.junit.Test;
@ -101,11 +101,15 @@ public class ChildPrimaryKeyJoinAuditing extends BaseEnversJPAFunctionalTestCase
public void testChildIdColumnName() {
Assert.assertEquals(
"other_id",
((Column) getCfg()
.getClassMapping(
( (Column) getMetadata()
.getEntityBinding(
"org.hibernate.envers.test.integration.inheritance.joined.primarykeyjoin.ChildPrimaryKeyJoinEntity_AUD"
)
.getKey().getColumnIterator().next()).getName()
.getHierarchyDetails()
.getEntityIdentifier()
.getAttributeBinding()
.getValues()
.get( 0 ) ).getColumnName().getText()
);
}
}

View File

@ -30,7 +30,8 @@ public class MixedInheritanceStrategiesEntityTest extends BaseEnversJPAFunctiona
AbstractActivity.class,
AbstractCheckActivity.class,
CheckInActivity.class,
NormalActivity.class
NormalActivity.class,
ActivityId.class
};
}

View File

@ -2,13 +2,14 @@ package org.hibernate.envers.test.integration.inheritance.single.discriminatorfo
import javax.persistence.EntityManager;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.EntityDiscriminator;
import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.relational.Value;
import org.junit.Assert;
import org.junit.Test;
@ -17,7 +18,7 @@ import org.junit.Test;
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class DiscriminatorFormulaTest extends BaseEnversJPAFunctionalTestCase {
private PersistentClass parentAudit = null;
private EntityBinding parentAudit = null;
private ChildEntity childVer1 = null;
private ChildEntity childVer2 = null;
private ParentEntity parentVer1 = null;
@ -31,7 +32,7 @@ public class DiscriminatorFormulaTest extends BaseEnversJPAFunctionalTestCase {
@Test
@Priority(10)
public void initData() {
parentAudit = getCfg().getClassMapping(
parentAudit = getMetadata().getEntityBinding(
"org.hibernate.envers.test.integration.inheritance.single.discriminatorformula.ParentEntity_AUD"
);
@ -87,16 +88,10 @@ public class DiscriminatorFormulaTest extends BaseEnversJPAFunctionalTestCase {
@Test
public void testDiscriminatorFormulaInAuditTable() {
assert parentAudit.getDiscriminator().hasFormula();
Iterator iterator = parentAudit.getDiscriminator().getColumnIterator();
while ( iterator.hasNext() ) {
Object o = iterator.next();
if ( o instanceof Formula ) {
Formula formula = (Formula) o;
Assert.assertEquals( ParentEntity.DISCRIMINATOR_QUERY, formula.getText() );
return;
}
}
final EntityDiscriminator entityDiscriminator = parentAudit.getHierarchyDetails().getEntityDiscriminator();
assert entityDiscriminator.getRelationalValue().getValueType() == Value.ValueType.DERIVED_VALUE;
DerivedValue derivedValue = (DerivedValue) entityDiscriminator.getRelationalValue();
Assert.assertEquals( ParentEntity.DISCRIMINATOR_QUERY, derivedValue.getExpression() );
assert false;
}

View File

@ -1,15 +1,16 @@
package org.hibernate.envers.test.integration.inheritance.tableperclass.abstractparent;
import javax.persistence.EntityManager;
import java.util.Iterator;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.mapping.Table;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.metamodel.spi.relational.Schema;
import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.testing.TestForIssue;
/**
@ -38,12 +39,12 @@ public class AuditedAbstractParentTest extends BaseEnversJPAFunctionalTestCase {
@Test
public void testAbstractTableExistence() {
Iterator<Table> tableIterator = getCfg().getTableMappings();
while ( tableIterator.hasNext() ) {
Table table = tableIterator.next();
if ( "AbstractEntity_AUD".equals( table.getName() ) ) {
Assert.assertFalse( table.isPhysicalTable() );
return;
for ( Schema schema : getMetadata().getDatabase().getSchemas() ) {
for ( TableSpecification table : schema.getTables() ) {
if ( "AbstractEntity_AUD".equals( table.getLogicalName().getText() ) ) {
Assert.assertFalse( Table.class.isInstance( table ) );
return;
}
}
}
Assert.fail();

View File

@ -39,7 +39,7 @@ public class InterfacesComponents extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {ComponentTestEntity.class};
return new Class[] {ComponentTestEntity.class, Component1.class};
}
@Test

View File

@ -1,10 +1,12 @@
package org.hibernate.envers.test.integration.interfaces.hbm.allAudited.joined;
import org.hibernate.envers.test.integration.interfaces.hbm.allAudited.AbstractAllAuditedTest;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
/**
* @author Hern<EFBFBD>n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class JoinedAllAuditedTest extends AbstractAllAuditedTest {
@Override
protected String[] getMappings() {

View File

@ -1,10 +1,12 @@
package org.hibernate.envers.test.integration.interfaces.hbm.allAudited.subclass;
import org.hibernate.envers.test.integration.interfaces.hbm.allAudited.AbstractAllAuditedTest;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
/**
* @author Hern<EFBFBD>n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class SubclassAllAuditedTest extends AbstractAllAuditedTest {
@Override
protected String[] getMappings() {

View File

@ -1,10 +1,12 @@
package org.hibernate.envers.test.integration.interfaces.hbm.allAudited.union;
import org.hibernate.envers.test.integration.interfaces.hbm.allAudited.AbstractAllAuditedTest;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
/**
* @author Hern<EFBFBD>n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class UnionAllAuditedTest extends AbstractAllAuditedTest {
@Override
protected String[] getMappings() {

View File

@ -1,10 +1,12 @@
package org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited.joined;
import org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited.AbstractPropertiesAuditedTest;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
/**
* @author Hern<EFBFBD>n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class JoinedPropertiesAuditedTest extends AbstractPropertiesAuditedTest {
@Override

View File

@ -1,10 +1,12 @@
package org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited.subclass;
import org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited.AbstractPropertiesAuditedTest;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
/**
* @author Hern<EFBFBD>n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class SubclassPropertiesAuditedTest extends AbstractPropertiesAuditedTest {
@Override
protected String[] getMappings() {

View File

@ -1,10 +1,12 @@
package org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited.union;
import org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited.AbstractPropertiesAuditedTest;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
/**
* @author Hern<EFBFBD>n Chanfreau
*/
@FailureExpectedWithNewMetamodel( message = "hbm.xml source not supported because it is not indexed." )
public class UnionPropertiesAuditedTest extends AbstractPropertiesAuditedTest {
@Override

Some files were not shown because too many files have changed in this diff Show More