diff --git a/src/main/java/com/avaje/ebean/config/TenantMode.java b/src/main/java/com/avaje/ebean/config/TenantMode.java index 2552fb029..bda074ff0 100644 --- a/src/main/java/com/avaje/ebean/config/TenantMode.java +++ b/src/main/java/com/avaje/ebean/config/TenantMode.java @@ -8,20 +8,33 @@ public enum TenantMode { /** * No multi-tenancy. */ - NONE, + NONE(false), /** * Each Tenant has their own Database (javax.sql.DataSource) */ - DB, + DB(true), /** * Each Tenant has their own Database schema. */ - SCHEMA, + SCHEMA(true), /** * Tenants share tables but have a discriminator/partition column that partitions the data. */ - PARTITION + PARTITION(false); + + boolean dynamicDataSource; + + TenantMode(boolean dynamicDataSource) { + this.dynamicDataSource = dynamicDataSource; + } + + /** + * Return true if the DataSource is not available on bootup. + */ + public boolean isDynamicDataSource() { + return dynamicDataSource; + } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/DdlGenerator.java b/src/main/java/com/avaje/ebean/dbmigration/DdlGenerator.java index 2f995fce2..b5afad733 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/DdlGenerator.java +++ b/src/main/java/com/avaje/ebean/dbmigration/DdlGenerator.java @@ -6,6 +6,8 @@ import com.avaje.ebean.dbmigration.model.CurrentModel; import com.avaje.ebeaninternal.api.SpiEbeanServer; import com.avaje.ebeaninternal.extraddl.model.ExtraDdlXmlReader; import org.avaje.dbmigration.ddl.DdlRunner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; import java.io.File; @@ -27,6 +29,8 @@ import java.sql.SQLException; */ public class DdlGenerator { + private static final Logger log = LoggerFactory.getLogger(DdlGenerator.class); + private final SpiEbeanServer server; private final boolean generateDdl; @@ -40,8 +44,13 @@ public class DdlGenerator { public DdlGenerator(SpiEbeanServer server, ServerConfig serverConfig) { this.server = server; this.generateDdl = serverConfig.isDdlGenerate(); - this.runDdl = serverConfig.isDdlRun(); this.createOnly = serverConfig.isDdlCreateOnly(); + if (serverConfig.getTenantMode().isDynamicDataSource() && serverConfig.isDdlRun()) { + log.warn("DDL can't be run on startup with TenantMode " + serverConfig.getTenantMode()); + this.runDdl = false; + } else { + this.runDdl = serverConfig.isDdlRun(); + } } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java index f73f94925..0f1bd1526 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java @@ -100,7 +100,7 @@ public class DefaultContainer implements SpiContainer { if (serverConfig.isDocStoreOnly()) { serverConfig.setDatabasePlatform(new H2Platform()); } else { - if (!TenantMode.DB.equals(serverConfig.getTenantMode())) { + if (!serverConfig.getTenantMode().isDynamicDataSource()) { setDataSource(serverConfig); // check the autoCommit and Transaction Isolation online = checkDataSource(serverConfig); @@ -240,6 +240,9 @@ public class DefaultContainer implements SpiContainer { DatabasePlatform dbPlatform = config.getDatabasePlatform(); if (dbPlatform == null) { + if (config.getTenantMode().isDynamicDataSource()) { + throw new IllegalStateException("DatabasePlatform must be explicitly set on ServerConfig for TenantMode "+config.getTenantMode()); + } DatabasePlatformFactory factory = new DatabasePlatformFactory(); DatabasePlatform db = factory.create(config); db.configure(config.getDbTypeConfig()); diff --git a/src/test/java/com/avaje/ebean/EbeanServerFactory_MultiTenancy_Test.java b/src/test/java/com/avaje/ebean/EbeanServerFactory_MultiTenancy_Test.java new file mode 100644 index 000000000..90cde09d1 --- /dev/null +++ b/src/test/java/com/avaje/ebean/EbeanServerFactory_MultiTenancy_Test.java @@ -0,0 +1,82 @@ +package com.avaje.ebean; + +import com.avaje.ebean.config.CurrentTenantProvider; +import com.avaje.ebean.config.ServerConfig; +import com.avaje.ebean.config.TenantDataSourceProvider; +import com.avaje.ebean.config.TenantMode; +import com.avaje.ebean.config.TenantSchemaProvider; +import com.avaje.ebean.config.dbplatform.MySqlPlatform; +import com.avaje.ebean.config.dbplatform.PostgresPlatform; +import org.junit.Test; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +public class EbeanServerFactory_MultiTenancy_Test { + + /** + * Tests using multi tenancy per database + */ + @Test + public void create_new_server_with_multi_tenancy_db() { + + String tenant = "customer"; + CurrentTenantProvider tenantProvider = Mockito.mock(CurrentTenantProvider.class); + Mockito.doReturn(tenant).when(tenantProvider).currentId(); + + DataSource mockedDataSource = Mockito.mock(DataSource.class); + TenantDataSourceProvider dataSourceProvider = Mockito.mock(TenantDataSourceProvider.class); + Mockito.doReturn(mockedDataSource).when(dataSourceProvider).dataSource(tenant); + + ServerConfig config = new ServerConfig(); + config.setName("multiTenantDb"); + config.loadFromProperties(); + config.loadTestProperties(); + config.setRegister(false); + config.setDefaultServer(false); + + config.setTenantMode(TenantMode.DB); + config.setCurrentTenantProvider(tenantProvider); + config.setTenantDataSourceProvider(dataSourceProvider); + + // When TenantMode.DB we don't really want to run DDL + // and we want to explicitly specify the Database platform + //config.setDdlGenerate(false); + //config.setDdlRun(false); + config.setDatabasePlatform(new PostgresPlatform()); + + EbeanServerFactory.create(config); + } + + + + /** + * Tests using multi tenancy per schema + */ + @Test + public void create_new_server_with_multi_tenancy_schema() { + + String tenant = "customer"; + CurrentTenantProvider tenantProvider = Mockito.mock(CurrentTenantProvider.class); + Mockito.doReturn(tenant).when(tenantProvider).currentId(); + + TenantSchemaProvider schemaProvider = Mockito.mock(TenantSchemaProvider.class); + Mockito.doReturn("tenant_schema").when(schemaProvider).schema(tenant); + + ServerConfig config = new ServerConfig(); + config.setName("multiTenantDb"); + config.loadFromProperties(); + config.loadTestProperties(); + config.setRegister(false); + config.setDefaultServer(false); + + config.setTenantMode(TenantMode.SCHEMA); + config.setCurrentTenantProvider(tenantProvider); + config.setTenantSchemaProvider(schemaProvider); + + config.setDdlRun(false); + config.setDatabasePlatform(new MySqlPlatform()); + + EbeanServerFactory.create(config); + } +}