Skip to content

Commit

Permalink
HHH-8056 : Create EntityHierarchyHelper to handle processing an Entit…
Browse files Browse the repository at this point in the history
…yHierarchy
  • Loading branch information
gbadner committed May 21, 2013
1 parent 9a02c9e commit c0fa635
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 18 deletions.
Expand Up @@ -227,6 +227,9 @@ public Binder(final MetadataImplementor metadata,
/**
* The entry point of {@linkplain Binder} class, adds all the entity hierarchy one by one.
*
* Indexes all {@link EntitySource} objects in an {@link EntityHierarchy} and
* creates all {@link EntityBinding}.
*
* @param entityHierarchies The entity hierarchies resolved from mappings
*/
public void addEntityHierarchies(final Iterable<EntityHierarchy> entityHierarchies) {
Expand All @@ -250,31 +253,45 @@ public void execute(LocalBindingContextExecutionContext bindingContextContext) {
}

public void bindEntityHierarchies() {

// Bind everything except for (non-ID) attributes.
// Need to bind ID attributes before resolving associations.
// TODO: when we know the proper order for processing entity hierarchies,
// then applyToAllEntityHierarchies(...) can replace the following method.
bindEntityHierarchiesExcludingNonIdAttributeBindings();

// cannot resolve associations until after entity identifiers are defined.
// Resolve associations:
// - determine if JPA @OneToOne translates to Hibernate's one-to-one or unique many-to-one;
// - determine if JPA @OneToMany translates to Hibernate's one-to-many or unique many-to-many.
applyToAllEntityHierarchies( resolveAssociationSourcesExecutor() );

// At this point, SourceIndex has all necessary information.

// Bind all composite attribute containers. This excludes composite sub-attributes.
applyToAllEntityHierarchies( bindSingularAttributesExecutor( SingularAttributeSource.Nature.COMPOSITE ) );

// bind singular attributes
// bind basic singular attributes, including composite sub-attributes that are basic.
applyToAllEntityHierarchies( bindSingularAttributesExecutor( SingularAttributeSource.Nature.BASIC ) );
// do many-to-one before one-to-one

// many-to-one needs to be bound before one-to-one (um, can't remember why).

// bind many-to-one attributes, including composite sub-attributes that are many-to-one.
applyToAllEntityHierarchies( bindSingularAttributesExecutor( SingularAttributeSource.Nature.MANY_TO_ONE ) );

// bind one-to-one attributes, including composite sub-attributes that are one-to-one.
applyToAllEntityHierarchies( bindSingularAttributesExecutor( SingularAttributeSource.Nature.ONE_TO_ONE ) );

// bind plural attributes (non-mappedBy first).
// bind plural attributes (non-mappedBy first), including composite sub-attributes that are plural
applyToAllEntityHierarchies( bindPluralAttributesExecutor( false ) );
applyToAllEntityHierarchies( bindPluralAttributesExecutor( true ) );

// Bind unique constraints after all attributes have been bound.
// TODO: Add impl note about why...
// Bind unique constraints after all attributes have been bound and the
// columns used by attributes is already determined.
applyToAllEntityHierarchies( bindUniqueConstraintsExecutor() );

// TODO: check if any many-to-one attribute bindings with logicalOneToOne == false have all columns
// (and no formulas) contained in a defined unique key that only contains these columns.
// if so, mark the many-to-one as a logical one-to-one.
// TODO: when does this have to be done.
}

private InheritanceType inheritanceType() {
Expand Down Expand Up @@ -336,6 +353,10 @@ public void execute(LocalBindingContextExecutionContext bindingContextContext) {
bindSecondaryTables( entityBinding, entitySource );
}
};
// TODO: need to determine the proper order for processing EntityHierarchy objects
// so that dependent EntityHierarchy is processed after the EntityHierarchy it
// is dependent on.
// For now, just delay processing the dependent entity hierarchies.
Set<EntityHierarchy> unresolvedEntityHierarchies = new HashSet<EntityHierarchy>( );
for ( final EntityHierarchy entityHierarchy : entityHierarchiesByRootEntityName.values() ) {
if ( isIdentifierDependentOnOtherEntityHierarchy( entityHierarchy ) ) {
Expand All @@ -346,6 +367,11 @@ public void execute(LocalBindingContextExecutionContext bindingContextContext) {
}
}

// The following is to try to resolve any dependent entity hierarchies.
// It runs through all the dependent entity hierarchies and resolves what it can.
// This process repeats until no more can be resolved.
// TODO: this will not be necessary once we know the proper order for
// processing entity hierarchies.
int oldSize = Integer.MAX_VALUE;
while( !unresolvedEntityHierarchies.isEmpty() && unresolvedEntityHierarchies.size() < oldSize ) {
oldSize = unresolvedEntityHierarchies.size();
Expand All @@ -361,11 +387,14 @@ public void execute(LocalBindingContextExecutionContext bindingContextContext) {
}
}
}
// If any entity hierarchies cannot be resolved, then throw exception.
if ( ! unresolvedEntityHierarchies.isEmpty() ) {
throw new IllegalStateException( "could not resolve all EntityHierarchies." );
}
}

// TODO: this will not be necessary once we know the proper order for
// processing entity hierarchies.
private boolean isIdentifierDependentOnOtherEntityHierarchy(EntityHierarchy entityHierarchy) {
final RootEntitySource rootEntitySource = entityHierarchy.getRootEntitySource();
final IdentifierSource identifierSource = rootEntitySource.getIdentifierSource();
Expand All @@ -381,6 +410,8 @@ private boolean isIdentifierDependentOnOtherEntityHierarchy(EntityHierarchy enti
}
}

// TODO: this will not be necessary once we know the proper order for
// processing entity hierarchies.
private boolean containsSingularAssociation(List<? extends AttributeSource> subAttributeSources) {
for ( AttributeSource attributeSource : subAttributeSources ) {
SingularAttributeSource singularAttributeSource = (SingularAttributeSource) attributeSource;
Expand Down Expand Up @@ -424,9 +455,11 @@ public void execute(LocalBindingContextExecutionContext bindingContextContext) {
};
}

// TODO: create separate methods that are more clear for the cases.
private void bindSingularAttributes(
final EntityBinding entityBinding,
final SingularAttributeSource.Nature nature) {
// Get the map of all attributes for the entity binding of the specified nature.
Map<SourceIndex.AttributeSourceKey, SingularAttributeSource> map = sourceIndex.getSingularAttributeSources(
entityBinding.getEntityName(),
nature
Expand All @@ -437,6 +470,7 @@ private void bindSingularAttributes(
final AttributeBindingContainer attributeBindingContainer =
locateAttributeBindingContainer( entityBinding, attributeSourceKey.containerPath() );
if ( nature == SingularAttributeSource.Nature.COMPOSITE ) {
// This only creates the composite attribute container.
createAggregatedCompositeAttribute(
attributeBindingContainer,
(ComponentAttributeSource) attributeSource,
Expand All @@ -457,35 +491,45 @@ else if ( attributeBindingContainer instanceof CompositeAttributeBinding ) {
}
}
else {
// The container is the EntityBinding itself.
bindAttribute( attributeBindingContainer, attributeSource );
}
}
}

// All sub-attributes must be bound before it's type and ComponentMetamodel can be determined.
private void completeCompositeAttributeBindingIfPossible(
CompositeAttributeBinding compositeAttributeBinding,
ComponentAttributeSource compositeAttributeSource
) {
// Find out the number of sub-attributes, excluding the parent attribute.
final int nAttributeSourcesExcludingParent =
compositeAttributeBinding.getParentReference() != null ?
compositeAttributeSource.attributeSources().size() - 1 :
compositeAttributeSource.attributeSources().size();
if ( compositeAttributeBinding.attributeBindingSpan() == nAttributeSourcesExcludingParent ) {
// All sub-attribute bindings are present; now check if all sub-attributes have
// their type resolved.
boolean allResolved = true;
for ( AttributeBinding attributeBinding : compositeAttributeBinding.attributeBindings() ) {
if ( attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() == null ) {
// Something is not resolved.
allResolved = false;
break;
}
}
if ( allResolved ) {
// All are resolved, so we can bind the type.
typeHelper.bindAggregatedCompositeAttributeType(
false,
(Aggregate) compositeAttributeBinding.getAttribute().getSingularAttributeType(),
null, // TODO: don't have the default value at this point; shouldn't be needed...
compositeAttributeBinding
);
// Now check the container.
if ( compositeAttributeBinding.getContainer() instanceof CompositeAttributeBindingContainer ) {
// The container is also a CompositeAttributeBindingContainer.
// We need this process for the container.
final CompositeAttributeBinding parentCompositeAttributeBinding =
(CompositeAttributeBinding) compositeAttributeBinding.seekEntityBinding().locateAttributeBinding(
( compositeAttributeBinding.getContainer() ).getPathBase()
Expand Down Expand Up @@ -517,27 +561,32 @@ public void execute(LocalBindingContextExecutionContext bindingContextContext) {
};
}

// TODO: may want bind plural attributes of a particular element nature.
private void bindPluralAttributes(
final EntityBinding entityBinding,
final EntitySource entitySource,
final boolean isInverse) {
// Get the map for inverse or non-inverse (as specified) plural attributes
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();
// Bind the attribute into the appropriate container.
final AttributeBindingContainer attributeBindingContainer =
locateAttributeBindingContainer( entityBinding, attributeSourceKey.containerPath() );
bindAttribute( attributeBindingContainer, attributeSource );
if ( attributeBindingContainer instanceof CompositeAttributeBinding ) {
// We just bound a sub-attribute into a CompositeAttributeBinding.
final CompositeAttributeBinding compositeAttributeBinding = (CompositeAttributeBinding) attributeBindingContainer;
final ComponentAttributeSource compositeAttributeSource =
(ComponentAttributeSource) sourceIndex.attributeSource(
entityBinding.getEntityName(),
compositeAttributeBinding.getPathBase()
);
// Resolve the type if types are resolved for all sub-attributes now.
completeCompositeAttributeBindingIfPossible( compositeAttributeBinding, compositeAttributeSource );
}
}
Expand Down
Expand Up @@ -70,6 +70,10 @@ public void applyToAllEntityHierarchies(
* Apply executors to a single entity hierarchy.
*
* @param entityHierarchy The entity hierarchy to be binded.
* @param rootEntityExecutor The executor to be applied to the root {@link EntitySource}
* in the entity hierarchy.
* @param subEntityExecutor The executer to be applied to each {@link SubclassEntitySource}
* in the entity hierarchy.
*/
public void applyToEntityHierarchy(
final EntityHierarchy entityHierarchy,
Expand Down
Expand Up @@ -473,6 +473,7 @@ public void registerIdentifierGenerator(String name, String generatorClassName)

private void processMappings(MetadataSourceProcessor[] metadataSourceProcessors) {
final Binder binder = new Binder( this, identifierGeneratorFactory );
// Add all hierarchies first, before binding.
for ( MetadataSourceProcessor processor : metadataSourceProcessors ) {
binder.addEntityHierarchies( processor.extractEntityHierarchies() );
}
Expand Down
Expand Up @@ -63,7 +63,7 @@ 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 =
private final Map<AttributeSourceKey, AttributeSourceKey> mappedByAttributeKeysByOwnerAttributeKeys =
new HashMap<AttributeSourceKey, AttributeSourceKey>();

public void indexEntitySource(final EntitySource entitySource) {
Expand Down Expand Up @@ -98,7 +98,7 @@ public AttributeSource attributeSource(final String entityName, final String att

public AttributeSource locateAttributeSourceOwnedBy(final String entityName, final String attributePath) {
AttributeSourceKey ownerKey = new AttributeSourceKey( entityName, attributePath );
AttributeSourceKey mappedByKey = mappedByAttributeNamesByOwnerAttributeNames.get( ownerKey );
AttributeSourceKey mappedByKey = mappedByAttributeKeysByOwnerAttributeKeys.get( ownerKey );
return mappedByKey == null ? null : attributeSourcesByKey.get( mappedByKey );
}

Expand Down Expand Up @@ -173,7 +173,7 @@ private void indexAttributeSources(
}

void addMappedByAssociationByOwnerAssociation(AttributeSourceKey ownerKey, AttributeSourceKey ownedKey) {
mappedByAttributeNamesByOwnerAttributeNames.put(
mappedByAttributeKeysByOwnerAttributeKeys.put(
ownerKey,
ownedKey
);
Expand Down Expand Up @@ -270,10 +270,12 @@ private static class EntitySourceIndex {
private final EntitySource entitySource;
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> identifierAttributeSourcesByNature =
new HashMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>();
// TODO: split out inverse and non-inverse SingularAttributeSource maps.
private final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> singularAttributeSourcesByNature =
new HashMap<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>>();
// TODO: the following should not need to be LinkedHashMap, but it appears that some unit tests
// depend on the ordering
// TODO: rework nonInversePluralAttributeSourcesByKey and inversePluralAttributeSourcesByKey
private final Map<AttributeSourceKey, PluralAttributeSource> nonInversePluralAttributeSourcesByKey =
new LinkedHashMap<AttributeSourceKey, PluralAttributeSource>();
private final Map<AttributeSourceKey, PluralAttributeSource> inversePluralAttributeSourcesByKey =
Expand Down Expand Up @@ -364,16 +366,21 @@ private Map<AttributeSourceKey, PluralAttributeSource> getPluralAttributeSources
}

private void resolveAssociationSources(final EntityBinding entityBinding) {
// Cycle through non-inverse plural attributes.
for ( Map.Entry<AttributeSourceKey,PluralAttributeSource> entry : inversePluralAttributeSourcesByKey.entrySet() ) {
final AttributeSourceKey pluralAttributeSourceKey = entry.getKey();
final PluralAttributeSource pluralAttributeSource = entry.getValue();
if ( pluralAttributeSource.getMappedBy() != null ) {
// This plural attribute is mappedBy the opposite side of the association,
// so it needs to be resolved.
// TODO: this should really just resolve PluralAttributeElementSource.Nature
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 );
// TODO: is this needed? if so, make more obvious and rename method.
sourceIndex.addMappedByAssociationByOwnerAssociation(
ownerAttributeSourceKey,
pluralAttributeSourceKey
Expand All @@ -387,6 +394,8 @@ public AttributeSource resolveAttributeSource(String referencedEntityName, Strin
final Map<AttributeSourceKey,SingularAttributeSource> unresolvedSingularAttributeSourceMap =
singularAttributeSourcesByNature.get( null );
if ( unresolvedSingularAttributeSourceMap != null ) {
// cycle through unresolved SingularAttributeSource.
// TODO: rework so approach is similar to one-to-many/many-to-many resolution.
for ( Iterator<Map.Entry<AttributeSourceKey,SingularAttributeSource>> it = unresolvedSingularAttributeSourceMap.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<AttributeSourceKey,SingularAttributeSource> entry = it.next();
final AttributeSourceKey attributeSourceKey = entry.getKey();
Expand Down
Expand Up @@ -79,7 +79,7 @@ public PluralAttributeSourceImpl(
this.nature = associationAttribute.getPluralAttributeNature();
if ( associationAttribute.getMappedBy() == null ) {
this.ownerAttributeSource = this;
this.elementSource = determineOwnerElementSource( this, associationAttribute, entityClass );
this.elementSource = determineElementSource( this, associationAttribute, entityClass );
}
this.filterSources = determineFilterSources(associationAttribute);
}
Expand Down Expand Up @@ -166,7 +166,7 @@ public ValueHolder<Class<?>> getElementClassReference() {
}
}

private static PluralAttributeElementSource determineOwnerElementSource(
private static PluralAttributeElementSource determineElementSource(
AttributeSource ownerAttributeSource,
PluralAssociationAttribute associationAttribute,
ConfiguredClass entityClass) {
Expand Down Expand Up @@ -353,17 +353,18 @@ public FetchStyle getFetchStyle() {
@Override
public PluralAttributeElementSource resolvePluralAttributeElementSource(
PluralAttributeElementSourceResolutionContext context) {
if ( associationAttribute.getMappedBy() == null ) {
return elementSource;
}
else {
if ( elementSource == null ) {
// elementSource has not been initialized, so we need to resolve it using the
// association owner.
// Get the owner attribute source that maps the opposite side of the association.
ownerAttributeSource = context.resolveAttributeSource(
associationAttribute.getReferencedEntityType(),
associationAttribute.getMappedBy()
);
elementSource = determineOwnerElementSource( ownerAttributeSource, associationAttribute, entityClass );
return elementSource;
// Initialize resolved entitySource.
elementSource = determineElementSource( ownerAttributeSource, associationAttribute, entityClass );
}
return elementSource;
}
}

Expand Down
Expand Up @@ -165,6 +165,7 @@ else if ( pluralAttributeElement.getManyToAny() != null ) {

@Override
public PluralAttributeElementSource resolvePluralAttributeElementSource(PluralAttributeElementSourceResolutionContext context) {
// elementSource is already resolved; nothing to do.
return elementSource;
}

Expand Down

0 comments on commit c0fa635

Please sign in to comment.