Fineract with ReadOnly tenant database connection
This commit is contained in:
committed by
Arnold Gálovics
parent
7cd9ff879a
commit
2a7d8b9496
@@ -539,6 +539,18 @@ configure(project.fineractJavaProjects) {
|
||||
excludeTestsMatching project.property('excludeTests')
|
||||
}
|
||||
}
|
||||
|
||||
// Database type used in the Test
|
||||
systemProperty 'dbType', 'mariadb'
|
||||
if (project.hasProperty('dbType')) {
|
||||
if ('postgresql'.equalsIgnoreCase(dbType)) {
|
||||
systemProperty 'dbType', 'postgresql'
|
||||
} else if ('mysql'.equalsIgnoreCase(dbType)) {
|
||||
systemProperty 'dbType', 'mysql'
|
||||
} else {
|
||||
throw new GradleException('Provided dbType is not supported')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testlogger {
|
||||
|
||||
@@ -223,6 +223,7 @@ bootRun {
|
||||
dependencies {
|
||||
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
||||
implementation 'org.postgresql:postgresql:42.3.5'
|
||||
implementation 'mysql:mysql-connector-java:8.0.29'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,6 +289,7 @@ jib {
|
||||
dependencies {
|
||||
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
||||
implementation 'org.postgresql:postgresql:42.3.5'
|
||||
implementation 'mysql:mysql-connector-java:8.0.29'
|
||||
}
|
||||
|
||||
pluginExtensions {
|
||||
|
||||
+40
-1
@@ -34,6 +34,12 @@ public class FineractPlatformTenantConnection {
|
||||
private final String schemaUsername;
|
||||
private final String schemaPassword;
|
||||
private final String schemaName;
|
||||
private final String readOnlySchemaServer;
|
||||
private final String readOnlySchemaServerPort;
|
||||
private final String readOnlySchemaName;
|
||||
private final String readOnlySchemaUsername;
|
||||
private final String readOnlySchemaPassword;
|
||||
private final String readOnlySchemaConnectionParameters;
|
||||
private final boolean autoUpdateEnabled;
|
||||
private final int initialSize;
|
||||
private final long validationInterval;
|
||||
@@ -57,7 +63,9 @@ public class FineractPlatformTenantConnection {
|
||||
final boolean removeAbandoned, final int removeAbandonedTimeout, final boolean logAbandoned,
|
||||
final int abandonWhenPercentageFull, final int maxActive, final int minIdle, final int maxIdle, final int suspectTimeout,
|
||||
final int timeBetweenEvictionRunsMillis, final int minEvictableIdleTimeMillis, final int maxRetriesOnDeadlock,
|
||||
final int maxIntervalBetweenRetries, final boolean tesOnBorrow) {
|
||||
final int maxIntervalBetweenRetries, final boolean tesOnBorrow, final String readOnlySchemaServer,
|
||||
final String readOnlySchemaServerPort, final String readOnlySchemaName, final String readOnlySchemaUsername,
|
||||
final String readOnlySchemaPassword, final String readOnlySchemaConnectionParameters) {
|
||||
|
||||
this.connectionId = connectionId;
|
||||
this.schemaName = schemaName;
|
||||
@@ -82,6 +90,12 @@ public class FineractPlatformTenantConnection {
|
||||
this.maxRetriesOnDeadlock = maxRetriesOnDeadlock;
|
||||
this.maxIntervalBetweenRetries = maxIntervalBetweenRetries;
|
||||
this.testOnBorrow = tesOnBorrow;
|
||||
this.readOnlySchemaServer = readOnlySchemaServer;
|
||||
this.readOnlySchemaServerPort = readOnlySchemaServerPort;
|
||||
this.readOnlySchemaName = readOnlySchemaName;
|
||||
this.readOnlySchemaUsername = readOnlySchemaUsername;
|
||||
this.readOnlySchemaPassword = readOnlySchemaPassword;
|
||||
this.readOnlySchemaConnectionParameters = readOnlySchemaConnectionParameters;
|
||||
}
|
||||
|
||||
public String getSchemaServer() {
|
||||
@@ -176,6 +190,30 @@ public class FineractPlatformTenantConnection {
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public String getReadOnlySchemaServer() {
|
||||
return readOnlySchemaServer;
|
||||
}
|
||||
|
||||
public String getReadOnlySchemaServerPort() {
|
||||
return readOnlySchemaServerPort;
|
||||
}
|
||||
|
||||
public String getReadOnlySchemaName() {
|
||||
return readOnlySchemaName;
|
||||
}
|
||||
|
||||
public String getReadOnlySchemaUsername() {
|
||||
return readOnlySchemaUsername;
|
||||
}
|
||||
|
||||
public String getReadOnlySchemaPassword() {
|
||||
return readOnlySchemaPassword;
|
||||
}
|
||||
|
||||
public String getReadOnlySchemaConnectionParameters() {
|
||||
return readOnlySchemaConnectionParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(this.schemaName).append(":").append(this.schemaServer).append(":")
|
||||
@@ -204,4 +242,5 @@ public class FineractPlatformTenantConnection {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.service;
|
||||
|
||||
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toJdbcUrl;
|
||||
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toProtocol;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import javax.sql.DataSource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||
import org.apache.fineract.infrastructure.security.constants.TenantConstants;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* Factory class to get data source service based on the details stored in {@link FineractPlatformTenantConnection}
|
||||
* variable
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class DataSourcePerTenantServiceFactory {
|
||||
|
||||
private final HikariConfig hikariConfig;
|
||||
private final FineractProperties fineractProperties;
|
||||
private final ApplicationContext context;
|
||||
|
||||
public DataSource createNewDataSourceFor(final DataSource tenantDataSource, final FineractPlatformTenantConnection tenantConnection) {
|
||||
String protocol = toProtocol(tenantDataSource);
|
||||
// Default properties for Writing
|
||||
String schemaServer = tenantConnection.getSchemaServer();
|
||||
String schemaPort = tenantConnection.getSchemaServerPort();
|
||||
String schemaName = tenantConnection.getSchemaName();
|
||||
String schemaUsername = tenantConnection.getSchemaUsername();
|
||||
String schemaPassword = tenantConnection.getSchemaPassword();
|
||||
String schemaConnectionParameters = tenantConnection.getSchemaConnectionParameters();
|
||||
// Properties to ReadOnly case
|
||||
if (this.fineractProperties.getMode().isReadOnlyMode()) {
|
||||
schemaServer = getPropertyValue(tenantConnection.getReadOnlySchemaServer(), TenantConstants.PROPERTY_RO_SCHEMA_SERVER_NAME,
|
||||
schemaServer);
|
||||
schemaPort = getPropertyValue(tenantConnection.getReadOnlySchemaServerPort(), TenantConstants.PROPERTY_RO_SCHEMA_SERVER_PORT,
|
||||
schemaPort);
|
||||
schemaName = getPropertyValue(tenantConnection.getReadOnlySchemaName(), TenantConstants.PROPERTY_RO_SCHEMA_SCHEMA_NAME,
|
||||
schemaName);
|
||||
schemaUsername = getPropertyValue(tenantConnection.getReadOnlySchemaUsername(), TenantConstants.PROPERTY_RO_SCHEMA_USERNAME,
|
||||
schemaUsername);
|
||||
schemaPassword = getPropertyValue(tenantConnection.getReadOnlySchemaPassword(), TenantConstants.PROPERTY_RO_SCHEMA_PASSWORD,
|
||||
schemaPassword);
|
||||
schemaConnectionParameters = getPropertyValue(tenantConnection.getReadOnlySchemaConnectionParameters(),
|
||||
TenantConstants.PROPERTY_RO_SCHEMA_CONNECTION_PARAMETERS, schemaConnectionParameters);
|
||||
}
|
||||
String jdbcUrl = toJdbcUrl(protocol, schemaServer, schemaPort, schemaName, schemaConnectionParameters);
|
||||
log.debug("{}", jdbcUrl);
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setReadOnly(this.fineractProperties.getMode().isReadOnlyMode());
|
||||
config.setDriverClassName(hikariConfig.getDriverClassName());
|
||||
config.setPoolName(schemaName + "_pool");
|
||||
config.setJdbcUrl(jdbcUrl);
|
||||
config.setUsername(schemaUsername);
|
||||
config.setPassword(schemaPassword);
|
||||
config.setMinimumIdle(tenantConnection.getInitialSize());
|
||||
config.setMaximumPoolSize(tenantConnection.getMaxActive());
|
||||
config.setConnectionTestQuery(hikariConfig.getConnectionTestQuery());
|
||||
config.setValidationTimeout(tenantConnection.getValidationInterval());
|
||||
config.setAutoCommit(hikariConfig.isAutoCommit());
|
||||
|
||||
// https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management
|
||||
config.setRegisterMbeans(true);
|
||||
|
||||
// https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
|
||||
// These are the properties for each Tenant DB; the same configuration
|
||||
// is also in src/main/resources/META-INF/spring/hikariDataSource.xml
|
||||
// for the all Tenants DB -->
|
||||
config.setDataSourceProperties(hikariConfig.getDataSourceProperties());
|
||||
|
||||
return new HikariDataSource(config);
|
||||
}
|
||||
|
||||
private String getPropertyValue(final String baseValue, final String propertyName, final String defaultValue) {
|
||||
// If the property already has set, return It
|
||||
if (null != baseValue) {
|
||||
return baseValue;
|
||||
}
|
||||
if (this.context == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return this.context.getEnvironment().getProperty(propertyName, defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
+5
-39
@@ -18,11 +18,6 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.service;
|
||||
|
||||
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toJdbcUrl;
|
||||
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toProtocol;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
@@ -44,12 +39,13 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
|
||||
private final Map<Long, DataSource> tenantToDataSourceMap = new HashMap<>(1);
|
||||
private final DataSource tenantDataSource;
|
||||
|
||||
@Autowired
|
||||
private HikariConfig hikariConfig;
|
||||
private final DataSourcePerTenantServiceFactory dataSourcePerTenantServiceFactory;
|
||||
|
||||
@Autowired
|
||||
public TomcatJdbcDataSourcePerTenantService(final @Qualifier("hikariTenantDataSource") DataSource tenantDataSource) {
|
||||
public TomcatJdbcDataSourcePerTenantService(final @Qualifier("hikariTenantDataSource") DataSource tenantDataSource,
|
||||
final DataSourcePerTenantServiceFactory dataSourcePerTenantServiceFactory) {
|
||||
this.tenantDataSource = tenantDataSource;
|
||||
this.dataSourcePerTenantServiceFactory = dataSourcePerTenantServiceFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,7 +64,7 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
|
||||
if (possibleDS != null) {
|
||||
tenantDataSource = possibleDS;
|
||||
} else {
|
||||
tenantDataSource = createNewDataSourceFor(tenantConnection);
|
||||
tenantDataSource = dataSourcePerTenantServiceFactory.createNewDataSourceFor(this.tenantDataSource, tenantConnection);
|
||||
this.tenantToDataSourceMap.put(tenantConnection.getConnectionId(), tenantDataSource);
|
||||
}
|
||||
}
|
||||
@@ -76,34 +72,4 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
|
||||
|
||||
return tenantDataSource;
|
||||
}
|
||||
|
||||
// creates the tenant data source for the oltp and report database
|
||||
private DataSource createNewDataSourceFor(final FineractPlatformTenantConnection tenantConnectionObj) {
|
||||
String protocol = toProtocol(this.tenantDataSource);
|
||||
String jdbcUrl = toJdbcUrl(protocol, tenantConnectionObj.getSchemaServer(), tenantConnectionObj.getSchemaServerPort(),
|
||||
tenantConnectionObj.getSchemaName(), tenantConnectionObj.getSchemaConnectionParameters());
|
||||
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setDriverClassName(hikariConfig.getDriverClassName());
|
||||
config.setPoolName(tenantConnectionObj.getSchemaName() + "_pool");
|
||||
config.setJdbcUrl(jdbcUrl);
|
||||
config.setUsername(tenantConnectionObj.getSchemaUsername());
|
||||
config.setPassword(tenantConnectionObj.getSchemaPassword());
|
||||
config.setMinimumIdle(tenantConnectionObj.getInitialSize());
|
||||
config.setMaximumPoolSize(tenantConnectionObj.getMaxActive());
|
||||
config.setConnectionTestQuery(hikariConfig.getConnectionTestQuery());
|
||||
config.setValidationTimeout(tenantConnectionObj.getValidationInterval());
|
||||
config.setAutoCommit(hikariConfig.isAutoCommit());
|
||||
|
||||
// https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management
|
||||
config.setRegisterMbeans(true);
|
||||
|
||||
// https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
|
||||
// These are the properties for each Tenant DB; the same configuration
|
||||
// is also in src/main/resources/META-INF/spring/hikariDataSource.xml
|
||||
// for the all Tenants DB -->
|
||||
config.setDataSourceProperties(hikariConfig.getDataSourceProperties());
|
||||
|
||||
return new HikariDataSource(config);
|
||||
}
|
||||
}
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.security.constants;
|
||||
|
||||
public final class TenantConstants {
|
||||
|
||||
private TenantConstants() {
|
||||
|
||||
}
|
||||
|
||||
public static final String PROPERTY_RO_SCHEMA_SERVER_NAME = "FINERACT_RO_SCHEMA_SERVER_NAME";
|
||||
public static final String PROPERTY_RO_SCHEMA_SERVER_PORT = "FINERACT_RO_SCHEMA_SERVER_PORT";
|
||||
public static final String PROPERTY_RO_SCHEMA_SCHEMA_NAME = "FINERACT_RO_SCHEMA_SCHEMA_NAME";
|
||||
public static final String PROPERTY_RO_SCHEMA_USERNAME = "FINERACT_RO_SCHEMA_USERNAME";
|
||||
public static final String PROPERTY_RO_SCHEMA_PASSWORD = "FINERACT_RO_SCHEMA_PASSWORD";
|
||||
public static final String PROPERTY_RO_SCHEMA_CONNECTION_PARAMETERS = "FINERACT_RO_SCHEMA_CONNECTION_PARAMETERS";
|
||||
}
|
||||
-90
@@ -18,18 +18,14 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.security.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import javax.sql.DataSource;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||
import org.apache.fineract.infrastructure.security.exception.InvalidTenantIdentiferException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@@ -46,92 +42,6 @@ public class BasicAuthTenantDetailsServiceJdbc implements BasicAuthTenantDetails
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
private static final class TenantMapper implements RowMapper<FineractPlatformTenant> {
|
||||
|
||||
private final boolean isReport;
|
||||
private final StringBuilder sqlBuilder = new StringBuilder(" t.id, ts.id as connectionId , ")//
|
||||
.append(" t.timezone_id as timezoneId , t.name,t.identifier, ts.schema_name as schemaName, ts.schema_server as schemaServer,")//
|
||||
.append(" ts.schema_server_port as schemaServerPort, ts.schema_connection_parameters as schemaConnectionParameters, ts.auto_update as autoUpdate,")//
|
||||
.append(" ts.schema_username as schemaUsername, ts.schema_password as schemaPassword , ts.pool_initial_size as initialSize,")//
|
||||
.append(" ts.pool_validation_interval as validationInterval, ts.pool_remove_abandoned as removeAbandoned, ts.pool_remove_abandoned_timeout as removeAbandonedTimeout,")//
|
||||
.append(" ts.pool_log_abandoned as logAbandoned, ts.pool_abandon_when_percentage_full as abandonedWhenPercentageFull, ts.pool_test_on_borrow as testOnBorrow,")//
|
||||
.append(" ts.pool_max_active as poolMaxActive, ts.pool_min_idle as poolMinIdle, ts.pool_max_idle as poolMaxIdle,")//
|
||||
.append(" ts.pool_suspect_timeout as poolSuspectTimeout, ts.pool_time_between_eviction_runs_millis as poolTimeBetweenEvictionRunsMillis,")//
|
||||
.append(" ts.pool_min_evictable_idle_time_millis as poolMinEvictableIdleTimeMillis,")//
|
||||
.append(" ts.deadlock_max_retries as maxRetriesOnDeadlock,")//
|
||||
.append(" ts.deadlock_max_retry_interval as maxIntervalBetweenRetries ")//
|
||||
.append(" from tenants t left join tenant_server_connections ts ");
|
||||
|
||||
TenantMapper(boolean isReport) {
|
||||
this.isReport = isReport;
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
if (this.isReport) {
|
||||
this.sqlBuilder.append(" on t.report_Id = ts.id");
|
||||
} else {
|
||||
this.sqlBuilder.append(" on t.oltp_Id = ts.id");
|
||||
}
|
||||
return this.sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FineractPlatformTenant mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
final Long id = rs.getLong("id");
|
||||
final String tenantIdentifier = rs.getString("identifier");
|
||||
final String name = rs.getString("name");
|
||||
final String timezoneId = rs.getString("timezoneId");
|
||||
final FineractPlatformTenantConnection connection = getDBConnection(rs);
|
||||
return new FineractPlatformTenant(id, tenantIdentifier, name, timezoneId, connection);
|
||||
}
|
||||
|
||||
// gets the DB connection
|
||||
private FineractPlatformTenantConnection getDBConnection(ResultSet rs) throws SQLException {
|
||||
|
||||
final Long connectionId = rs.getLong("connectionId");
|
||||
final String schemaName = rs.getString("schemaName");
|
||||
final String schemaServer = rs.getString("schemaServer");
|
||||
final String schemaServerPort = rs.getString("schemaServerPort");
|
||||
final String schemaConnectionParameters = rs.getString("schemaConnectionParameters");
|
||||
final String schemaUsername = rs.getString("schemaUsername");
|
||||
final String schemaPassword = rs.getString("schemaPassword");
|
||||
final boolean autoUpdateEnabled = rs.getBoolean("autoUpdate");
|
||||
final int initialSize = rs.getInt("initialSize");
|
||||
final boolean testOnBorrow = rs.getBoolean("testOnBorrow");
|
||||
final long validationInterval = rs.getLong("validationInterval");
|
||||
final boolean removeAbandoned = rs.getBoolean("removeAbandoned");
|
||||
final int removeAbandonedTimeout = rs.getInt("removeAbandonedTimeout");
|
||||
final boolean logAbandoned = rs.getBoolean("logAbandoned");
|
||||
final int abandonWhenPercentageFull = rs.getInt("abandonedWhenPercentageFull");
|
||||
final int maxActive = rs.getInt("poolMaxActive");
|
||||
final int minIdle = rs.getInt("poolMinIdle");
|
||||
final int maxIdle = rs.getInt("poolMaxIdle");
|
||||
final int suspectTimeout = rs.getInt("poolSuspectTimeout");
|
||||
final int timeBetweenEvictionRunsMillis = rs.getInt("poolTimeBetweenEvictionRunsMillis");
|
||||
final int minEvictableIdleTimeMillis = rs.getInt("poolMinEvictableIdleTimeMillis");
|
||||
int maxRetriesOnDeadlock = rs.getInt("maxRetriesOnDeadlock");
|
||||
int maxIntervalBetweenRetries = rs.getInt("maxIntervalBetweenRetries");
|
||||
|
||||
maxRetriesOnDeadlock = bindValueInMinMaxRange(maxRetriesOnDeadlock, 0, 15);
|
||||
maxIntervalBetweenRetries = bindValueInMinMaxRange(maxIntervalBetweenRetries, 1, 15);
|
||||
|
||||
return new FineractPlatformTenantConnection(connectionId, schemaName, schemaServer, schemaServerPort,
|
||||
schemaConnectionParameters, schemaUsername, schemaPassword, autoUpdateEnabled, initialSize, validationInterval,
|
||||
removeAbandoned, removeAbandonedTimeout, logAbandoned, abandonWhenPercentageFull, maxActive, minIdle, maxIdle,
|
||||
suspectTimeout, timeBetweenEvictionRunsMillis, minEvictableIdleTimeMillis, maxRetriesOnDeadlock,
|
||||
maxIntervalBetweenRetries, testOnBorrow);
|
||||
}
|
||||
|
||||
private int bindValueInMinMaxRange(final int value, int min, int max) {
|
||||
if (value < min) {
|
||||
return min;
|
||||
} else if (value > max) {
|
||||
return max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "tenantsById")
|
||||
public FineractPlatformTenant loadTenantById(final String tenantIdentifier, final boolean isReport) {
|
||||
|
||||
+2
-85
@@ -18,19 +18,15 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.security.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import javax.sql.DataSource;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||
import org.apache.fineract.infrastructure.security.exception.InvalidTenantIdentiferException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@@ -47,90 +43,11 @@ public class JdbcTenantDetailsService implements TenantDetailsService {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
private static final class TenantMapper implements RowMapper<FineractPlatformTenant> {
|
||||
|
||||
private final StringBuilder sqlBuilder = new StringBuilder("t.id, ts.id as connectionId , ")//
|
||||
.append(" t.timezone_id as timezoneId , t.name,t.identifier, ts.schema_name as schemaName, ts.schema_server as schemaServer,")//
|
||||
.append(" ts.schema_server_port as schemaServerPort, ts.schema_connection_parameters as schemaConnectionParameters, ts.auto_update as autoUpdate,")//
|
||||
.append(" ts.schema_username as schemaUsername, ts.schema_password as schemaPassword , ts.pool_initial_size as initialSize,")//
|
||||
.append(" ts.pool_validation_interval as validationInterval, ts.pool_remove_abandoned as removeAbandoned, ts.pool_remove_abandoned_timeout as removeAbandonedTimeout,")//
|
||||
.append(" ts.pool_log_abandoned as logAbandoned, ts.pool_abandon_when_percentage_full as abandonedWhenPercentageFull, ts.pool_test_on_borrow as testOnBorrow,")//
|
||||
.append(" ts.pool_max_active as poolMaxActive, ts.pool_min_idle as poolMinIdle, ts.pool_max_idle as poolMaxIdle,")//
|
||||
.append(" ts.pool_suspect_timeout as poolSuspectTimeout, ts.pool_time_between_eviction_runs_millis as poolTimeBetweenEvictionRunsMillis,")//
|
||||
.append(" ts.pool_min_evictable_idle_time_millis as poolMinEvictableIdleTimeMillis,")//
|
||||
.append(" ts.deadlock_max_retries as maxRetriesOnDeadlock,")//
|
||||
.append(" ts.deadlock_max_retry_interval as maxIntervalBetweenRetries ")//
|
||||
.append(" from tenants t left join tenant_server_connections ts on t.oltp_Id=ts.id ");
|
||||
|
||||
public String schema() {
|
||||
return this.sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FineractPlatformTenant mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
final Long id = rs.getLong("id");
|
||||
final String tenantIdentifier = rs.getString("identifier");
|
||||
final String name = rs.getString("name");
|
||||
final String timezoneId = rs.getString("timezoneId");
|
||||
final FineractPlatformTenantConnection connection = getDBConnection(rs);
|
||||
|
||||
return new FineractPlatformTenant(id, tenantIdentifier, name, timezoneId, connection);
|
||||
}
|
||||
|
||||
// gets the DB connection
|
||||
private FineractPlatformTenantConnection getDBConnection(ResultSet rs) throws SQLException {
|
||||
|
||||
final Long connectionId = rs.getLong("connectionId");
|
||||
final String schemaName = rs.getString("schemaName");
|
||||
final String schemaServer = rs.getString("schemaServer");
|
||||
final String schemaServerPort = rs.getString("schemaServerPort");
|
||||
final String schemaConnectionParameters = rs.getString("schemaConnectionParameters");
|
||||
final String schemaUsername = rs.getString("schemaUsername");
|
||||
final String schemaPassword = rs.getString("schemaPassword");
|
||||
final boolean autoUpdateEnabled = rs.getBoolean("autoUpdate");
|
||||
final int initialSize = rs.getInt("initialSize");
|
||||
final boolean testOnBorrow = rs.getBoolean("testOnBorrow");
|
||||
final long validationInterval = rs.getLong("validationInterval");
|
||||
final boolean removeAbandoned = rs.getBoolean("removeAbandoned");
|
||||
final int removeAbandonedTimeout = rs.getInt("removeAbandonedTimeout");
|
||||
final boolean logAbandoned = rs.getBoolean("logAbandoned");
|
||||
final int abandonWhenPercentageFull = rs.getInt("abandonedWhenPercentageFull");
|
||||
final int maxActive = rs.getInt("poolMaxActive");
|
||||
final int minIdle = rs.getInt("poolMinIdle");
|
||||
final int maxIdle = rs.getInt("poolMaxIdle");
|
||||
final int suspectTimeout = rs.getInt("poolSuspectTimeout");
|
||||
final int timeBetweenEvictionRunsMillis = rs.getInt("poolTimeBetweenEvictionRunsMillis");
|
||||
final int minEvictableIdleTimeMillis = rs.getInt("poolMinEvictableIdleTimeMillis");
|
||||
int maxRetriesOnDeadlock = rs.getInt("maxRetriesOnDeadlock");
|
||||
int maxIntervalBetweenRetries = rs.getInt("maxIntervalBetweenRetries");
|
||||
|
||||
maxRetriesOnDeadlock = bindValueInMinMaxRange(maxRetriesOnDeadlock, 0, 15);
|
||||
maxIntervalBetweenRetries = bindValueInMinMaxRange(maxIntervalBetweenRetries, 1, 15);
|
||||
|
||||
return new FineractPlatformTenantConnection(connectionId, schemaName, schemaServer, schemaServerPort,
|
||||
schemaConnectionParameters, schemaUsername, schemaPassword, autoUpdateEnabled, initialSize, validationInterval,
|
||||
removeAbandoned, removeAbandonedTimeout, logAbandoned, abandonWhenPercentageFull, maxActive, minIdle, maxIdle,
|
||||
suspectTimeout, timeBetweenEvictionRunsMillis, minEvictableIdleTimeMillis, maxRetriesOnDeadlock,
|
||||
maxIntervalBetweenRetries, testOnBorrow);
|
||||
|
||||
}
|
||||
|
||||
private int bindValueInMinMaxRange(final int value, int min, int max) {
|
||||
if (value < min) {
|
||||
return min;
|
||||
} else if (value > max) {
|
||||
return max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "tenantsById")
|
||||
public FineractPlatformTenant loadTenantById(final String tenantIdentifier) {
|
||||
|
||||
try {
|
||||
final TenantMapper rm = new TenantMapper();
|
||||
final TenantMapper rm = new TenantMapper(false);
|
||||
final String sql = "select " + rm.schema() + " where t.identifier = ?";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { tenantIdentifier }); // NOSONAR
|
||||
@@ -141,7 +58,7 @@ public class JdbcTenantDetailsService implements TenantDetailsService {
|
||||
|
||||
@Override
|
||||
public List<FineractPlatformTenant> findAllTenants() {
|
||||
final TenantMapper rm = new TenantMapper();
|
||||
final TenantMapper rm = new TenantMapper(false);
|
||||
final String sql = "select " + rm.schema();
|
||||
|
||||
final List<FineractPlatformTenant> fineractPlatformTenants = this.jdbcTemplate.query(sql, rm); // NOSONAR
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.fineract.infrastructure.security.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
public final class TenantMapper implements RowMapper<FineractPlatformTenant> {
|
||||
|
||||
private final boolean isReport;
|
||||
private static final String TENANT_SERVER_CONNECTION_BUILDER = " t.id, ts.id as connectionId , "
|
||||
+ " t.timezone_id as timezoneId , t.name,t.identifier, ts.schema_name as schemaName, ts.schema_server as schemaServer,"
|
||||
+ " ts.schema_server_port as schemaServerPort, ts.schema_connection_parameters as schemaConnectionParameters, ts.auto_update as autoUpdate,"
|
||||
+ " ts.schema_username as schemaUsername, ts.schema_password as schemaPassword , ts.pool_initial_size as initialSize,"
|
||||
+ " ts.pool_validation_interval as validationInterval, ts.pool_remove_abandoned as removeAbandoned, ts.pool_remove_abandoned_timeout as removeAbandonedTimeout,"
|
||||
+ " ts.pool_log_abandoned as logAbandoned, ts.pool_abandon_when_percentage_full as abandonedWhenPercentageFull, ts.pool_test_on_borrow as testOnBorrow,"
|
||||
+ " ts.pool_max_active as poolMaxActive, ts.pool_min_idle as poolMinIdle, ts.pool_max_idle as poolMaxIdle,"
|
||||
+ " ts.pool_suspect_timeout as poolSuspectTimeout, ts.pool_time_between_eviction_runs_millis as poolTimeBetweenEvictionRunsMillis,"
|
||||
+ " ts.pool_min_evictable_idle_time_millis as poolMinEvictableIdleTimeMillis,"
|
||||
+ " ts.deadlock_max_retries as maxRetriesOnDeadlock," + " ts.deadlock_max_retry_interval as maxIntervalBetweenRetries,"
|
||||
+ " ts.readonly_schema_server as readOnlySchemaServer, " + " ts.readonly_schema_server_port as readOnlySchemaServerPort, "
|
||||
+ " ts.readonly_schema_name as readOnlySchemaName, " + " ts.readonly_schema_username as readOnlySchemaUsername, "
|
||||
+ " ts.readonly_schema_password as readOnlySchemaPassword, "
|
||||
+ " ts.readonly_schema_connection_parameters as readOnlySchemaConnectionParameters "
|
||||
+ " from tenants t left join tenant_server_connections ts ";
|
||||
private final StringBuilder sqlBuilder = new StringBuilder(TENANT_SERVER_CONNECTION_BUILDER);
|
||||
|
||||
TenantMapper(boolean isReport) {
|
||||
this.isReport = isReport;
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
if (this.isReport) {
|
||||
this.sqlBuilder.append(" on t.report_Id = ts.id");
|
||||
} else {
|
||||
this.sqlBuilder.append(" on t.oltp_Id = ts.id");
|
||||
}
|
||||
return this.sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FineractPlatformTenant mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
final Long id = rs.getLong("id");
|
||||
final String tenantIdentifier = rs.getString("identifier");
|
||||
final String name = rs.getString("name");
|
||||
final String timezoneId = rs.getString("timezoneId");
|
||||
final FineractPlatformTenantConnection connection = getDBConnection(rs);
|
||||
return new FineractPlatformTenant(id, tenantIdentifier, name, timezoneId, connection);
|
||||
}
|
||||
|
||||
// gets the DB connection
|
||||
private FineractPlatformTenantConnection getDBConnection(ResultSet rs) throws SQLException {
|
||||
|
||||
final Long connectionId = rs.getLong("connectionId");
|
||||
final String schemaName = rs.getString("schemaName");
|
||||
final String schemaServer = rs.getString("schemaServer");
|
||||
final String schemaServerPort = rs.getString("schemaServerPort");
|
||||
final String schemaConnectionParameters = rs.getString("schemaConnectionParameters");
|
||||
final String schemaUsername = rs.getString("schemaUsername");
|
||||
final String schemaPassword = rs.getString("schemaPassword");
|
||||
final String readOnlySchemaName = rs.getString("readOnlySchemaName");
|
||||
final String readOnlySchemaServer = rs.getString("readOnlySchemaServer");
|
||||
final String readOnlySchemaServerPort = rs.getString("readOnlySchemaServerPort");
|
||||
final String readOnlySchemaUsername = rs.getString("readOnlySchemaUsername");
|
||||
final String readOnlySchemaPassword = rs.getString("readOnlySchemaPassword");
|
||||
final String readOnlySchemaConnectionParameters = rs.getString("readOnlySchemaConnectionParameters");
|
||||
|
||||
final boolean autoUpdateEnabled = rs.getBoolean("autoUpdate");
|
||||
final int initialSize = rs.getInt("initialSize");
|
||||
final boolean testOnBorrow = rs.getBoolean("testOnBorrow");
|
||||
final long validationInterval = rs.getLong("validationInterval");
|
||||
final boolean removeAbandoned = rs.getBoolean("removeAbandoned");
|
||||
final int removeAbandonedTimeout = rs.getInt("removeAbandonedTimeout");
|
||||
final boolean logAbandoned = rs.getBoolean("logAbandoned");
|
||||
final int abandonWhenPercentageFull = rs.getInt("abandonedWhenPercentageFull");
|
||||
final int maxActive = rs.getInt("poolMaxActive");
|
||||
final int minIdle = rs.getInt("poolMinIdle");
|
||||
final int maxIdle = rs.getInt("poolMaxIdle");
|
||||
final int suspectTimeout = rs.getInt("poolSuspectTimeout");
|
||||
final int timeBetweenEvictionRunsMillis = rs.getInt("poolTimeBetweenEvictionRunsMillis");
|
||||
final int minEvictableIdleTimeMillis = rs.getInt("poolMinEvictableIdleTimeMillis");
|
||||
int maxRetriesOnDeadlock = rs.getInt("maxRetriesOnDeadlock");
|
||||
int maxIntervalBetweenRetries = rs.getInt("maxIntervalBetweenRetries");
|
||||
|
||||
maxRetriesOnDeadlock = bindValueInMinMaxRange(maxRetriesOnDeadlock, 0, 15);
|
||||
maxIntervalBetweenRetries = bindValueInMinMaxRange(maxIntervalBetweenRetries, 1, 15);
|
||||
|
||||
return new FineractPlatformTenantConnection(connectionId, schemaName, schemaServer, schemaServerPort, schemaConnectionParameters,
|
||||
schemaUsername, schemaPassword, autoUpdateEnabled, initialSize, validationInterval, removeAbandoned, removeAbandonedTimeout,
|
||||
logAbandoned, abandonWhenPercentageFull, maxActive, minIdle, maxIdle, suspectTimeout, timeBetweenEvictionRunsMillis,
|
||||
minEvictableIdleTimeMillis, maxRetriesOnDeadlock, maxIntervalBetweenRetries, testOnBorrow, readOnlySchemaServer,
|
||||
readOnlySchemaServerPort, readOnlySchemaName, readOnlySchemaUsername, readOnlySchemaPassword,
|
||||
readOnlySchemaConnectionParameters);
|
||||
}
|
||||
|
||||
private int bindValueInMinMaxRange(final int value, int min, int max) {
|
||||
if (value < min) {
|
||||
return min;
|
||||
} else if (value > max) {
|
||||
return max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+1
@@ -23,4 +23,5 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<include file="parts/0003_reset_postgresql_sequences.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0004_readonly_database_connection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<changeSet author="fineract" id="add-readonly-database-connection-properties" context="tenant_store_db">
|
||||
<addColumn tableName="tenant_server_connections">
|
||||
<column name="readonly_schema_server" type="VARCHAR(100)"/>
|
||||
</addColumn>
|
||||
<addColumn tableName="tenant_server_connections">
|
||||
<column name="readonly_schema_name" type="VARCHAR(100)"/>
|
||||
</addColumn>
|
||||
<addColumn tableName="tenant_server_connections">
|
||||
<column name="readonly_schema_server_port" type="VARCHAR(10)"/>
|
||||
</addColumn>
|
||||
<addColumn tableName="tenant_server_connections">
|
||||
<column name="readonly_schema_username" type="VARCHAR(100)"/>
|
||||
</addColumn>
|
||||
<addColumn tableName="tenant_server_connections">
|
||||
<column name="readonly_schema_password" type="VARCHAR(100)"/>
|
||||
</addColumn>
|
||||
<addColumn tableName="tenant_server_connections">
|
||||
<column name="readonly_schema_connection_parameters" type="TEXT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+5
@@ -25,6 +25,11 @@
|
||||
<dropForeignKeyConstraint baseTableName="job_run_history" constraintName="scheduledjobsFK"/>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="1">
|
||||
<validCheckSum>8:18ed72e1958f7db9c1a0c983ac823ab3</validCheckSum> <!-- checksum withsout delete from history -->
|
||||
<validCheckSum>8:b4a83f9764270372a384616acf066d7c</validCheckSum> <!-- checksum with delete from history -->
|
||||
<sql>
|
||||
DELETE FROM job_run_history WHERE job_id IN (SELECT id FROM job WHERE name IN ('Update loan Summary', 'Update Loan Paid In Advance'))
|
||||
</sql>
|
||||
<delete tableName="job">
|
||||
<where>name='Update loan Summary'</where>
|
||||
</delete>
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
import javax.sql.DataSource;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.apache.fineract.infrastructure.core.db.DatabaseConnectionProperties;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||
import org.apache.fineract.infrastructure.core.service.DataSourcePerTenantServiceFactory;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
@TestPropertySource("classpath:application-test.properties")
|
||||
public class TomcatJdbcDataSourcePerTenantServiceTest {
|
||||
|
||||
@Mock
|
||||
private FineractProperties fineractProperties;
|
||||
|
||||
@Mock
|
||||
private HikariConfig hikariConfig;
|
||||
|
||||
@Mock
|
||||
private Connection connection;
|
||||
|
||||
@Mock
|
||||
private FineractPlatformTenant defaultTenant;
|
||||
|
||||
@Mock
|
||||
private FineractPlatformTenantConnection tenantConnection;
|
||||
|
||||
@InjectMocks
|
||||
private DataSourcePerTenantServiceFactory underTest;
|
||||
|
||||
private DataSource dataSource;
|
||||
private DataSource tenantDataSource;
|
||||
private DatabaseConnectionProperties databaseConnectionProperties;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws SQLException {
|
||||
this.databaseConnectionProperties = DatabaseConnectionProperties.instance(System.getProperty("dbType"));
|
||||
|
||||
tenantDataSource = mock(HikariDataSource.class);
|
||||
given(tenantDataSource.getConnection()).willReturn(connection);
|
||||
given(connection.getMetaData()).willReturn(mock(DatabaseMetaData.class));
|
||||
given(connection.getMetaData().getURL()).willReturn(databaseConnectionProperties.getJdbcUrl());
|
||||
|
||||
given(tenantConnection.getSchemaServer()).willReturn(databaseConnectionProperties.getSchemaServer());
|
||||
given(tenantConnection.getSchemaServerPort()).willReturn(databaseConnectionProperties.getSchemaPort());
|
||||
given(tenantConnection.getSchemaUsername()).willReturn(databaseConnectionProperties.getSchemaUsername());
|
||||
given(tenantConnection.getSchemaPassword()).willReturn(databaseConnectionProperties.getSchemaPassword());
|
||||
given(tenantConnection.getSchemaName()).willReturn(databaseConnectionProperties.getSchemaName());
|
||||
|
||||
given(defaultTenant.getConnection()).willReturn(tenantConnection);
|
||||
given(defaultTenant.getConnection().getMaxActive()).willReturn(5);
|
||||
given(defaultTenant.getConnection().getValidationInterval()).willReturn(500L);
|
||||
|
||||
given(hikariConfig.getInitializationFailTimeout()).willReturn(0L);
|
||||
given(hikariConfig.getDriverClassName()).willReturn(databaseConnectionProperties.getDriverClassName());
|
||||
given(hikariConfig.getConnectionTestQuery()).willReturn(databaseConnectionProperties.getConnectionTestQuery());
|
||||
given(hikariConfig.getDataSourceProperties()).willReturn(mock(Properties.class));
|
||||
given(hikariConfig.isAutoCommit()).willReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRetrieveDataSource_ShouldCreateDataSource_WhenFineractIsInAllMode() {
|
||||
// given
|
||||
FineractProperties.FineractModeProperties modeProperties = createModeProps(true, true, true);
|
||||
given(fineractProperties.getMode()).willReturn(modeProperties);
|
||||
|
||||
// when
|
||||
dataSource = underTest.createNewDataSourceFor(tenantDataSource, defaultTenant.getConnection());
|
||||
|
||||
// then
|
||||
assertNotNull(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRetrieveDataSource_ShouldCreateDataSource_WhenFineractIsInReadOnlyMode() {
|
||||
// given
|
||||
FineractProperties.FineractModeProperties modeProperties = createModeProps(true, false, false);
|
||||
given(fineractProperties.getMode()).willReturn(modeProperties);
|
||||
|
||||
// when
|
||||
dataSource = underTest.createNewDataSourceFor(tenantDataSource, defaultTenant.getConnection());
|
||||
|
||||
// then
|
||||
assertNotNull(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRetrieveDataSource_ShouldCreateDataSource_WhenFineractIsInBatchMode() {
|
||||
// given
|
||||
FineractProperties.FineractModeProperties modeProperties = createModeProps(false, false, true);
|
||||
given(fineractProperties.getMode()).willReturn(modeProperties);
|
||||
|
||||
// when
|
||||
dataSource = underTest.createNewDataSourceFor(tenantDataSource, defaultTenant.getConnection());
|
||||
|
||||
// then
|
||||
assertNotNull(dataSource);
|
||||
}
|
||||
|
||||
private FineractProperties.FineractModeProperties createModeProps(boolean readEnabled, boolean writeEnabled, boolean batchEnabled) {
|
||||
FineractProperties.FineractModeProperties modeProperties = new FineractProperties.FineractModeProperties();
|
||||
modeProperties.setReadEnabled(readEnabled);
|
||||
modeProperties.setWriteEnabled(writeEnabled);
|
||||
modeProperties.setBatchEnabled(batchEnabled);
|
||||
return modeProperties;
|
||||
}
|
||||
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.fineract.infrastructure.core.db;
|
||||
|
||||
public class DatabaseConnectionProperties {
|
||||
|
||||
private String driverClassName;
|
||||
private String jdbcUrl;
|
||||
private String connectionTestQuery;
|
||||
|
||||
private String schemaServer;
|
||||
private String schemaName;
|
||||
private String schemaPort;
|
||||
private String schemaUsername;
|
||||
private String schemaPassword;
|
||||
|
||||
protected DatabaseConnectionProperties(final String driverClassName, final String jdbcUrl, final String schemaPort,
|
||||
final String schemaPassword) {
|
||||
this.driverClassName = driverClassName;
|
||||
this.jdbcUrl = jdbcUrl;
|
||||
this.schemaPort = schemaPort;
|
||||
this.schemaPassword = schemaPassword;
|
||||
|
||||
this.schemaServer = "localhost";
|
||||
this.schemaUsername = "root";
|
||||
this.schemaName = "fineract_tenants";
|
||||
this.connectionTestQuery = "SELECT 1";
|
||||
}
|
||||
|
||||
public static DatabaseConnectionProperties instance(final String dbType) {
|
||||
return new DatabaseConnectionProperties(getDbDriverClassName(dbType), buildJdbcUrl(dbType), getDbPort(dbType),
|
||||
getDbPassword(dbType));
|
||||
}
|
||||
|
||||
private static String getDbDriverClassName(final String dbType) {
|
||||
if (dbType.equals("mariadb")) {
|
||||
return "org.mariadb.jdbc.Driver";
|
||||
} else if (dbType.equals("mysql")) {
|
||||
return "com.mysql.cj.jdbc.Driver";
|
||||
} else {
|
||||
return "org.postgresql.Driver";
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildJdbcUrl(final String dbType) {
|
||||
return "jdbc:" + dbType + "://localhost:" + getDbPort(dbType) + "/fineract_tenants";
|
||||
}
|
||||
|
||||
private static String getDbPort(final String dbType) {
|
||||
if (dbType.equals("postgresql")) {
|
||||
return "5432";
|
||||
}
|
||||
return "3306";
|
||||
}
|
||||
|
||||
private static String getDbPassword(final String dbType) {
|
||||
if (dbType.equals("postgresql")) {
|
||||
return "postgres";
|
||||
}
|
||||
return "mysql";
|
||||
}
|
||||
|
||||
public String getDriverClassName() {
|
||||
return driverClassName;
|
||||
}
|
||||
|
||||
public String getJdbcUrl() {
|
||||
return jdbcUrl;
|
||||
}
|
||||
|
||||
public String getConnectionTestQuery() {
|
||||
return connectionTestQuery;
|
||||
}
|
||||
|
||||
public String getSchemaServer() {
|
||||
return schemaServer;
|
||||
}
|
||||
|
||||
public String getSchemaName() {
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public String getSchemaPort() {
|
||||
return schemaPort;
|
||||
}
|
||||
|
||||
public String getSchemaUsername() {
|
||||
return schemaUsername;
|
||||
}
|
||||
|
||||
public String getSchemaPassword() {
|
||||
return schemaPassword;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user