/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.test.multitenancy.schema; import java.util.HashMap; import java.util.Map; import org.hibernate.HibernateException; import org.hibernate.MultiTenancyStrategy; import org.hibernate.Session; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.SessionFactoryBuilder; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Environment; import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl; import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.mapping.RootClass; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool; import org.hibernate.tool.schema.internal.SchemaCreatorImpl; import org.hibernate.tool.schema.internal.SchemaDropperImpl; import org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase; import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.cache.CachingRegionFactory; import org.hibernate.testing.env.ConnectionProviderBuilder; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.test.util.DdlTransactionIsolatorTestingImpl; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * @author Steve Ebersole */ @RequiresDialectFeature( value = ConnectionProviderBuilder.class ) public class SchemaBasedMultiTenancyTest extends BaseUnitTestCase { private DriverManagerConnectionProviderImpl acmeProvider; private DriverManagerConnectionProviderImpl jbossProvider; private ServiceRegistryImplementor serviceRegistry; protected SessionFactoryImplementor sessionFactory; @Before public void setUp() { AbstractMultiTenantConnectionProvider multiTenantConnectionProvider = buildMultiTenantConnectionProvider(); Map settings = new HashMap(); settings.put( Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA ); settings.put( Environment.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName() ); settings.put( Environment.GENERATE_STATISTICS, "true" ); serviceRegistry = (ServiceRegistryImplementor) new StandardServiceRegistryBuilder() .applySettings( settings ) .addService( MultiTenantConnectionProvider.class, multiTenantConnectionProvider ) .build(); MetadataSources ms = new MetadataSources( serviceRegistry ); ms.addAnnotatedClass( Customer.class ); ms.addAnnotatedClass( Invoice.class ); Metadata metadata = ms.buildMetadata(); ( (RootClass) metadata.getEntityBinding( Customer.class.getName() ) ).setCacheConcurrencyStrategy( "read-write" ); HibernateSchemaManagementTool tool = new HibernateSchemaManagementTool(); tool.injectServices( serviceRegistry ); final GenerationTargetToDatabase acmeTarget = new GenerationTargetToDatabase( new DdlTransactionIsolatorTestingImpl( serviceRegistry, acmeProvider ) ); final GenerationTargetToDatabase jbossTarget = new GenerationTargetToDatabase( new DdlTransactionIsolatorTestingImpl( serviceRegistry, jbossProvider ) ); new SchemaDropperImpl( serviceRegistry ).doDrop( metadata, serviceRegistry, settings, true, acmeTarget, jbossTarget ); new SchemaCreatorImpl( serviceRegistry ).doCreation( metadata, serviceRegistry, settings, true, acmeTarget, jbossTarget ); final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); configure( sfb ); sessionFactory = (SessionFactoryImplementor) sfb.build(); } protected void configure(SessionFactoryBuilder sfb) { } private AbstractMultiTenantConnectionProvider buildMultiTenantConnectionProvider() { acmeProvider = ConnectionProviderBuilder.buildConnectionProvider( "acme" ); jbossProvider = ConnectionProviderBuilder.buildConnectionProvider( "jboss" ); return new AbstractMultiTenantConnectionProvider() { @Override protected ConnectionProvider getAnyConnectionProvider() { return acmeProvider; } @Override protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) { if ( "acme".equals( tenantIdentifier ) ) { return acmeProvider; } else if ( "jboss".equals( tenantIdentifier ) ) { return jbossProvider; } throw new HibernateException( "Unknown tenant identifier" ); } }; } @After public void tearDown() { if ( sessionFactory != null ) { sessionFactory.close(); } if ( serviceRegistry != null ) { serviceRegistry.destroy(); } if ( jbossProvider != null ) { jbossProvider.stop(); } if ( acmeProvider != null ) { acmeProvider.stop(); } } @Test public void testBasicExpectedBehavior() { Session session = getNewSession("jboss"); session.beginTransaction(); Customer steve = new Customer( 1L, "steve" ); session.save( steve ); session.getTransaction().commit(); session.close(); session = getNewSession("acme"); try { session.beginTransaction(); Customer check = (Customer) session.get( Customer.class, steve.getId() ); Assert.assertNull( "tenancy not properly isolated", check ); } finally { session.getTransaction().commit(); session.close(); } session = getNewSession("jboss"); session.beginTransaction(); session.delete( steve ); session.getTransaction().commit(); session.close(); } @Test public void testSameIdentifiers() { // create a customer 'steve' in jboss Session session = getNewSession("jboss"); session.beginTransaction(); Customer steve = new Customer( 1L, "steve" ); session.save( steve ); session.getTransaction().commit(); session.close(); // now, create a customer 'john' in acme session = getNewSession("acme"); session.beginTransaction(); Customer john = new Customer( 1L, "john" ); session.save( john ); session.getTransaction().commit(); session.close(); sessionFactory.getStatisticsImplementor().clear(); // make sure we get the correct people back, from cache // first, jboss { session = getNewSession("jboss"); session.beginTransaction(); Customer customer = (Customer) session.load( Customer.class, 1L ); Assert.assertEquals( "steve", customer.getName() ); // also, make sure this came from second level Assert.assertEquals( 1, sessionFactory.getStatisticsImplementor().getSecondLevelCacheHitCount() ); session.getTransaction().commit(); session.close(); } sessionFactory.getStatisticsImplementor().clear(); // then, acme { session = getNewSession("acme"); session.beginTransaction(); Customer customer = (Customer) session.load( Customer.class, 1L ); Assert.assertEquals( "john", customer.getName() ); // also, make sure this came from second level Assert.assertEquals( 1, sessionFactory.getStatisticsImplementor().getSecondLevelCacheHitCount() ); session.getTransaction().commit(); session.close(); } // make sure the same works from datastore too sessionFactory.getStatisticsImplementor().clear(); sessionFactory.getCache().evictEntityRegions(); // first jboss { session = getNewSession("jboss"); session.beginTransaction(); Customer customer = (Customer) session.load( Customer.class, 1L ); Assert.assertEquals( "steve", customer.getName() ); // also, make sure this came from second level Assert.assertEquals( 0, sessionFactory.getStatisticsImplementor().getSecondLevelCacheHitCount() ); session.getTransaction().commit(); session.close(); } sessionFactory.getStatisticsImplementor().clear(); // then, acme { session = getNewSession("acme"); session.beginTransaction(); Customer customer = (Customer) session.load( Customer.class, 1L ); Assert.assertEquals( "john", customer.getName() ); // also, make sure this came from second level Assert.assertEquals( 0, sessionFactory.getStatisticsImplementor().getSecondLevelCacheHitCount() ); session.getTransaction().commit(); session.close(); } session = getNewSession("jboss"); session.beginTransaction(); session.delete( steve ); session.getTransaction().commit(); session.close(); session = getNewSession("acme"); session.beginTransaction(); session.delete( john ); session.getTransaction().commit(); session.close(); } @Test public void testTableIdentifiers() { Session session = getNewSession( "jboss" ); session.beginTransaction(); Invoice orderJboss = new Invoice(); session.save( orderJboss ); Assert.assertEquals( Long.valueOf( 1 ), orderJboss.getId() ); session.getTransaction().commit(); session.close(); session = getNewSession( "acme" ); session.beginTransaction(); Invoice orderAcme = new Invoice(); session.save( orderAcme ); Assert.assertEquals( Long.valueOf( 1 ), orderAcme.getId() ); session.getTransaction().commit(); session.close(); session = getNewSession( "jboss" ); session.beginTransaction(); session.delete( orderJboss ); session.getTransaction().commit(); session.close(); session = getNewSession( "acme" ); session.beginTransaction(); session.delete( orderAcme ); session.getTransaction().commit(); session.close(); sessionFactory.getStatisticsImplementor().clear(); } protected Session getNewSession(String tenant) { return sessionFactory.withOptions().tenantIdentifier( tenant ).openSession(); } }