/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.envers.configuration.internal; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.hibernate.MappingException; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.boot.spi.MetadataImplementor; 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.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.service.ServiceRegistry; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; /** * @author Adam Warski (adam at warski dot org) */ public class EntitiesConfigurator { public EntitiesConfigurations configure( MetadataImplementor metadata, ServiceRegistry serviceRegistry, ReflectionManager reflectionManager, MappingCollector mappingCollector, GlobalConfiguration globalConfiguration, AuditEntitiesConfiguration auditEntitiesConfiguration, AuditStrategy auditStrategy, Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) { // Creating a name register to capture all audit entity names created. final AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister(); // Sorting the persistent class topologically - superclass always before subclass final Iterator<PersistentClass> classes = GraphTopologicalSort.sort( new PersistentClassGraphDefiner( metadata ) ) .iterator(); final ClassesAuditingData classesAuditingData = new ClassesAuditingData(); final Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<>(); // Reading metadata from annotations while ( classes.hasNext() ) { final PersistentClass pc = classes.next(); // Ensure we're in POJO, not dynamic model, mapping. if (pc.getClassName() != null) { // Collecting information from annotations on the persistent class pc final AnnotationsMetadataReader annotationsMetadataReader = new AnnotationsMetadataReader( globalConfiguration, reflectionManager, pc ); final ClassAuditingData auditData = annotationsMetadataReader.getAuditData(); classesAuditingData.addClassAuditingData( pc, auditData ); } } // Now that all information is read we can update the calculated fields. classesAuditingData.updateCalculatedFields(); final AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator( metadata, serviceRegistry, globalConfiguration, auditEntitiesConfiguration, auditStrategy, revisionInfoRelationMapping, auditEntityNameRegister ); // First pass for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) { final PersistentClass pc = pcDatasEntry.getKey(); final ClassAuditingData auditData = pcDatasEntry.getValue(); final EntityXmlMappingData xmlMappingData = new EntityXmlMappingData(); if ( auditData.isAudited() ) { if ( !StringTools.isEmpty( auditData.getAuditTable().value() ) ) { auditEntitiesConfiguration.addCustomAuditTableName( pc.getEntityName(), auditData.getAuditTable().value() ); } auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, true ); } else { auditMetaGen.generateFirstPass( pc, auditData, xmlMappingData, false ); } xmlMappings.put( pc, xmlMappingData ); } // Second pass for ( Map.Entry<PersistentClass, ClassAuditingData> pcDatasEntry : classesAuditingData.getAllClassAuditedData() ) { final EntityXmlMappingData xmlMappingData = xmlMappings.get( pcDatasEntry.getKey() ); if ( pcDatasEntry.getValue().isAudited() ) { auditMetaGen.generateSecondPass( pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData ); try { mappingCollector.addDocument( xmlMappingData.getMainXmlMapping() ); for ( Document additionalMapping : xmlMappingData.getAdditionalXmlMappings() ) { mappingCollector.addDocument( additionalMapping ); } } catch (DocumentException e) { throw new MappingException( e ); } } } // Only if there are any versioned classes if ( auditMetaGen.getEntitiesConfigurations().size() > 0 ) { try { if ( revisionInfoXmlMapping != null ) { mappingCollector.addDocument( revisionInfoXmlMapping ); } } catch (DocumentException e) { throw new MappingException( e ); } } return new EntitiesConfigurations( auditMetaGen.getEntitiesConfigurations(), auditMetaGen.getNotAuditedEntitiesConfigurations() ); } }