HHH-17619 Add the multitenancy filter in a stateless session
This commit is contained in:
parent
f5800a0388
commit
733b555e86
|
@ -29,7 +29,9 @@ import org.hibernate.SessionEventListener;
|
|||
import org.hibernate.SessionException;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.UnknownEntityTypeException;
|
||||
import org.hibernate.binder.internal.TenantIdBinder;
|
||||
import org.hibernate.cache.spi.CacheTransactionSynchronization;
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.engine.internal.SessionEventListenerManagerImpl;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
|
@ -38,6 +40,7 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
|||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.ExceptionConverter;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionEventListenerManager;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
@ -224,6 +227,24 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
&& ( (SharedSessionCreationOptions) options ).isTransactionCoordinatorShared();
|
||||
}
|
||||
|
||||
protected final void setUpMultitenancy(SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) {
|
||||
if ( factory.getDefinedFilterNames().contains( TenantIdBinder.FILTER_NAME ) ) {
|
||||
final Object tenantIdentifier = getTenantIdentifierValue();
|
||||
if ( tenantIdentifier == null ) {
|
||||
throw new HibernateException( "SessionFactory configured for multi-tenancy, but no tenant identifier specified" );
|
||||
}
|
||||
else {
|
||||
final CurrentTenantIdentifierResolver<Object> resolver = factory.getCurrentTenantIdentifierResolver();
|
||||
if ( resolver==null || !resolver.isRoot( tenantIdentifier ) ) {
|
||||
// turn on the filter, unless this is the "root" tenant with access to all partitions
|
||||
loadQueryInfluencers
|
||||
.enableFilter( TenantIdBinder.FILTER_NAME )
|
||||
.setParameter( TenantIdBinder.PARAMETER_NAME, tenantIdentifier );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void logInconsistentOptions(SharedSessionCreationOptions sharedOptions) {
|
||||
if ( sharedOptions.shouldAutoJoinTransactions() ) {
|
||||
log.debug(
|
||||
|
|
|
@ -49,9 +49,7 @@ import org.hibernate.TransientObjectException;
|
|||
import org.hibernate.TypeMismatchException;
|
||||
import org.hibernate.UnknownProfileException;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.binder.internal.TenantIdBinder;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.engine.internal.StatefulPersistenceContext;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.NonContextualLobCreator;
|
||||
|
@ -268,7 +266,7 @@ public class SessionImpl
|
|||
setHibernateFlushMode( getInitialFlushMode() );
|
||||
}
|
||||
|
||||
setUpMultitenancy( factory );
|
||||
setUpMultitenancy( factory, loadQueryInfluencers );
|
||||
|
||||
if ( log.isTraceEnabled() ) {
|
||||
log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), currentTimeMillis() );
|
||||
|
@ -283,24 +281,6 @@ public class SessionImpl
|
|||
: ConfigurationHelper.getFlushMode( getSessionProperty( HINT_FLUSH_MODE ), FlushMode.AUTO );
|
||||
}
|
||||
|
||||
private void setUpMultitenancy(SessionFactoryImplementor factory) {
|
||||
if ( factory.getDefinedFilterNames().contains( TenantIdBinder.FILTER_NAME ) ) {
|
||||
final Object tenantIdentifier = getTenantIdentifierValue();
|
||||
if ( tenantIdentifier == null ) {
|
||||
throw new HibernateException( "SessionFactory configured for multi-tenancy, but no tenant identifier specified" );
|
||||
}
|
||||
else {
|
||||
final CurrentTenantIdentifierResolver<Object> resolver = factory.getCurrentTenantIdentifierResolver();
|
||||
if ( resolver==null || !resolver.isRoot( tenantIdentifier ) ) {
|
||||
// turn on the filter, unless this is the "root" tenant with access to all partitions
|
||||
loadQueryInfluencers
|
||||
.enableFilter( TenantIdBinder.FILTER_NAME )
|
||||
.setParameter( TenantIdBinder.PARAMETER_NAME, tenantIdentifier );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected StatefulPersistenceContext createPersistenceContext() {
|
||||
return new StatefulPersistenceContext( this );
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
connectionProvided = options.getConnection() != null;
|
||||
temporaryPersistenceContext = new StatefulPersistenceContext( this );
|
||||
influencers = new LoadQueryInfluencers( getFactory() );
|
||||
setUpMultitenancy( factory, influencers );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.orm.test.tenantid;
|
|||
|
||||
import org.hibernate.HibernateError;
|
||||
import org.hibernate.PropertyValueException;
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
|
@ -20,6 +21,9 @@ import org.hibernate.testing.orm.junit.SessionFactoryProducer;
|
|||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.hibernate.binder.internal.TenantIdBinder;
|
||||
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||
import org.hibernate.query.criteria.JpaCriteriaQuery;
|
||||
import org.hibernate.query.criteria.JpaRoot;
|
||||
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -28,6 +32,7 @@ import org.junit.jupiter.api.Test;
|
|||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION;
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.toMap;
|
||||
import static org.hibernate.jpa.HibernateHints.HINT_TENANT_ID;
|
||||
|
@ -37,6 +42,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SessionFactory
|
||||
@DomainModel(annotatedClasses = { Account.class, Client.class, Record.class })
|
||||
@ServiceRegistry(
|
||||
|
@ -53,6 +60,7 @@ public class TenantIdTest implements SessionFactoryProducer {
|
|||
scope.inTransaction( session -> {
|
||||
session.createQuery("delete from Account").executeUpdate();
|
||||
session.createQuery("delete from Client").executeUpdate();
|
||||
session.createQuery("delete from Record").executeUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -217,6 +225,34 @@ public class TenantIdTest implements SessionFactoryProducer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void tenantFilterWithStatelessSession(SessionFactoryScope scope) {
|
||||
currentTenant = "mine";
|
||||
Record myRecord1 = new Record();
|
||||
Record myRecord2 = new Record();
|
||||
|
||||
scope.inTransaction( session -> {
|
||||
session.persist(myRecord1);
|
||||
session.persist(myRecord2);
|
||||
} );
|
||||
scope.inStatelessTransaction( session -> {
|
||||
assertThat( listAllRecordsForTenant( session ) ).hasSize( 2 );
|
||||
} );
|
||||
|
||||
currentTenant = "yours";
|
||||
scope.inStatelessTransaction( session -> {
|
||||
assertThat( listAllRecordsForTenant( session ) ).isEmpty();
|
||||
} );
|
||||
}
|
||||
|
||||
private static List<Record> listAllRecordsForTenant(StatelessSession session) {
|
||||
HibernateCriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
|
||||
JpaCriteriaQuery<Record> criteriaQuery = criteriaBuilder.createQuery( Record.class );
|
||||
JpaRoot<Record> from = criteriaQuery.from( Record.class );
|
||||
return session.createQuery( criteriaQuery ).getResultList();
|
||||
}
|
||||
|
||||
private static void waitALittle() {
|
||||
try {
|
||||
Thread.sleep( 10 );
|
||||
|
|
Loading…
Reference in New Issue