package org.hibernate.metamodel.source.hbm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.MappingException;
import org.hibernate.internal.jaxb.mapping.hbm.EntityElement;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbHibernateMapping;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbJoinedSubclassElement;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbSubclassElement;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbUnionSubclassElement;
import org.hibernate.internal.jaxb.mapping.hbm.SubEntityElement;
import org.hibernate.metamodel.source.binder.SubclassEntityContainer;
import org.hibernate.metamodel.source.binder.SubclassEntitySource;
public class HierarchyBuilder {
private final List<EntityHierarchyImpl> entityHierarchies = new ArrayList<EntityHierarchyImpl>();
private final Map<String,SubclassEntityContainer> subEntityContainerMap = new HashMap<String, SubclassEntityContainer>();
private final List<ExtendsQueueEntry> extendsQueue = new ArrayList<ExtendsQueueEntry>();
private MappingDocument currentMappingDocument;
public void processMappingDocument(MappingDocument mappingDocument) {
this.currentMappingDocument = mappingDocument;
try {
processCurrentMappingDocument();
}
finally {
this.currentMappingDocument = null;
}
}
private void processCurrentMappingDocument() {
for ( Object entityElementO : currentMappingDocument.getMappingRoot().getClazzOrSubclassOrJoinedSubclass() ) {
final EntityElement entityElement = (EntityElement) entityElementO;
if ( JaxbHibernateMapping.JaxbClass.class.isInstance( entityElement ) ) {
final JaxbHibernateMapping.JaxbClass jaxbClass = (JaxbHibernateMapping.JaxbClass) entityElement;
final RootEntitySourceImpl rootEntitySource = new RootEntitySourceImpl( currentMappingDocument,
jaxbClass
);
final EntityHierarchyImpl hierarchy = new EntityHierarchyImpl( rootEntitySource );
entityHierarchies.add( hierarchy );
subEntityContainerMap.put( rootEntitySource.getEntityName(), rootEntitySource );
processSubElements( entityElement, rootEntitySource );
}
else {
final SubclassEntitySourceImpl subClassEntitySource = new SubclassEntitySourceImpl( currentMappingDocument, entityElement );
final String entityName = subClassEntitySource.getEntityName();
subEntityContainerMap.put( entityName, subClassEntitySource );
final String entityItExtends = currentMappingDocument.getMappingLocalBindingContext().qualifyClassName(
((SubEntityElement) entityElement).getExtends()
);
processSubElements( entityElement, subClassEntitySource );
final SubclassEntityContainer container = subEntityContainerMap.get( entityItExtends );
if ( container != null ) {
container.add( subClassEntitySource );
}
else {
extendsQueue.add( new ExtendsQueueEntry( subClassEntitySource, entityItExtends ) );
}
}
}
}
public List<EntityHierarchyImpl> groupEntityHierarchies() {
while ( ! extendsQueue.isEmpty() ) {
int numberOfMappingsProcessed = 0;
Iterator<ExtendsQueueEntry> iterator = extendsQueue.iterator();
while ( iterator.hasNext() ) {
final ExtendsQueueEntry entry = iterator.next();
final SubclassEntityContainer container = subEntityContainerMap.get( entry.entityItExtends );
if ( container != null ) {
container.add( entry.subClassEntitySource );
iterator.remove();
numberOfMappingsProcessed++;
}
}
if ( numberOfMappingsProcessed == 0 ) {
throw new MappingException( "Unable to process extends dependencies in hbm files" );
}
}
return entityHierarchies;
}
private void processSubElements(EntityElement entityElement, SubclassEntityContainer container) {
if ( JaxbHibernateMapping.JaxbClass.class.isInstance( entityElement ) ) {
final JaxbHibernateMapping.JaxbClass jaxbClass = (JaxbHibernateMapping.JaxbClass) entityElement;
processElements( jaxbClass.getJoinedSubclass(), container );
processElements( jaxbClass.getSubclass(), container );
processElements( jaxbClass.getUnionSubclass(), container );
}
else if ( JaxbSubclassElement.class.isInstance( entityElement ) ) {
final JaxbSubclassElement jaxbSubclass = (JaxbSubclassElement) entityElement;
processElements( jaxbSubclass.getSubclass(), container );
}
else if ( JaxbJoinedSubclassElement.class.isInstance( entityElement ) ) {
final JaxbJoinedSubclassElement jaxbJoinedSubclass = (JaxbJoinedSubclassElement) entityElement;
processElements( jaxbJoinedSubclass.getJoinedSubclass(), container );
}
else if ( JaxbUnionSubclassElement.class.isInstance( entityElement ) ) {
final JaxbUnionSubclassElement jaxbUnionSubclass = (JaxbUnionSubclassElement) entityElement;
processElements( jaxbUnionSubclass.getUnionSubclass(), container );
}
}
private void processElements(List subElements, SubclassEntityContainer container) {
for ( Object subElementO : subElements ) {
final SubEntityElement subElement = (SubEntityElement) subElementO;
final SubclassEntitySourceImpl subclassEntitySource = new SubclassEntitySourceImpl( currentMappingDocument, subElement );
container.add( subclassEntitySource );
final String subEntityName = subclassEntitySource.getEntityName();
subEntityContainerMap.put( subEntityName, subclassEntitySource );
}
}
private static class ExtendsQueueEntry {
private final SubclassEntitySource subClassEntitySource;
private final String entityItExtends;
private ExtendsQueueEntry(SubclassEntitySource subClassEntitySource, String entityItExtends) {
this.subClassEntitySource = subClassEntitySource;
this.entityItExtends = entityItExtends;
}
}
}