diff --git a/mifosng-db/multi-tenant-demo-backups/0001-mifos-platform-shared-tenants.sql b/mifosng-db/multi-tenant-demo-backups/0001-mifos-platform-shared-tenants.sql index 5b7c74955..e4d2afdb0 100644 --- a/mifosng-db/multi-tenant-demo-backups/0001-mifos-platform-shared-tenants.sql +++ b/mifosng-db/multi-tenant-demo-backups/0001-mifos-platform-shared-tenants.sql @@ -36,6 +36,7 @@ CREATE TABLE `tenants` ( `schema_server_port` varchar(10) NOT NULL DEFAULT '3306', `schema_username` varchar(100) NOT NULL DEFAULT 'root', `schema_password` varchar(100) NOT NULL DEFAULT 'mysql', + `auto_update` tinyint(1) NOT NULL DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/mifosng-provider/build.gradle b/mifosng-provider/build.gradle index 70849d76e..afbb8c6c1 100644 --- a/mifosng-provider/build.gradle +++ b/mifosng-provider/build.gradle @@ -191,6 +191,9 @@ task deployPentahoReports() { war { it.dependsOn deployPentahoReports + from ('../mifosng-db/migrations') { + into "WEB-INF/classes/sql" + } } license { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/domain/MifosPlatformTenant.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/domain/MifosPlatformTenant.java index 23e87d727..83ff28d20 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/domain/MifosPlatformTenant.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/domain/MifosPlatformTenant.java @@ -15,10 +15,11 @@ public class MifosPlatformTenant { private final String schemaUsername; private final String schemaPassword; private final String timezoneId; - + private final boolean autoUpdateEnabled; public MifosPlatformTenant(final Long id, final String name, final String schemaName, final String schemaServer, - final String schemaServerPort, final String schemaUsername, final String schemaPassword, String timezoneId) { + final String schemaServerPort, final String schemaUsername, final String schemaPassword, String timezoneId, + final boolean autoUpdateEnabled) { this.id = id; this.name = name; this.schemaName = schemaName; @@ -27,7 +28,14 @@ public class MifosPlatformTenant { this.schemaUsername = schemaUsername; this.schemaPassword = schemaPassword; this.timezoneId = timezoneId; - + this.autoUpdateEnabled = autoUpdateEnabled; + + } + + public String databaseURL() { + String url = new StringBuilder("jdbc:mysql://").append(schemaServer).append(':').append(schemaServerPort).append('/') + .append(schemaName).toString(); + return url; } public Long getId() { @@ -39,15 +47,7 @@ public class MifosPlatformTenant { } public String getSchemaName() { - return schemaName; - } - - public String getSchemaServer() { - return schemaServer; - } - - public String getSchemaServerPort() { - return schemaServerPort; + return this.schemaName; } public String getSchemaUsername() { @@ -57,9 +57,13 @@ public class MifosPlatformTenant { public String getSchemaPassword() { return schemaPassword; } - + public String getTimezoneId() { return timezoneId; } - + + public boolean isAutoUpdateEnabled() { + return this.autoUpdateEnabled; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/domain/Tenant.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/domain/Tenant.java new file mode 100755 index 000000000..79c8c3189 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/domain/Tenant.java @@ -0,0 +1,65 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.core.domain; + +public class Tenant { + + private final Long id; + private final String name; + private final String schemaName; + private final String schemaServer; + private final String schemaServerPort; + private final String schemaUsername; + private final String schemaPassword; + private final String timezoneId; + + + public Tenant(final Long id, final String name, final String schemaName, final String schemaServer, + final String schemaServerPort, final String schemaUsername, final String schemaPassword, String timezoneId) { + this.id = id; + this.name = name; + this.schemaName = schemaName; + this.schemaServer = schemaServer; + this.schemaServerPort = schemaServerPort; + this.schemaUsername = schemaUsername; + this.schemaPassword = schemaPassword; + this.timezoneId = timezoneId; + + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getSchemaName() { + return schemaName; + } + + public String getSchemaServer() { + return schemaServer; + } + + public String getSchemaServerPort() { + return schemaServerPort; + } + + public String getSchemaUsername() { + return schemaUsername; + } + + public String getSchemaPassword() { + return schemaPassword; + } + + public String getTimezoneId() { + return timezoneId; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/ITenantUpgradeService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/ITenantUpgradeService.java new file mode 100755 index 000000000..6b186e3bf --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/ITenantUpgradeService.java @@ -0,0 +1,13 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.core.service; + + +public interface ITenantUpgradeService { + + void upgradeAllTenants(); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/TenantUpgradeService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/TenantUpgradeService.java new file mode 100755 index 000000000..4ee3ab336 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/TenantUpgradeService.java @@ -0,0 +1,46 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.core.service; + +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant; +import org.mifosplatform.infrastructure.security.service.TenantDetailsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.googlecode.flyway.core.Flyway; + +/** + * A JDBC implementation of {@link TenantDetailsService} for loading a tenants + * details by a tenantIdentifier. + */ +@Service +public class TenantUpgradeService implements ITenantUpgradeService { + + private final TenantDetailsService tenantDetailsService; + + @Autowired + public TenantUpgradeService(TenantDetailsService detailsService) { + this.tenantDetailsService = detailsService; + } + + @Override + @PostConstruct + public void upgradeAllTenants() { + List tenants = tenantDetailsService.findAllTenants(); + for (MifosPlatformTenant tenant : tenants) { + if (tenant.isAutoUpdateEnabled()) { + Flyway flyway = new Flyway(); + flyway.setDataSource(tenant.databaseURL(), tenant.getSchemaUsername(), tenant.getSchemaPassword()); + flyway.setLocations("sql"); + flyway.migrate(); + } + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/TomcatJdbcDataSourcePerTenantService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/TomcatJdbcDataSourcePerTenantService.java index 9a79839a9..d7290548a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/TomcatJdbcDataSourcePerTenantService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/TomcatJdbcDataSourcePerTenantService.java @@ -27,7 +27,7 @@ import org.springframework.stereotype.Service; */ @Service public class TomcatJdbcDataSourcePerTenantService implements DataSourcePerTenantService { - + private final Map tenantToDataSourceMap = new ConcurrentHashMap(1); private final DataSource tenantDataSource; @@ -61,24 +61,23 @@ public class TomcatJdbcDataSourcePerTenantService implements DataSourcePerTenant // see // http://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency - StringBuilder jdbcUrlBuilder = new StringBuilder("jdbc:mysql://").append(tenant.getSchemaServer()).append(':') - .append(tenant.getSchemaServerPort()).append('/').append(tenant.getSchemaName()); + String jdbcUrl = tenant.databaseURL(); PoolConfiguration poolConfiguration = new PoolProperties(); poolConfiguration.setDriverClassName("com.mysql.jdbc.Driver"); poolConfiguration.setName(tenant.getSchemaName() + "_pool"); - poolConfiguration.setUrl(jdbcUrlBuilder.toString()); + poolConfiguration.setUrl(jdbcUrl); poolConfiguration.setUsername(tenant.getSchemaUsername()); poolConfiguration.setPassword(tenant.getSchemaPassword()); poolConfiguration.setInitialSize(5); - //poolConfiguration.setMaxActive(5); - //poolConfiguration.setMinIdle(1); - //poolConfiguration.setMaxIdle(4); + // poolConfiguration.setMaxActive(5); + // poolConfiguration.setMinIdle(1); + // poolConfiguration.setMaxIdle(4); - //poolConfiguration.setSuspectTimeout(60); - //poolConfiguration.setTimeBetweenEvictionRunsMillis(30000); - //poolConfiguration.setMinEvictableIdleTimeMillis(60000); + // poolConfiguration.setSuspectTimeout(60); + // poolConfiguration.setTimeBetweenEvictionRunsMillis(30000); + // poolConfiguration.setMinEvictableIdleTimeMillis(60000); poolConfiguration.setTestOnBorrow(true); poolConfiguration.setValidationQuery("SELECT 1"); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/security/service/JdbcTenantDetailsService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/security/service/JdbcTenantDetailsService.java index 28a5f9b98..c286e7c2b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/security/service/JdbcTenantDetailsService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/security/service/JdbcTenantDetailsService.java @@ -7,6 +7,7 @@ package org.mifosplatform.infrastructure.security.service; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; import javax.sql.DataSource; @@ -33,23 +34,17 @@ public class JdbcTenantDetailsService implements TenantDetailsService { this.jdbcTemplate = new JdbcTemplate(dataSource); } - @Override - public MifosPlatformTenant loadTenantById(final String tenantIdentifier) { - - try { - TenantMapper rm = new TenantMapper(); - String sql = "select id, name, schema_name as schemaName, schema_server as schemaServer, schema_server_port as schemaServerPort, " - + " schema_username as schemaUsername, schema_password as schemaPassword , timezone_id as timezoneId " - + " from tenants t where t.identifier like ?"; - - return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { tenantIdentifier }); - } catch (EmptyResultDataAccessException e) { - throw new InvalidTenantIdentiferException("The tenant identifier: " + tenantIdentifier + " is not valid."); - } - } - private static final class TenantMapper implements RowMapper { + private StringBuilder sqlBuilder = new StringBuilder( + "id, name, schema_name as schemaName, schema_server as schemaServer, schema_server_port as schemaServerPort, auto_update as autoUpdate, ")// + .append(" schema_username as schemaUsername, schema_password as schemaPassword , timezone_id as timezoneId ")// + .append(" from tenants t");// + + public String schema() { + return sqlBuilder.toString(); + } + @Override public MifosPlatformTenant mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { @@ -60,9 +55,33 @@ public class JdbcTenantDetailsService implements TenantDetailsService { String schemaServerPort = rs.getString("schemaServerPort"); String schemaUsername = rs.getString("schemaUsername"); String schemaPassword = rs.getString("schemaPassword"); - String timezoneId =rs.getString("timezoneId"); - - return new MifosPlatformTenant(id, name, schemaName, schemaServer, schemaServerPort, schemaUsername, schemaPassword ,timezoneId); + String timezoneId = rs.getString("timezoneId"); + boolean autoUpdateEnabled = rs.getBoolean("autoUpdate"); + + return new MifosPlatformTenant(id, name, schemaName, schemaServer, schemaServerPort, schemaUsername, schemaPassword, + timezoneId, autoUpdateEnabled); } } + + @Override + public MifosPlatformTenant loadTenantById(final String tenantIdentifier) { + + try { + TenantMapper rm = new TenantMapper(); + String sql = "select " + rm.schema() + " where t.identifier like ?"; + + return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { tenantIdentifier }); + } catch (EmptyResultDataAccessException e) { + throw new InvalidTenantIdentiferException("The tenant identifier: " + tenantIdentifier + " is not valid."); + } + } + + @Override + public List findAllTenants() { + TenantMapper rm = new TenantMapper(); + String sql = "select " + rm.schema(); + + List mifosPlatformTenants = jdbcTemplate.query(sql, rm, new Object[] {}); + return mifosPlatformTenants; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/security/service/TenantDetailsService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/security/service/TenantDetailsService.java index 4a6f554bf..cb58b8870 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/security/service/TenantDetailsService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/security/service/TenantDetailsService.java @@ -5,10 +5,14 @@ */ package org.mifosplatform.infrastructure.security.service; +import java.util.List; + import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant; public interface TenantDetailsService { MifosPlatformTenant loadTenantById(String tenantId); + List findAllTenants(); + } diff --git a/mifosng-provider/src/main/resources/META-INF/spring/infrastructure.xml b/mifosng-provider/src/main/resources/META-INF/spring/infrastructure.xml index 1cc49c00f..f009fcb2c 100644 --- a/mifosng-provider/src/main/resources/META-INF/spring/infrastructure.xml +++ b/mifosng-provider/src/main/resources/META-INF/spring/infrastructure.xml @@ -13,7 +13,7 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"> - +