Skip to content

Commit 7c315fd

Browse files
quaffbeikov
authored andcommitted
HHH-15422 Pick up CurrentTenantIdentifierResolver and MultiTenantConnectionProvider from BeanContainer if not explicit set
1 parent 8ca2481 commit 7c315fd

13 files changed

+432
-15
lines changed

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@
6363
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
6464
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
6565
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
66+
import org.hibernate.resource.beans.container.spi.BeanContainer;
67+
import org.hibernate.resource.beans.internal.Helper;
68+
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
69+
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
6670
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
6771
import org.hibernate.resource.jdbc.spi.StatementInspector;
6872
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
@@ -283,6 +287,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
283287
private final int queryStatisticsMaxSize;
284288

285289

290+
@SuppressWarnings( "unchecked" )
286291
public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, BootstrapContext context) {
287292
this.serviceRegistry = serviceRegistry;
288293
this.jpaBootstrap = context.isJpaBootstrap();
@@ -372,6 +377,38 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo
372377
CurrentTenantIdentifierResolver.class,
373378
configurationSettings.get( MULTI_TENANT_IDENTIFIER_RESOLVER )
374379
);
380+
if ( this.currentTenantIdentifierResolver == null ) {
381+
final BeanContainer beanContainer = Helper.allowExtensionsInCdi( serviceRegistry ) ? serviceRegistry.requireService( ManagedBeanRegistry.class ).getBeanContainer() : null;
382+
if (beanContainer != null) {
383+
this.currentTenantIdentifierResolver = beanContainer.getBean(
384+
CurrentTenantIdentifierResolver.class,
385+
new BeanContainer.LifecycleOptions() {
386+
@Override
387+
public boolean canUseCachedReferences() {
388+
return true;
389+
}
390+
391+
@Override
392+
public boolean useJpaCompliantCreation() {
393+
return false;
394+
}
395+
},
396+
new BeanInstanceProducer() {
397+
398+
@Override
399+
public <B> B produceBeanInstance(Class<B> beanType) {
400+
return null;
401+
}
402+
403+
@Override
404+
public <B> B produceBeanInstance(String name, Class<B> beanType) {
405+
return null;
406+
}
407+
408+
}
409+
).getBeanInstance();
410+
}
411+
}
375412

376413
this.delayBatchFetchLoaderCreations = configurationService.getSetting( DELAY_ENTITY_LOADER_CREATIONS, BOOLEAN, true );
377414
this.defaultBatchFetchSize = getInt( DEFAULT_BATCH_FETCH_SIZE, configurationSettings, -1 );

hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/internal/MultiTenantConnectionProviderInitiator.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
import org.hibernate.cfg.AvailableSettings;
1313
import org.hibernate.engine.jdbc.connections.spi.DataSourceBasedMultiTenantConnectionProviderImpl;
1414
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
15+
import org.hibernate.resource.beans.container.spi.BeanContainer;
16+
import org.hibernate.resource.beans.internal.Helper;
17+
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
18+
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
1519
import org.hibernate.service.spi.ServiceException;
1620
import org.hibernate.service.spi.ServiceRegistryImplementor;
1721

@@ -39,7 +43,36 @@ public Class<MultiTenantConnectionProvider<?>> getServiceInitiated() {
3943
@Override
4044
public MultiTenantConnectionProvider<?> initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
4145
if ( !configurationValues.containsKey( AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER ) ) {
42-
// nothing to do, but given the separate hierarchies have to handle this here.
46+
final BeanContainer beanContainer = Helper.allowExtensionsInCdi( registry ) ? registry.requireService( ManagedBeanRegistry.class ).getBeanContainer() : null;
47+
if (beanContainer != null) {
48+
return beanContainer.getBean(
49+
MultiTenantConnectionProvider.class,
50+
new BeanContainer.LifecycleOptions() {
51+
@Override
52+
public boolean canUseCachedReferences() {
53+
return true;
54+
}
55+
56+
@Override
57+
public boolean useJpaCompliantCreation() {
58+
return true;
59+
}
60+
},
61+
new BeanInstanceProducer() {
62+
63+
@Override
64+
public <B> B produceBeanInstance(Class<B> beanType) {
65+
return null;
66+
}
67+
68+
@Override
69+
public <B> B produceBeanInstance(String name, Class<B> beanType) {
70+
return null;
71+
}
72+
73+
}
74+
).getBeanInstance();
75+
}
4376
return null;
4477
}
4578

hibernate-core/src/test/java/org/hibernate/orm/test/idgen/userdefined/SimpleBeanContainer.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
1212

1313
/**
14-
*
14+
* @author Yanming Zhou
1515
*/
1616
@SuppressWarnings("unchecked")
1717
public class SimpleBeanContainer implements BeanContainer {
@@ -23,10 +23,8 @@ public <B> ContainedBean<B> getBean(
2323
Class<B> beanType,
2424
LifecycleOptions lifecycleOptions,
2525
BeanInstanceProducer fallbackProducer) {
26-
if ( beanType == SimpleGenerator.class ) {
27-
return () -> (B) new SimpleGenerator( new AtomicLong( INITIAL_VALUE ) );
28-
}
29-
return null;
26+
return () -> (B) ( beanType == SimpleGenerator.class ?
27+
new SimpleGenerator( new AtomicLong( INITIAL_VALUE ) ) : fallbackProducer.produceBeanInstance( beanType ) );
3028
}
3129

3230
@Override

hibernate-core/src/test/java/org/hibernate/orm/test/idgen/userdefined/UserDefinedGeneratorsTests.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.hibernate.resource.beans.container.spi.BeanContainer.LifecycleOptions;
2525
import org.hibernate.resource.beans.container.spi.ContainedBean;
2626
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
27+
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
2728

2829
import org.hibernate.testing.orm.junit.JiraKey;
2930
import org.hibernate.testing.orm.junit.BaseUnitTest;
@@ -39,7 +40,7 @@
3940

4041
import static org.hamcrest.CoreMatchers.instanceOf;
4142
import static org.hamcrest.CoreMatchers.is;
42-
import static org.junit.Assert.assertThat;
43+
import static org.hamcrest.MatcherAssert.assertThat;
4344
import static org.mockito.ArgumentMatchers.any;
4445
import static org.mockito.ArgumentMatchers.same;
4546
import static org.mockito.BDDMockito.given;
@@ -59,10 +60,16 @@ public void testCreateGeneratorsByBeanContainer() {
5960

6061
final BeanContainer beanContainer = Mockito.mock( BeanContainer.class );
6162
given(beanContainer.getBean( any(), any(), any() ) ).willAnswer( invocation -> {
63+
Class<?> beanType = (Class<?>) invocation.getArguments()[0];
6264
LifecycleOptions options = (LifecycleOptions) invocation.getArguments()[1];
63-
assertThat( options.canUseCachedReferences(), is( false ) );
64-
assertThat( options.useJpaCompliantCreation(), is( true ) );
65-
return (ContainedBean<?>) TestIdentifierGenerator::new;
65+
if (beanType == TestIdentifierGenerator.class) {
66+
assertThat( options.canUseCachedReferences(), is( false ) );
67+
assertThat( options.useJpaCompliantCreation(), is( true ) );
68+
return (ContainedBean<?>) TestIdentifierGenerator::new;
69+
}
70+
else {
71+
return (ContainedBean<?>) () -> ( ( BeanInstanceProducer ) invocation.getArguments()[2] ).produceBeanInstance( beanType );
72+
}
6673
} );
6774

6875
final StandardServiceRegistryBuilder ssrb = ServiceRegistryUtil.serviceRegistryBuilder();

hibernate-core/src/test/java/org/hibernate/orm/test/multitenancy/AbstractMultiTenancyTest.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ public abstract class AbstractMultiTenancyTest extends BaseUnitTestCase {
5555
protected static final String FRONT_END_TENANT = "front_end";
5656
protected static final String BACK_END_TENANT = "back_end";
5757

58-
private Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>();
58+
protected Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>();
5959

60-
private SessionFactory sessionFactory;
60+
protected SessionFactory sessionFactory;
6161

6262
public AbstractMultiTenancyTest() {
6363
init();
@@ -67,13 +67,15 @@ public AbstractMultiTenancyTest() {
6767
private void init() {
6868
registerConnectionProvider(FRONT_END_TENANT);
6969
registerConnectionProvider(BACK_END_TENANT);
70+
sessionFactory = sessionFactory(createSettings());
71+
}
7072

73+
protected Map<String, Object> createSettings() {
7174
Map<String, Object> settings = new HashMap<>();
7275

7376
settings.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER,
74-
new ConfigurableMultiTenantConnectionProvider(connectionProviderMap));
75-
76-
sessionFactory = sessionFactory(settings);
77+
new ConfigurableMultiTenantConnectionProvider(connectionProviderMap));
78+
return settings;
7779
}
7880
//end::multitenacy-hibernate-MultiTenantConnectionProvider-example[]
7981

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.multitenancy.beancontainer;
6+
7+
import org.hibernate.testing.orm.junit.DomainModel;
8+
import org.hibernate.testing.orm.junit.JiraKey;
9+
import org.hibernate.testing.orm.junit.SessionFactory;
10+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
11+
import org.junit.jupiter.api.Test;
12+
13+
import static org.hamcrest.CoreMatchers.is;
14+
import static org.hamcrest.MatcherAssert.assertThat;
15+
16+
/**
17+
* @author Yanming Zhou
18+
*/
19+
@JiraKey("HHH-15422")
20+
@SessionFactory
21+
@DomainModel(annotatedClasses = TestEntity.class)
22+
abstract class AbstractTenantResolverBeanContainerTest {
23+
24+
@Test
25+
void tentantIdShouldBeFilled(SessionFactoryScope scope) {
26+
scope.inTransaction( s -> {
27+
TestEntity entity = new TestEntity();
28+
s.persist( entity );
29+
s.flush();
30+
assertThat( entity.getTenant(), is( TestCurrentTenantIdentifierResolver.FIXED_TENANT ) );
31+
} );
32+
}
33+
34+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.multitenancy.beancontainer;
6+
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
10+
import org.hibernate.cfg.AvailableSettings;
11+
import org.hibernate.dialect.H2Dialect;
12+
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
13+
import org.hibernate.internal.SessionFactoryImpl;
14+
import org.hibernate.orm.test.multitenancy.AbstractMultiTenancyTest;
15+
import org.hibernate.orm.test.multitenancy.ConfigurableMultiTenantConnectionProvider;
16+
import org.hibernate.resource.beans.container.spi.BeanContainer;
17+
import org.hibernate.resource.beans.container.spi.ContainedBean;
18+
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
19+
20+
import org.hibernate.testing.orm.junit.RequiresDialect;
21+
import org.junit.Test;
22+
23+
import static org.junit.Assert.assertSame;
24+
25+
/**
26+
* @author Yanming Zhou
27+
*/
28+
@RequiresDialect(H2Dialect.class)
29+
public class MultiTenantConnectionProviderFromBeanContainerTest extends AbstractMultiTenancyTest {
30+
31+
private ConfigurableMultiTenantConnectionProvider providerFromBeanContainer;
32+
33+
@Override
34+
protected Map<String, Object> createSettings() {
35+
Map<String, Object> settings = new HashMap<>();
36+
37+
providerFromBeanContainer = new ConfigurableMultiTenantConnectionProvider( connectionProviderMap);
38+
settings.put( AvailableSettings.ALLOW_EXTENSIONS_IN_CDI, "true" );
39+
settings.put( AvailableSettings.BEAN_CONTAINER, new BeanContainer() {
40+
@Override
41+
@SuppressWarnings("unchecked")
42+
public <B> ContainedBean<B> getBean(
43+
Class<B> beanType,
44+
LifecycleOptions lifecycleOptions,
45+
BeanInstanceProducer fallbackProducer) {
46+
return () -> (B) ( beanType == MultiTenantConnectionProvider.class ? providerFromBeanContainer : fallbackProducer.produceBeanInstance( beanType ) );
47+
}
48+
49+
@Override
50+
public <B> ContainedBean<B> getBean(
51+
String name,
52+
Class<B> beanType,
53+
LifecycleOptions lifecycleOptions,
54+
BeanInstanceProducer fallbackProducer) {
55+
return () -> (B) fallbackProducer.produceBeanInstance( beanType );
56+
}
57+
58+
@Override
59+
public void stop() {
60+
61+
}
62+
} );
63+
return settings;
64+
}
65+
66+
@Override
67+
protected String tenantUrl(String originalUrl, String tenantIdentifier) {
68+
return originalUrl.replace("db1", tenantIdentifier);
69+
}
70+
71+
@Test
72+
public void testProviderInUse() {
73+
MultiTenantConnectionProvider<?> providerInUse = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService( MultiTenantConnectionProvider.class );
74+
assertSame( providerInUse, expectedProviderInUse());
75+
}
76+
77+
protected MultiTenantConnectionProvider<?> expectedProviderInUse() {
78+
return providerFromBeanContainer;
79+
}
80+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.multitenancy.beancontainer;
6+
7+
import java.util.Map;
8+
9+
import org.hibernate.cfg.AvailableSettings;
10+
import org.hibernate.dialect.H2Dialect;
11+
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
12+
import org.hibernate.orm.test.multitenancy.ConfigurableMultiTenantConnectionProvider;
13+
14+
import org.hibernate.testing.orm.junit.RequiresDialect;
15+
16+
/**
17+
* @author Yanming Zhou
18+
*/
19+
@RequiresDialect(H2Dialect.class)
20+
public class MultiTenantConnectionProviderFromSettingsOverBeanContainerTest extends MultiTenantConnectionProviderFromBeanContainerTest {
21+
22+
private ConfigurableMultiTenantConnectionProvider providerFromSettings;
23+
24+
@Override
25+
protected Map<String, Object> createSettings() {
26+
Map<String, Object> settings = super.createSettings();
27+
providerFromSettings = new ConfigurableMultiTenantConnectionProvider(connectionProviderMap);
28+
settings.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, providerFromSettings);
29+
return settings;
30+
}
31+
32+
@Override
33+
protected MultiTenantConnectionProvider<?> expectedProviderInUse() {
34+
return providerFromSettings;
35+
}
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.multitenancy.beancontainer;
6+
7+
import org.hibernate.cfg.AvailableSettings;
8+
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
9+
10+
import org.hibernate.testing.orm.junit.ServiceRegistry;
11+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
12+
import org.hibernate.testing.orm.junit.Setting;
13+
14+
import org.junit.jupiter.api.Test;
15+
16+
import static org.hamcrest.CoreMatchers.is;
17+
import static org.hamcrest.MatcherAssert.assertThat;
18+
19+
/**
20+
* @author Yanming Zhou
21+
*/
22+
@ServiceRegistry(
23+
settings = {
24+
@Setting(name = AvailableSettings.ALLOW_EXTENSIONS_IN_CDI, value = "true"),
25+
@Setting(name = AvailableSettings.BEAN_CONTAINER, value = "org.hibernate.orm.test.multitenancy.beancontainer.TestBeanContainer")
26+
}
27+
)
28+
public class TenantResolverFromBeanContainerTest extends AbstractTenantResolverBeanContainerTest {
29+
30+
@Test
31+
void tenantResolverFromBeanContainerShouldBeUsed(SessionFactoryScope scope) {
32+
CurrentTenantIdentifierResolver<?> tenantResolver = scope.getSessionFactory().getCurrentTenantIdentifierResolver();
33+
assertThat(tenantResolver, is(TestCurrentTenantIdentifierResolver.INSTANCE_FOR_BEAN_CONTAINER));
34+
}
35+
36+
}

0 commit comments

Comments
 (0)