Skip to content

Commit

Permalink
OGM-469 Caching AssocationTypeContext instances in collection persister
Browse files Browse the repository at this point in the history
  • Loading branch information
gunnarmorling committed Oct 29, 2014
1 parent fedf0e6 commit 1ed111c
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 59 deletions.
Expand Up @@ -474,8 +474,7 @@ private TupleAsMapResultSet getResultSet(Serializable id, OgmLoadingContext ogmL
.gridDialect( gridDialect )
.key( id, persister.getKeyGridType() )
.associationKeyMetadata( persister.getAssociationKeyMetadata() )
// we can be on the main or on the inverse side, so we cannot simply use the unqualified role
.roleOnMainSide( persister.getMainSidePropertyName() )
.associationTypeContext( persister.getAssociationTypeContext() )
.session( session );

Association assoc = associationPersister.getAssociationOrNull();
Expand Down
Expand Up @@ -86,14 +86,14 @@ public static AssociationKeyMetadata getInverseAssociationKeyMetadata(OgmEntityP
}

/**
* Returns the meta-data for the inverse side of the given collection persister in case it represents the main side
* Returns the given collection persister for the inverse side in case the given persister represents the main side
* of a bi-directional many-to-many association.
*
* @param mainSidePersister the collection persister on the main side of a bi-directional many-to-many association
* @return the meta-data for the inverse side of the given collection persister or {@code null} in case it
* @return the collection persister for the inverse side of the given persister or {@code null} in case it
* represents the inverse side itself or the association is uni-directional
*/
public static AssociationKeyMetadata getInverseAssociationKeyMetadata(OgmCollectionPersister mainSidePersister) {
public static OgmCollectionPersister getInverseCollectionPersister(OgmCollectionPersister mainSidePersister) {
if ( mainSidePersister.isInverse() || !mainSidePersister.isManyToMany() || !mainSidePersister.getElementType().isEntityType() ) {
return null;
}
Expand All @@ -105,7 +105,7 @@ public static AssociationKeyMetadata getInverseAssociationKeyMetadata(OgmCollect
if ( type.isCollectionType() ) {
OgmCollectionPersister inverseCollectionPersister = getPersister( mainSidePersister.getFactory(), (CollectionType) type );
if ( isCollectionMatching( mainSidePersister, inverseCollectionPersister ) ) {
return inverseCollectionPersister.getAssociationKeyMetadata();
return inverseCollectionPersister;
}
}
}
Expand Down
Expand Up @@ -9,12 +9,16 @@
import java.io.Serializable;

import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.ogm.dialect.impl.AssociationTypeContextImpl;
import org.hibernate.ogm.dialect.spi.AssociationTypeContext;
import org.hibernate.ogm.dialect.spi.GridDialect;
import org.hibernate.ogm.model.impl.RowKeyBuilder;
import org.hibernate.ogm.model.key.spi.AssociationKeyMetadata;
import org.hibernate.ogm.model.key.spi.RowKey;
import org.hibernate.ogm.model.spi.Association;
import org.hibernate.ogm.model.spi.Tuple;
import org.hibernate.ogm.options.spi.OptionsService;
import org.hibernate.ogm.options.spi.OptionsService.OptionsServiceContext;
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.ogm.util.impl.AssociationPersister;
import org.hibernate.ogm.util.impl.CollectionHelper;
Expand Down Expand Up @@ -170,6 +174,17 @@ private void removeNavigationalInformationFromInverseSide(int propertyIndex, Ass
}

private AssociationPersister createAssociationPersister(int propertyIndex, AssociationKeyMetadata associationKeyMetadata, Object[] keyColumnValues) {
OptionsServiceContext serviceContext = session.getFactory()
.getServiceRegistry()
.getService( OptionsService.class )
.context();

AssociationTypeContext associationTypeContext = new AssociationTypeContextImpl(
serviceContext.getPropertyOptions( persister.getPropertyTypes()[propertyIndex].getReturnedClass(), associationKeyMetadata.getCollectionRole() ),
associationKeyMetadata.getAssociatedEntityKeyMetadata(),
persister.getPropertyNames()[propertyIndex]
);

return new AssociationPersister(
persister.getPropertyTypes()[propertyIndex].getReturnedClass()
)
Expand All @@ -178,7 +193,7 @@ private AssociationPersister createAssociationPersister(int propertyIndex, Assoc
.associationKeyMetadata( associationKeyMetadata )
.keyColumnValues( keyColumnValues )
.session( session )
.roleOnMainSide( persister.getPropertyNames()[propertyIndex] );
.associationTypeContext( associationTypeContext );
}

/**
Expand Down
Expand Up @@ -30,6 +30,7 @@
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.mapping.Collection;
import org.hibernate.ogm.dialect.impl.AssociationTypeContextImpl;
import org.hibernate.ogm.dialect.spi.AssociationContext;
import org.hibernate.ogm.dialect.spi.AssociationTypeContext;
import org.hibernate.ogm.dialect.spi.GridDialect;
import org.hibernate.ogm.jdbc.impl.TupleAsMapResultSet;
Expand All @@ -49,6 +50,7 @@
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.ogm.type.spi.TypeTranslator;
import org.hibernate.ogm.util.impl.AssociationPersister;
import org.hibernate.ogm.util.impl.Contracts;
import org.hibernate.ogm.util.impl.Log;
import org.hibernate.ogm.util.impl.LoggerFactory;
import org.hibernate.ogm.util.impl.LogicalPhysicalConverterHelper;
Expand Down Expand Up @@ -82,15 +84,21 @@ public class OgmCollectionPersister extends AbstractCollectionPersister implemen
private final String nodeName;

/**
* The {@link AssociationKeyMetadata} from the other side of this association in case it represents the main side of
* The {@link OgmCollectionPersister} from the other side of this association in case it represents the main side of
* a bi-directional many-to-many association, {@code null} otherwise.
*/
private volatile AssociationKeyMetadata inverseAssociationKeymetadata;
private OgmCollectionPersister inverseCollectionPersister;

/**
* The name of the main side property in case this is the inverse side of a one-to-many or many-to-many association.
*/
private volatile String mainSidePropertyName;
private String mainSidePropertyName;

/**
* A context to be passed (either directly or via {@link AssociationContext}) to grid dialect operations relating to
* the association managed by this persister.
*/
private AssociationTypeContext associationTypeContext;

public OgmCollectionPersister(final Collection collection, final CollectionRegionAccessStrategy cacheAccessStrategy, final Configuration cfg, final SessionFactoryImplementor factory)
throws MappingException, CacheException {
Expand Down Expand Up @@ -369,7 +377,7 @@ private static class RowKeyAndTuple {
}

// Centralize the RowKey column setting logic as the values settings are slightly different between insert / update and delete
public RowKeyBuilder initializeRowKeyBuilder() {
private RowKeyBuilder initializeRowKeyBuilder() {
RowKeyBuilder builder = new RowKeyBuilder();
if ( hasIdentifier ) {
builder.addColumns( getIdentifierColumnName() );
Expand Down Expand Up @@ -619,18 +627,11 @@ else if ( associationType == AssociationType.ASSOCIATION_TABLE_TO_ENTITY ) {
Object[] elementColumnValues = LogicalPhysicalConverterHelper.getColumnValuesFromResultset( associationRow, elementColumnNames );
Serializable entityId = (Serializable) gridTypeOfAssociatedId.nullSafeGet( associationRow, getElementColumnNames(), session, null );

if ( inverseAssociationKeymetadata == null ) {
if ( inverseCollectionPersister == null ) {
return;
}

AssociationPersister associationPersister = new AssociationPersister(
getElementPersister().getMappedClass()
)
.gridDialect( gridDialect )
.keyColumnValues( elementColumnValues )
.session( session )
.associationKeyMetadata( inverseAssociationKeymetadata )
.roleOnMainSide( getUnqualifiedRole() );
AssociationPersister associationPersister = inverseCollectionPersister.getAssociationPersister( null, elementColumnValues, session );

// TODO what happens when a row should be *updated* ?: I suspect ADD works OK as it's a put()
if ( action == Action.ADD ) {
Expand Down Expand Up @@ -669,7 +670,7 @@ else if ( action == Action.REMOVE ) {
}

private RowKey getInverseRowKey(Tuple associationRow) {
String[] inverseRowKeyColumnNames = inverseAssociationKeymetadata.getRowKeyColumnNames();
String[] inverseRowKeyColumnNames = inverseCollectionPersister.getAssociationKeyMetadata().getRowKeyColumnNames();
Object[] columnValues = new Object[inverseRowKeyColumnNames.length];

for ( int i = 0; i < inverseRowKeyColumnNames.length; i++ ) {
Expand Down Expand Up @@ -762,12 +763,14 @@ protected void logStaticSQL() {
public void postInstantiate() throws MappingException {
if ( isInverse ) {
mainSidePropertyName = BiDirectionalAssociationHelper.getMainSidePropertyName( this );
inverseAssociationKeymetadata = null;
inverseCollectionPersister = null;
}
else {
mainSidePropertyName = getUnqualifiedRole();
inverseAssociationKeymetadata = BiDirectionalAssociationHelper.getInverseAssociationKeyMetadata( this );
inverseCollectionPersister = BiDirectionalAssociationHelper.getInverseCollectionPersister( this );
}

associationTypeContext = getAssociationTypeContext( mainSidePropertyName );
}

@Override
Expand Down Expand Up @@ -809,7 +812,20 @@ public String getMainSidePropertyName() {
return mainSidePropertyName;
}

/**
* Returns the association type context providing meta-data to be passed to grid dialects when working on this
* association.
* <p>
* <b>Note:</b> Due to initialization order related constraints, this method may only be invoked after all
* collection and entity persisters have been set up. Use {@link #getAssociationTypeContext(String)} when in need of
* a context prior to that point.
*/
public AssociationTypeContext getAssociationTypeContext() {
Contracts.assertNotNull( associationTypeContext, "Association type context has not yet been initialized" );
return associationTypeContext;
}

public AssociationTypeContext getAssociationTypeContext(String mainSidePropertyName) {
OptionsServiceContext serviceContext = getFactory()
.getServiceRegistry()
.getService( OptionsService.class )
Expand All @@ -818,8 +834,8 @@ public AssociationTypeContext getAssociationTypeContext() {
AssociationTypeContext associationTypeContext = new AssociationTypeContextImpl(
serviceContext.getPropertyOptions( getOwnerEntityPersister().getMappedClass(), associationKeyMetadata.getCollectionRole() ),
associationKeyMetadata.getAssociatedEntityKeyMetadata(),
getMainSidePropertyName()
);
mainSidePropertyName
);

return associationTypeContext;
}
Expand All @@ -832,7 +848,19 @@ private AssociationPersister getAssociationPersister(Object collectionOwner, Ser
.gridDialect( gridDialect )
.key( id, getKeyGridType() )
.associationKeyMetadata( associationKeyMetadata )
.roleOnMainSide( mainSidePropertyName )
.associationTypeContext( associationTypeContext )
.session( session );
}

private AssociationPersister getAssociationPersister(Object collectionOwner, Object[] keyColumnValues, SessionImplementor session) {
return new AssociationPersister(
getOwnerEntityPersister().getMappedClass()
)
.hostingEntity( collectionOwner )
.gridDialect( gridDialect )
.keyColumnValues( keyColumnValues )
.associationKeyMetadata( associationKeyMetadata )
.associationTypeContext( associationTypeContext )
.session( session );
}
}
Expand Up @@ -43,8 +43,10 @@
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Table;
import org.hibernate.ogm.dialect.identity.spi.IdentityColumnAwareGridDialect;
import org.hibernate.ogm.dialect.impl.AssociationTypeContextImpl;
import org.hibernate.ogm.dialect.impl.TupleContextImpl;
import org.hibernate.ogm.dialect.optimisticlock.spi.OptimisticLockingAwareGridDialect;
import org.hibernate.ogm.dialect.spi.AssociationTypeContext;
import org.hibernate.ogm.dialect.spi.GridDialect;
import org.hibernate.ogm.dialect.spi.TupleContext;
import org.hibernate.ogm.entityentry.impl.OgmEntityEntryState;
Expand All @@ -60,6 +62,7 @@
import org.hibernate.ogm.model.spi.AssociationKind;
import org.hibernate.ogm.model.spi.Tuple;
import org.hibernate.ogm.options.spi.OptionsService;
import org.hibernate.ogm.options.spi.OptionsService.OptionsServiceContext;
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.ogm.type.spi.TypeTranslator;
import org.hibernate.ogm.util.impl.ArrayHelper;
Expand Down Expand Up @@ -600,14 +603,25 @@ public Object loadByUniqueKey(

OgmEntityPersister inversePersister = (OgmEntityPersister) ((EntityType) getPropertyTypes()[propertyIndex]).getAssociatedJoinable( session.getFactory() );

OptionsServiceContext serviceContext = session.getFactory()
.getServiceRegistry()
.getService( OptionsService.class )
.context();

AssociationTypeContext associationTypeContext = new AssociationTypeContextImpl(
serviceContext.getPropertyOptions( inversePersister.getMappedClass(), associationKeyMetadata.getCollectionRole() ),
associationKeyMetadata.getAssociatedEntityKeyMetadata(),
getPropertyNames()[propertyIndex]
);

AssociationPersister associationPersister = new AssociationPersister(
inversePersister.getMappedClass()
)
.gridDialect( gridDialect )
.key( uniqueKey, gridUniqueKeyType )
.associationKeyMetadata( associationKeyMetadata )
.session( session )
.roleOnMainSide( getPropertyNames()[propertyIndex] );
.associationTypeContext( associationTypeContext );

final Association ids = associationPersister.getAssociationOrNull();

Expand Down
Expand Up @@ -11,7 +11,6 @@
import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.ogm.dialect.impl.AssociationContextImpl;
import org.hibernate.ogm.dialect.impl.AssociationTypeContextImpl;
import org.hibernate.ogm.dialect.spi.AssociationContext;
import org.hibernate.ogm.dialect.spi.AssociationTypeContext;
import org.hibernate.ogm.dialect.spi.GridDialect;
Expand All @@ -20,8 +19,6 @@
import org.hibernate.ogm.model.key.spi.AssociationKeyMetadata;
import org.hibernate.ogm.model.key.spi.EntityKey;
import org.hibernate.ogm.model.spi.Association;
import org.hibernate.ogm.options.spi.OptionsService;
import org.hibernate.ogm.options.spi.OptionsService.OptionsServiceContext;
import org.hibernate.ogm.persister.impl.OgmEntityPersister;
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.persister.entity.EntityPersister;
Expand All @@ -44,7 +41,6 @@ public class AssociationPersister {
private Association association;
private Object[] columnValues;
private GridDialect gridDialect;
private String roleOnMainSide;
private AssociationContext associationContext;
private AssociationTypeContext associationTypeContext;
private AssociationKeyMetadata associationKeyMetadata;
Expand Down Expand Up @@ -92,8 +88,8 @@ public AssociationPersister hostingEntity(Object entity) {
return this;
}

public AssociationPersister roleOnMainSide(String roleOnMainSide) {
this.roleOnMainSide = roleOnMainSide;
public AssociationPersister associationTypeContext(AssociationTypeContext associationTypeContext) {
this.associationTypeContext = associationTypeContext;
return this;
}

Expand Down Expand Up @@ -202,7 +198,7 @@ private void updateHostingEntityIfRequired() {
*/
public boolean hostingEntityRequiresReadAfterUpdate() {
if ( hostingEntityRequiresReadAfterUpdate == null ) {
boolean storedInEntityStructure = gridDialect.isStoredInEntityStructure( associationKeyMetadata, getAssociationTypeContext() );
boolean storedInEntityStructure = gridDialect.isStoredInEntityStructure( associationKeyMetadata, associationTypeContext );
boolean hasUpdateGeneratedProperties = getHostingEntityPersister().hasUpdateGeneratedProperties();

hostingEntityRequiresReadAfterUpdate = storedInEntityStructure && hasUpdateGeneratedProperties;
Expand All @@ -225,28 +221,9 @@ private EntityPersister getHostingEntityPersister() {
*/
private AssociationContext getAssociationContext() {
if ( associationContext == null ) {
associationContext = new AssociationContextImpl(
getAssociationTypeContext()
);
associationContext = new AssociationContextImpl( associationTypeContext );
}

return associationContext;
}

private AssociationTypeContext getAssociationTypeContext() {
if ( associationContext == null ) {
OptionsServiceContext serviceContext = session.getFactory()
.getServiceRegistry()
.getService( OptionsService.class )
.context();

associationTypeContext = new AssociationTypeContextImpl(
serviceContext.getPropertyOptions( hostingEntityType, getAssociationKey().getMetadata().getCollectionRole() ),
associationKeyMetadata.getAssociatedEntityKeyMetadata(),
roleOnMainSide
);
}

return associationTypeContext;
}
}
Expand Up @@ -33,8 +33,8 @@ public class BiDirectionalAssociationHelperTest extends OgmTestCase {
@Test
public void inverseMetadataForUnidirectionalOneToManyShouldBeNull() {
OgmCollectionPersister persister = (OgmCollectionPersister) sessions.getCollectionPersister( Cloud.class.getName() + ".producedSnowFlakes" );
AssociationKeyMetadata inverseAssociationKeyMetadata = BiDirectionalAssociationHelper.getInverseAssociationKeyMetadata( persister );
assertThat( inverseAssociationKeyMetadata ).isNull();
OgmCollectionPersister inversePersister = BiDirectionalAssociationHelper.getInverseCollectionPersister( persister );
assertThat( inversePersister ).isNull();
}

@Test
Expand All @@ -47,10 +47,10 @@ public void canObtainInverseMetadataForBiDirectionalManyToOne() {
assertThat( inverseAssociationKeyMetadata.getColumnNames() ).isEqualTo( new String[]{ "salesForce_id" } );
assertThat( inverseAssociationKeyMetadata.getRowKeyColumnNames() ).isEqualTo( new String[]{ "salesForce_id", "id" } );

// no collection on the main side
// no persister on the main side
OgmCollectionPersister collectionPersister = (OgmCollectionPersister) sessions.getCollectionPersister( SalesForce.class.getName() + ".salesGuys" );
inverseAssociationKeyMetadata = BiDirectionalAssociationHelper.getInverseAssociationKeyMetadata( collectionPersister );
assertThat( inverseAssociationKeyMetadata ).isNull();
OgmCollectionPersister mainSidePersister = BiDirectionalAssociationHelper.getInverseCollectionPersister( collectionPersister );
assertThat( mainSidePersister ).isNull();
}

@Test
Expand Down

0 comments on commit 1ed111c

Please sign in to comment.