HHH-8056 : EntityHierarchyHelper

This commit is contained in:
Gail Badner 2013-03-06 13:42:30 -08:00
parent 92ae31b514
commit 7da7f28902
3 changed files with 372 additions and 231 deletions

View File

@ -33,7 +33,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -59,6 +58,8 @@ import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.internal.EntityHierarchyHelper.LocalBindingContextExecutionContext;
import org.hibernate.metamodel.internal.EntityHierarchyHelper.LocalBindingContextExecutor;
import org.hibernate.internal.FilterConfiguration;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
@ -161,7 +162,6 @@ import org.hibernate.metamodel.spi.source.SequentialPluralAttributeIndexSource;
import org.hibernate.metamodel.spi.source.SimpleIdentifierSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.Sortable;
import org.hibernate.metamodel.spi.source.SubclassEntitySource;
import org.hibernate.metamodel.spi.source.TableSource;
import org.hibernate.metamodel.spi.source.TableSpecificationSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
@ -206,12 +206,9 @@ public class Binder {
private final SourceIndex sourceIndex = new SourceIndex();
// todo : apply org.hibernate.metamodel.MetadataSources.getExternalCacheRegionDefinitions()
// the inheritanceTypes and entityModes correspond with bindingContexts
private final LinkedList<LocalBindingContext> bindingContexts = new LinkedList<LocalBindingContext>();
private final LinkedList<InheritanceType> inheritanceTypes = new LinkedList<InheritanceType>();
private final LinkedList<EntityMode> entityModes = new LinkedList<EntityMode>();
// helpers
private final EntityHierarchyHelper entityHierarchyHelper;
private final HibernateTypeHelper typeHelper; // todo: refactor helper and remove redundant methods in this class
private final ForeignKeyHelper foreignKeyHelper;
@ -219,6 +216,7 @@ public class Binder {
final IdentifierGeneratorFactory identifierGeneratorFactory) {
this.metadata = metadata;
this.identifierGeneratorFactory = identifierGeneratorFactory;
this.entityHierarchyHelper = new EntityHierarchyHelper( metadata );
this.typeHelper = new HibernateTypeHelper( this, metadata );
this.foreignKeyHelper = new ForeignKeyHelper( this );
this.nameNormalizer = metadata.getObjectNameNormalizer();
@ -230,10 +228,6 @@ public class Binder {
* @param entityHierarchies The entity hierarchies resolved from mappings
*/
public void addEntityHierarchies(final Iterable<EntityHierarchy> entityHierarchies) {
inheritanceTypes.clear();
entityModes.clear();
bindingContexts.clear();
LocalBindingContextExecutor executor = new LocalBindingContextExecutor() {
@Override
public void execute(LocalBindingContextExecutionContext bindingContextContext) {
@ -249,14 +243,13 @@ public class Binder {
entityHierarchy.getRootEntitySource().getEntityName(),
entityHierarchy
);
applyToEntityHierarchy( entityHierarchy, executor, executor );
entityHierarchyHelper.applyToEntityHierarchy( entityHierarchy, executor, executor );
}
}
public void bindEntityHierarchies() {
bindingContexts.clear();
inheritanceTypes.clear();
entityModes.clear();
applyToAllEntityHierarchies( resolveAssociationSourcesExecutor() );
bindEntityHierarchiesExcludingNonIdAttributeBindings();
@ -281,6 +274,27 @@ public class Binder {
// if so, mark the many-to-one as a logical one-to-one.
}
private InheritanceType inheritanceType() {
return entityHierarchyHelper.inheritanceType();
}
private EntityMode entityMode() {
return entityHierarchyHelper.entityMode();
}
// TODO: make this private
LocalBindingContext bindingContext() {
return entityHierarchyHelper.bindingContext();
}
private void applyToAllEntityHierarchies(LocalBindingContextExecutor executor) {
applyToAllEntityHierarchies( executor, executor );
}
private void applyToAllEntityHierarchies(LocalBindingContextExecutor rootExecutor, LocalBindingContextExecutor subExecutor) {
entityHierarchyHelper.applyToAllEntityHierarchies( entityHierarchiesByRootEntityName.values(), rootExecutor, subExecutor );
}
private void bindEntityHierarchiesExcludingNonIdAttributeBindings() {
LocalBindingContextExecutor rootEntityCallback = new LocalBindingContextExecutor() {
@Override
@ -324,12 +338,12 @@ public class Binder {
unresolvedEntityHierarchies.add( entityHierarchy );
}
else {
applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback );
entityHierarchyHelper.applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback );
}
}
for ( EntityHierarchy entityHierarchy : unresolvedEntityHierarchies ) {
applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback );
entityHierarchyHelper.applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback );
}
}
@ -369,6 +383,15 @@ public class Binder {
(AttributeBindingContainer) entityBinding.locateAttributeBindingByPath( containerPath, false );
}
private LocalBindingContextExecutor resolveAssociationSourcesExecutor() {
return new LocalBindingContextExecutor() {
@Override
public void execute(LocalBindingContextExecutionContext bindingContextContext) {
sourceIndex.resolveAssociationSources( bindingContextContext.getEntitySource().getEntityName() );
}
};
}
private LocalBindingContextExecutor bindSingularAttributesExecutor(
final SingularAttributeSource.Nature nature) {
return new LocalBindingContextExecutor() {
@ -443,12 +466,26 @@ public class Binder {
null, // TODO: don't have the default value at this point; shouldn't be needed...
compositeAttributeBinding
);
if ( compositeAttributeBinding.getContainer() instanceof CompositeAttributeBindingContainer ) {
final CompositeAttributeBinding parentCompositeAttributeBinding =
(CompositeAttributeBinding) compositeAttributeBinding.seekEntityBinding().locateAttributeBinding(
( compositeAttributeBinding.getContainer() ).getPathBase()
);
final ComponentAttributeSource parentCompositeAttributeSource =
(ComponentAttributeSource) sourceIndex.attributeSource(
parentCompositeAttributeBinding.seekEntityBinding().getEntityName(),
parentCompositeAttributeBinding.getPathBase()
);
completeCompositeAttributeBindingIfPossible(
parentCompositeAttributeBinding,
parentCompositeAttributeSource
);
}
}
}
}
private LocalBindingContextExecutor bindPluralAttributesExecutor(
final boolean isInverse) {
private LocalBindingContextExecutor bindPluralAttributesExecutor(final boolean isInverse) {
return new LocalBindingContextExecutor() {
@Override
public void execute(LocalBindingContextExecutionContext bindingContextContext) {
@ -462,28 +499,27 @@ public class Binder {
}
private void bindPluralAttributes(
final AttributeBindingContainer attributeBindingContainer,
final AttributeSourceContainer attributeSourceContainer,
final EntityBinding entityBinding,
final EntitySource entitySource,
final boolean isInverse) {
for ( AttributeSource attributeSource : attributeSourceContainer.attributeSources() ) {
if ( attributeSource.isSingular() ) {
SingularAttributeSource singularAttributeSource = (SingularAttributeSource) attributeSource;
if ( singularAttributeSource.getNature() == SingularAttributeSource.Nature.COMPOSITE ) {
final ComponentAttributeSource compositeAttributeSource = (ComponentAttributeSource) attributeSource;
final CompositeAttributeBinding compositeAttributeBinding =
(CompositeAttributeBinding) attributeBindingContainer.locateAttributeBinding( attributeSource.getName() );
bindPluralAttributes(
compositeAttributeBinding,
compositeAttributeSource,
isInverse
);
completeCompositeAttributeBindingIfPossible( compositeAttributeBinding, compositeAttributeSource );
}
}
else {
if ( isInverse == ( (PluralAttributeSource) attributeSource ).isInverse() ) {
bindAttribute( attributeBindingContainer, attributeSource );
}
Map<SourceIndex.AttributeSourceKey, PluralAttributeSource> map = sourceIndex.getPluralAttributeSources(
entityBinding.getEntityName(),
isInverse
);
for ( Map.Entry<SourceIndex.AttributeSourceKey, PluralAttributeSource> entry : map.entrySet() ){
final SourceIndex.AttributeSourceKey attributeSourceKey = entry.getKey();
final PluralAttributeSource attributeSource = entry.getValue();
final AttributeBindingContainer attributeBindingContainer =
locateAttributeBindingContainer( entityBinding, attributeSourceKey.containerPath() );
bindAttribute( attributeBindingContainer, attributeSource );
if ( attributeBindingContainer instanceof CompositeAttributeBinding ) {
final CompositeAttributeBinding compositeAttributeBinding = (CompositeAttributeBinding) attributeBindingContainer;
final ComponentAttributeSource compositeAttributeSource =
(ComponentAttributeSource) sourceIndex.attributeSource(
entityBinding.getEntityName(),
compositeAttributeBinding.getPathBase()
);
completeCompositeAttributeBindingIfPossible( compositeAttributeBinding, compositeAttributeSource );
}
}
}
@ -524,17 +560,15 @@ public class Binder {
final EntityBinding superEntityBinding,
final EntitySource entitySource) {
// Create binding
final InheritanceType inheritanceType = inheritanceTypes.peek();
final EntityMode entityMode = entityModes.peek();
final EntityBinding entityBinding =
entitySource instanceof RootEntitySource ? new EntityBinding(
inheritanceType,
entityMode
inheritanceType(),
entityMode()
) : new EntityBinding(
superEntityBinding
);
// Create domain entity
final String entityClassName = entityMode == EntityMode.POJO ? entitySource.getClassName() : null;
final String entityClassName = entityMode() == EntityMode.POJO ? entitySource.getClassName() : null;
LocalBindingContext bindingContext = bindingContext();
entityBinding.setEntity(
new Entity(
@ -621,7 +655,7 @@ public class Binder {
private void resolveEntityLaziness(
final EntityBinding entityBinding,
final EntitySource entitySource) {
if ( entityModes.peek() == EntityMode.POJO ) {
if ( entityMode() == EntityMode.POJO ) {
final String proxy = entitySource.getProxy();
if ( proxy == null ) {
if ( entitySource.isLazy() ) {
@ -1545,16 +1579,6 @@ public class Binder {
final AttributeBindingContainer attributeBindingContainer,
final PluralAttributeSource attributeSource) {
final PluralAttributeSource.Nature nature = attributeSource.getNature();
if ( attributeSource.getMappedBy() != null ) {
attributeSource.resolvePluralAttributeElementSource(
new PluralAttributeElementSourceResolver.PluralAttributeElementSourceResolutionContext() {
@Override
public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy) {
return sourceIndex.attributeSource( referencedEntityName, mappedBy );
}
}
);
}
final PluralAttribute attribute =
attributeBindingContainer.getAttributeContainer().locatePluralAttribute( attributeSource.getName() );
final AbstractPluralAttributeBinding attributeBinding;
@ -2164,33 +2188,26 @@ public class Binder {
);
final PluralAttributeKeyBinding keyBinding = attributeBinding.getPluralAttributeKeyBinding();
keyBinding.setInverse( isInverse );
String oppositeAttributeName = null;
final AttributeSource oppositeAttributeSource;
if ( attributeSource.getMappedBy() == null ) {
final String path;
//if ( StringHelper.isEmpty( attributeBinding.getContainer().getPathBase() ) ) {
path = createAttributePath( attributeBinding );
//}
//else {
// path = attributeBinding.getContainer().getPathBase() + '.' + attributeBinding.getAttribute().getName();
//}
// determine if there is an association that is mappedBy this one
EntitySource referencedEntitySource = sourceIndex.entitySource( referencedEntityBinding.getEntityName() );
for ( AttributeSource referencedAttributeSource : referencedEntitySource.attributeSources() ) {
// TODO: move this somewhere else or index beforehand.
// TODO: deal with mappedBy w/in CompositeAttributeBindings.
if ( referencedAttributeSource instanceof PluralAttributeSource) {
PluralAttributeSource referencedPluralAttributeSource = (PluralAttributeSource) referencedAttributeSource;
if ( path.equals( referencedPluralAttributeSource.getMappedBy() ) ) {
oppositeAttributeName = referencedPluralAttributeSource.getName();
}
}
}
oppositeAttributeSource = sourceIndex.locateAttributeSourceOwnedBy(
attributeBinding.getContainer().seekEntityBinding().getEntityName(),
createAttributePath( attributeBinding )
);
}
else {
oppositeAttributeName = attributeSource.getMappedBy();
oppositeAttributeSource =
sourceIndex.attributeSource(
referencedEntityBinding.getEntityName(),
attributeSource.getMappedBy()
);
}
bindCollectionTableForeignKey( attributeBinding, attributeSource.getKeySource(), collectionTable, oppositeAttributeName );
bindCollectionTableForeignKey(
attributeBinding,
attributeSource.getKeySource(),
collectionTable,
oppositeAttributeSource == null ? null : oppositeAttributeSource.getName()
);
}
private void bindPluralAttributeIndex(
@ -3032,26 +3049,6 @@ public class Binder {
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ simple instance helper methods
private void cleanupBindingContext() {
bindingContexts.pop();
inheritanceTypes.pop();
entityModes.pop();
}
public LocalBindingContext bindingContext() {
return bindingContexts.peek();
}
private void setupBindingContext(
final EntityHierarchy entityHierarchy,
final RootEntitySource rootEntitySource) {
// Save inheritance type and entity mode that will apply to entire hierarchy
inheritanceTypes.push( entityHierarchy.getHierarchyInheritanceType() );
entityModes.push( rootEntitySource.getEntityMode() );
bindingContexts.push( rootEntitySource.getLocalBindingContext() );
}
private String propertyAccessorName(final AttributeSource attributeSource) {
return propertyAccessorName( attributeSource.getPropertyAccessorName() );
}
@ -3293,78 +3290,6 @@ public class Binder {
return unsavedValue;
}
/**
* Apply executors to all entity hierarchies.
*/
private void applyToAllEntityHierarchies(
final LocalBindingContextExecutor executor) {
applyToAllEntityHierarchies( executor, executor );
}
/**
* Apply executors to all entity hierarchies.
*/
private void applyToAllEntityHierarchies(
final LocalBindingContextExecutor rootEntityExecutor,
final LocalBindingContextExecutor subEntityExecutor) {
for ( final EntityHierarchy entityHierarchy : entityHierarchiesByRootEntityName.values() ) {
applyToEntityHierarchy( entityHierarchy, rootEntityExecutor, subEntityExecutor );
}
}
/**
* Apply executors to a single entity hierarchy.
*
* @param entityHierarchy The entity hierarchy to be binded.
*/
private void applyToEntityHierarchy(
final EntityHierarchy entityHierarchy,
final LocalBindingContextExecutor rootEntityExecutor,
final LocalBindingContextExecutor subEntityExecutor) {
final RootEntitySource rootEntitySource = entityHierarchy.getRootEntitySource();
setupBindingContext( entityHierarchy, rootEntitySource );
try {
LocalBindingContextExecutionContext executionContext =
new LocalBindingContextExecutionContextImpl( rootEntitySource, null );
rootEntityExecutor.execute( executionContext );
if ( inheritanceTypes.peek() != InheritanceType.NO_INHERITANCE ) {
applyToSubEntities(
executionContext.getEntityBinding(),
rootEntitySource,
subEntityExecutor );
}
}
finally {
cleanupBindingContext();
}
}
private void applyToSubEntities(
final EntityBinding entityBinding,
final EntitySource entitySource,
final LocalBindingContextExecutor subEntityExecutor) {
for ( final SubclassEntitySource subEntitySource : entitySource.subclassEntitySources() ) {
applyToSubEntity( entityBinding, subEntitySource, subEntityExecutor );
}
}
private void applyToSubEntity(
final EntityBinding superEntityBinding,
final EntitySource entitySource,
final LocalBindingContextExecutor subEntityExecutor) {
final LocalBindingContext bindingContext = entitySource.getLocalBindingContext();
bindingContexts.push( bindingContext );
try {
LocalBindingContextExecutionContext executionContext =
new LocalBindingContextExecutionContextImpl( entitySource, superEntityBinding );
subEntityExecutor.execute( executionContext );
applyToSubEntities( executionContext.getEntityBinding(), entitySource, subEntityExecutor );
}
finally {
bindingContexts.pop();
}
}
private static void addUniqueConstraintForNaturalIdColumn(
final TableSpecification table,
final Column column) {
@ -3372,41 +3297,6 @@ public class Binder {
uniqueKey.addColumn( column );
}
private interface LocalBindingContextExecutor {
void execute(LocalBindingContextExecutionContext bindingContextContext);
}
private interface LocalBindingContextExecutionContext {
EntitySource getEntitySource();
EntityBinding getEntityBinding();
EntityBinding getSuperEntityBinding();
}
private class LocalBindingContextExecutionContextImpl implements LocalBindingContextExecutionContext {
private final EntitySource entitySource;
private final EntityBinding superEntityBinding;
private LocalBindingContextExecutionContextImpl(
EntitySource entitySource,
EntityBinding superEntityBinding) {
this.entitySource = entitySource;
this.superEntityBinding = superEntityBinding;
}
@Override
public EntitySource getEntitySource() {
return entitySource;
}
@Override
public EntityBinding getEntityBinding() {
return metadata.getEntityBinding( entitySource.getEntityName() );
}
@Override
public EntityBinding getSuperEntityBinding() {
return superEntityBinding;
}
}
public static interface DefaultNamingStrategy {
String defaultName();

View File

@ -0,0 +1,183 @@
/*
* 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.metamodel.internal;
import java.util.LinkedList;
import org.hibernate.EntityMode;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.InheritanceType;
import org.hibernate.metamodel.spi.source.EntityHierarchy;
import org.hibernate.metamodel.spi.source.EntitySource;
import org.hibernate.metamodel.spi.source.LocalBindingContext;
import org.hibernate.metamodel.spi.source.RootEntitySource;
import org.hibernate.metamodel.spi.source.SubclassEntitySource;
/**
* @author Gail Badner
*/
public class EntityHierarchyHelper {
public interface LocalBindingContextExecutor {
void execute(LocalBindingContextExecutionContext bindingContextContext);
}
private MetadataImplementor metadata;
// the inheritanceTypes and entityModes correspond with bindingContexts
private final LinkedList<LocalBindingContext> bindingContexts = new LinkedList<LocalBindingContext>();
private final LinkedList<InheritanceType> inheritanceTypes = new LinkedList<InheritanceType>();
private final LinkedList<EntityMode> entityModes = new LinkedList<EntityMode>();
EntityHierarchyHelper(final MetadataImplementor metadata) {
this.metadata = metadata;
}
/**
* Apply executors to all entity hierarchies.
*/
public void applyToAllEntityHierarchies(
final Iterable<EntityHierarchy> entityHierarchies,
final LocalBindingContextExecutor rootEntityExecutor,
final LocalBindingContextExecutor subEntityExecutor) {
for ( final EntityHierarchy entityHierarchy : entityHierarchies ) {
applyToEntityHierarchy( entityHierarchy, rootEntityExecutor, subEntityExecutor );
}
}
/**
* Apply executors to a single entity hierarchy.
*
* @param entityHierarchy The entity hierarchy to be binded.
*/
public void applyToEntityHierarchy(
final EntityHierarchy entityHierarchy,
final LocalBindingContextExecutor rootEntityExecutor,
final LocalBindingContextExecutor subEntityExecutor) {
bindingContexts.clear();
inheritanceTypes.clear();
entityModes.clear();
final RootEntitySource rootEntitySource = entityHierarchy.getRootEntitySource();
setupBindingContext( entityHierarchy, rootEntitySource );
try {
LocalBindingContextExecutionContext executionContext =
new LocalBindingContextExecutionContextImpl( rootEntitySource, null );
rootEntityExecutor.execute( executionContext );
if ( inheritanceTypes.peek() != InheritanceType.NO_INHERITANCE ) {
applyToSubEntities(
executionContext.getEntityBinding(),
rootEntitySource,
subEntityExecutor );
}
}
finally {
cleanupBindingContext();
}
}
private void cleanupBindingContext() {
bindingContexts.pop();
inheritanceTypes.pop();
entityModes.pop();
}
public LocalBindingContext bindingContext() {
return bindingContexts.peek();
}
public InheritanceType inheritanceType() {
return inheritanceTypes.peek();
}
public EntityMode entityMode() {
return entityModes.peek();
}
private void setupBindingContext(
final EntityHierarchy entityHierarchy,
final RootEntitySource rootEntitySource) {
// Save inheritance type and entity mode that will apply to entire hierarchy
inheritanceTypes.push( entityHierarchy.getHierarchyInheritanceType() );
entityModes.push( rootEntitySource.getEntityMode() );
bindingContexts.push( rootEntitySource.getLocalBindingContext() );
}
private void applyToSubEntities(
final EntityBinding entityBinding,
final EntitySource entitySource,
final LocalBindingContextExecutor subEntityExecutor) {
for ( final SubclassEntitySource subEntitySource : entitySource.subclassEntitySources() ) {
applyToSubEntity( entityBinding, subEntitySource, subEntityExecutor );
}
}
private void applyToSubEntity(
final EntityBinding superEntityBinding,
final EntitySource entitySource,
final LocalBindingContextExecutor subEntityExecutor) {
final LocalBindingContext bindingContext = entitySource.getLocalBindingContext();
bindingContexts.push( bindingContext );
try {
LocalBindingContextExecutionContext executionContext =
new LocalBindingContextExecutionContextImpl( entitySource, superEntityBinding );
subEntityExecutor.execute( executionContext );
applyToSubEntities( executionContext.getEntityBinding(), entitySource, subEntityExecutor );
}
finally {
bindingContexts.pop();
}
}
public interface LocalBindingContextExecutionContext {
EntitySource getEntitySource();
EntityBinding getEntityBinding();
EntityBinding getSuperEntityBinding();
}
private class LocalBindingContextExecutionContextImpl implements LocalBindingContextExecutionContext {
private final EntitySource entitySource;
private final EntityBinding superEntityBinding;
private LocalBindingContextExecutionContextImpl(
EntitySource entitySource,
EntityBinding superEntityBinding) {
this.entitySource = entitySource;
this.superEntityBinding = superEntityBinding;
}
@Override
public EntitySource getEntitySource() {
return entitySource;
}
@Override
public EntityBinding getEntityBinding() {
return metadata.getEntityBinding( entitySource.getEntityName() );
}
@Override
public EntityBinding getSuperEntityBinding() {
return superEntityBinding;
}
}
}

View File

@ -26,10 +26,8 @@ package org.hibernate.metamodel.internal;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.logging.Logger;
@ -42,6 +40,7 @@ import org.hibernate.metamodel.spi.source.ComponentAttributeSource;
import org.hibernate.metamodel.spi.source.EntitySource;
import org.hibernate.metamodel.spi.source.IdentifierSource;
import org.hibernate.metamodel.spi.source.NonAggregatedCompositeIdentifierSource;
import org.hibernate.metamodel.spi.source.PluralAttributeElementSourceResolver;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.RootEntitySource;
import org.hibernate.metamodel.spi.source.SimpleIdentifierSource;
@ -59,15 +58,21 @@ public class SourceIndex {
private final Map<String, EntitySourceIndex> entitySourceIndexByEntityName = new HashMap<String, EntitySourceIndex>();
private final Map<AttributeSourceKey, AttributeSource> attributeSourcesByKey = new HashMap<AttributeSourceKey, AttributeSource>();
private final Map<AttributeSourceKey, AttributeSourceKey> mappedByAttributeNamesByOwnerAttributeNames =
new HashMap<AttributeSourceKey, AttributeSourceKey>();
public void indexEntitySource(final EntitySource entitySource) {
String entityName = entitySource.getEntityName();
EntitySourceIndex entitySourceIndex = new EntitySourceIndex( entitySource );
EntitySourceIndex entitySourceIndex = new EntitySourceIndex( this, entitySource );
entitySourceIndexByEntityName.put( entityName, entitySourceIndex );
log.debugf( "Mapped entity source \"%s\"", entityName );
indexAttributes( entitySourceIndex );
}
public void resolveAssociationSources(String entityName) {
entitySourceIndexByEntityName.get( entityName ).resolveAssociationSources();
}
public Map<AttributeSourceKey, SingularAttributeSource> getSingularAttributeSources(
String entityName,
SingularAttributeSource.Nature nature) {
@ -75,10 +80,23 @@ public class SourceIndex {
return entitySourceIndex.getSingularAttributeSources( nature );
}
public Map<AttributeSourceKey, PluralAttributeSource> getPluralAttributeSources(
String entityName,
boolean isInverse) {
final EntitySourceIndex entitySourceIndex = entitySourceIndexByEntityName.get( entityName );
return entitySourceIndex.getPluralAttributeSources( isInverse );
}
public AttributeSource attributeSource(final String entityName, final String attributePath) {
return attributeSourcesByKey.get( new AttributeSourceKey( entityName, attributePath ) );
}
public AttributeSource locateAttributeSourceOwnedBy(final String entityName, final String attributePath) {
AttributeSourceKey ownerKey = new AttributeSourceKey( entityName, attributePath );
AttributeSourceKey mappedByKey = mappedByAttributeNamesByOwnerAttributeNames.get( ownerKey );
return mappedByKey == null ? null : attributeSourcesByKey.get( mappedByKey );
}
public EntitySource entitySource(final String entityName) {
return entitySourceIndexByEntityName.get( entityName ).entitySource;
}
@ -149,6 +167,14 @@ public class SourceIndex {
}
}
void addMappedByAssociationByOwnerAssociation(AttributeSourceKey ownerKey, AttributeSourceKey ownedKey) {
mappedByAttributeNamesByOwnerAttributeNames.put(
ownerKey,
ownedKey
);
}
public static class AttributeSourceKey {
private final String entityName;
@ -192,9 +218,13 @@ public class SourceIndex {
containerPath + '.' + attributeName;
}
public String getAttributePathQualifiedByEntityName() {
return entityName + '.' + attributePath();
}
@Override
public String toString() {
return entityName + '.' + attributePath();
return getAttributePathQualifiedByEntityName();
}
@Override
@ -231,30 +261,24 @@ public class SourceIndex {
}
private static class EntitySourceIndex {
private final SourceIndex sourceIndex;
private final EntitySource entitySource;
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> identifierAttributeSourcesByNature =
new HashMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>();
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> singularAttributeSourcesByNature =
new HashMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>();
private final Map<PluralAttributeSource.Nature, Set<PluralAttributeSource>> pluralAttributeSourcesByNature =
new HashMap<PluralAttributeSource.Nature, Set<PluralAttributeSource>>();
// TODO: the following should not need to be LinkedHashMap, but it appears that some unit tests
// depend on the ordering
private final Map<AttributeSourceKey, PluralAttributeSource> nonInversePluralAttributeSourcesByKey =
new LinkedHashMap<AttributeSourceKey, PluralAttributeSource>();
private final Map<AttributeSourceKey, PluralAttributeSource> inversePluralAttributeSourcesByKey =
new LinkedHashMap<AttributeSourceKey, PluralAttributeSource>();
private EntitySourceIndex(final EntitySource entitySource) {
private EntitySourceIndex(final SourceIndex sourceIndex, final EntitySource entitySource) {
this.sourceIndex = sourceIndex;
this.entitySource = entitySource;
}
private Map<AttributeSourceKey, SingularAttributeSource> getSingularAttributeSources(
SingularAttributeSource.Nature nature) {
final Map<AttributeSourceKey, SingularAttributeSource> entries;
if ( singularAttributeSourcesByNature.containsKey( nature ) ) {
entries = Collections.unmodifiableMap( singularAttributeSourcesByNature.get( nature ) );
}
else {
entries = Collections.emptyMap();
}
return entries;
}
private void indexSingularAttributeSource(
String pathBase,
SingularAttributeSource attributeSource,
@ -287,16 +311,28 @@ public class SourceIndex {
}
}
private void indexPluralAttributeSource(String pathBase, PluralAttributeSource attributeSource) {
final Set<PluralAttributeSource> pluralAttributeSources;
if ( pluralAttributeSourcesByNature.containsKey( attributeSource.getNature() ) ) {
pluralAttributeSources = pluralAttributeSourcesByNature.get( attributeSource.getNature() );
private Map<AttributeSourceKey, SingularAttributeSource> getSingularAttributeSources(
SingularAttributeSource.Nature nature) {
final Map<AttributeSourceKey, SingularAttributeSource> entries;
if ( singularAttributeSourcesByNature.containsKey( nature ) ) {
entries = Collections.unmodifiableMap( singularAttributeSourcesByNature.get( nature ) );
}
else {
pluralAttributeSources = new LinkedHashSet<PluralAttributeSource>();
pluralAttributeSourcesByNature.put( attributeSource.getNature(), pluralAttributeSources );
entries = Collections.emptyMap();
}
if ( !pluralAttributeSources.add( attributeSource ) ) {
return entries;
}
private void indexPluralAttributeSource(
String pathBase,
PluralAttributeSource attributeSource) {
AttributeSourceKey key =
new AttributeSourceKey( entitySource.getEntityName(), pathBase, attributeSource.getName() );
final Map<AttributeSourceKey,PluralAttributeSource> map =
attributeSource.isInverse() ?
inversePluralAttributeSourcesByKey :
nonInversePluralAttributeSourcesByKey;
if ( map.put( key, attributeSource ) != null ) {
throw new AssertionFailure(
String.format(
"Attempt to reindex attribute source for: [%s]",
@ -305,5 +341,37 @@ public class SourceIndex {
);
}
}
private Map<AttributeSourceKey, PluralAttributeSource> getPluralAttributeSources(
boolean isInverse) {
final Map<AttributeSourceKey,PluralAttributeSource> map =
isInverse ?
inversePluralAttributeSourcesByKey :
nonInversePluralAttributeSourcesByKey;
return Collections.unmodifiableMap( map );
}
private void resolveAssociationSources() {
for ( Map.Entry<AttributeSourceKey,PluralAttributeSource> entry : inversePluralAttributeSourcesByKey.entrySet() ) {
final AttributeSourceKey pluralAttributeSourceKey = entry.getKey();
final PluralAttributeSource pluralAttributeSource = entry.getValue();
if ( pluralAttributeSource.getMappedBy() != null ) {
pluralAttributeSource.resolvePluralAttributeElementSource(
new PluralAttributeElementSourceResolver.PluralAttributeElementSourceResolutionContext() {
@Override
public AttributeSource resolveAttributeSource(String referencedEntityName, String mappedBy) {
AttributeSourceKey ownerAttributeSourceKey = new AttributeSourceKey( referencedEntityName, mappedBy );
AttributeSource ownerAttributeSource = sourceIndex.attributeSource( referencedEntityName, mappedBy );
sourceIndex.addMappedByAssociationByOwnerAssociation(
ownerAttributeSourceKey,
pluralAttributeSourceKey
);
return ownerAttributeSource;
}
}
);
}
}
}
}
}