FINERACT-796

Use Hikari instead of Tomcat Connection Pool
 - Created hikari connection pool bean
 - Configured connection parameters to match hikari
 - Removed tomcat-jdbc and dbcp
 - Remove unused classes
 - Add Hikari to logback
 - update hikaridatasource bean

closes https://issues.apache.org/jira/browse/FINERACT-796

remove hikaricp import from gradle files

more specific bean config

- Set up datasource properties
- Cleanup unused classes
- Add hikari to logback
This commit is contained in:
xurror
2020-03-28 15:06:34 +01:00
committed by Michael Vorburger ⛑️
parent 2e620b4de8
commit 3475c0cfb7
20 changed files with 100 additions and 496 deletions
@@ -39,7 +39,7 @@ import org.springframework.context.annotation.ImportResource;
*/
public class WarWebApplicationInitializer extends SpringBootServletInitializer {
@ImportResource({ "classpath*:META-INF/spring/jndi.xml" })
@ImportResource({ "classpath*:META-INF/spring/hikariDataSource.xml" })
private static class Configuration extends AbstractApplicationConfiguration {
}
@@ -1,56 +0,0 @@
/**
* 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.boot.db;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.boot.JDBCDriverConfig;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration for a DataSource.
* @see DataSourceProperties about how to configure this DS
*/
@Configuration
public class DataSourceConfiguration {
private static final Logger logger = LoggerFactory.getLogger(DataSourceConfiguration.class);
@Autowired JDBCDriverConfig config ;
@Bean
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties(config.getDriverClassName(), config.getProtocol(), config.getSubProtocol(), config.getPort());
}
@Bean
public DataSource tenantDataSourceJndi() {
PoolConfiguration p = getProperties();
org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource(p);
logger.info("Created new DataSource; url={}", p.getUrl());
return ds;
}
protected DataSourceProperties getProperties() {
return dataSourceProperties();
}
}
@@ -1,156 +0,0 @@
/**
* 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.boot.db;
import javax.validation.constraints.NotNull;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
/**
* Configurable DataSource. Properties have sensible defaults, but end-users can
* override those via the Spring Values listed below; i.e. via -D Java System
* properties, or main() command line arguments, OS environment variables, from
* JNDI, or application.properties (thanks Spring Boot). For example:
* -Dfineract.datasource.port=3307.
*/
// NOT a @Component - we do not want this to picked up by component scan, only explicitly declared in DataSourceConfiguration (if that's active)
public class DataSourceProperties extends PoolProperties {
public final static String PORT = "fineract.datasource.port";
public final static String HOST = "fineract.datasource.host";
public final static String DB = "fineract.datasource.db";
public final static String UID = "fineract.datasource.username";
public final static String PWD = "fineract.datasource.password";
public final static String PROTOCOL = "fineract.datasource.protocol";
public final static String SUBPROTOCOL = "fineract.datasource.subprotocol";
@Value("${" + PORT + ":3306}")
private volatile @NotNull int port;
@Value("${" + HOST + ":localhost}")
private volatile @NotNull String hostname;
@Value("${" + DB + ":fineract_tenants}")
private volatile @NotNull String dbName;
@Value("${" + UID + ":root}")
private volatile @NotNull String username;
@Value("${" + PWD + ":mysql}")
private volatile @NotNull String password;
@Value("${" + PROTOCOL + ":jdbc}")
private volatile @NotNull String jdbcProtocol;
@Value("${" + SUBPROTOCOL + ":mysql:thin}")
private volatile @NotNull String jdbcSubprotocol;
public DataSourceProperties(String driverClassName, String protocol, String subProtocol, Integer port) {
super();
setDriverClassName(driverClassName);
this.jdbcProtocol = protocol ;
this.jdbcSubprotocol = subProtocol ;
this.port = port ;
setDefaults();
}
/**
* as per (some of..) INSTALL.md and
* org.apache.fineract.infrastructure.core.service
* .TomcatJdbcDataSourcePerTenantService
* .createNewDataSourceFor(FineractPlatformTenant)
*/
protected void setDefaults() {
setInitialSize(3);
// setMaxIdle(6); -- strange, why?
// setMinIdle(3); -- JavaDoc says default is initialSize.. so shouldn't
// be needed
if (getValidationQuery() == null) setValidationQuery("SELECT 1");
setTestOnBorrow(true);
setTestOnReturn(true);
setTestWhileIdle(true);
setTimeBetweenEvictionRunsMillis(30000);
setTimeBetweenEvictionRunsMillis(60000);
setLogAbandoned(true);
setSuspectTimeout(60);
setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"
+ "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport");
}
@Override
public void setUrl(@SuppressWarnings("unused") String url) {
throw new UnsupportedOperationException("Use setHost/Port/DB() instead of setURL()");
}
@Override
public String getUrl() {
String url = super.getUrl();
if (StringUtils.hasText(url)) {
throw new IllegalStateException();
}
return jdbcProtocol + ":" + jdbcSubprotocol + "://" + getHost() + ":" + getPort() + "/" + getDBName();
}
public String getHost() {
return hostname;
}
public int getPort() {
return port;
}
public String getDBName() {
return dbName;
}
public void setPort(int port) {
this.port = port;
}
public void setHost(String hostname) {
this.hostname = hostname;
}
public void setDBName(String dbName) {
this.dbName = dbName;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public void setUsername(String username) {
this.username = username;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public void setPassword(String password) {
this.password = password;
}
}
@@ -1,93 +0,0 @@
/**
* 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.boot.db;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
/**
* Service which "fixes up" the schemaServerPort in the tenants table of the
* fineract_tenants schema. It sets it to the actual current port of
* MariaDB4j, instead of the default 3306 which is hard-coded in the initial
* set-up SQL script (V1__mifos-platform-shared-tenants.sql).
*
* This service is called by the TenantDatabaseUpgradeService
* "just at the right time" during start-up, that is AFTER the initialization of
* the fineract_tenants but BEFORE Flyway runs on all tenant schemas.
*
* It's difficult to achieve the same goal elsewhere, because we cannot do this
* e.g. in MariaDB4jSetupService, as that's too early
* (TenantDatabaseUpgradeService has not yet run), nor e.g. in
* TomcatJdbcDataSourcePerTenantService because in there we do not have access
* to and should not depend on MariaDB4j configuration.
*/
@Service
public class TenantDataSourcePortFixService {
private static final Logger logger = LoggerFactory.getLogger(TenantDataSourcePortFixService.class);
/**
* While what this class does is convenient in 96% you may would like to
* completely disable it if you've hand tuned your tenants table for an
* advanced configuration and use e.g. different databases maybe on
* different hosts for different tenants.
*/
public final static String ENABLED = "fineract.tenantdb.fixup";
@Value("${" + ENABLED + ":true}")
private boolean enabled;
// required=false is important here, because in
// WebApplicationInitializerConfiguration for classic WAR there
// is (intentionally) no MariaDB4j nor a DataSourceProperties
// bean (because in the WAR we're using a DS from JNDI)
private @Autowired(required = false) DataSourceProperties dsp;
private JdbcTemplate jdbcTemplate;
@Autowired
public TenantDataSourcePortFixService(@Qualifier("tenantDataSourceJndi") final DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public void fixUpTenantsSchemaServerPort() {
if (!enabled) {
logger.info("No schema_server_port UPDATE made to tenant_server_connections table of the fineract_tenants schema, because {} = false", ENABLED);
return;
}
if (dsp == null) {
// we don't have any generic mechanism to know the DB port, given just a tenant DataSource
logger.debug("No schema_server_port UPDATE made to tenant_server_connections table of the fineract_tenants schema (because neither MariaDB4j nor our own Spring Boot DataSourceConfiguration is used in a traditional WAR)");
return;
}
int r = jdbcTemplate
.update("UPDATE tenant_server_connections SET schema_server = ?, schema_server_port = ?, schema_username = ?, schema_password = ?",
dsp.getHost(), dsp.getPort(), dsp.getUsername(), dsp.getPassword());
if ( r == 0 )
logger.warn("UPDATE tenant_server_connections SET ... did not update ANY rows - something is probably wrong");
else
logger.info("Upated {} rows in the tenant_server_connections table of the fineract_tenants schema to the real current host: {}, port: {}",
new Object[] { r, dsp.getHost(), dsp.getPort() });
}
}
@@ -32,7 +32,7 @@ public class DataSourceForTenants implements RoutingDataSourceService {
private final DataSource tenantDataSource;
@Autowired
public DataSourceForTenants(final @Qualifier("tenantDataSourceJndi") DataSource tenantDataSource) {
public DataSourceForTenants(final @Qualifier("hikariTenantDataSource") DataSource tenantDataSource) {
this.tenantDataSource = tenantDataSource;
}
@@ -26,7 +26,6 @@ import java.util.List;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.boot.JDBCDriverConfig;
import org.apache.fineract.infrastructure.core.boot.db.TenantDataSourcePortFixService;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
@@ -47,16 +46,13 @@ public class TenantDatabaseUpgradeService {
private final TenantDetailsService tenantDetailsService;
protected final DataSource tenantDataSource;
protected final TenantDataSourcePortFixService tenantDataSourcePortFixService;
@Autowired private JDBCDriverConfig driverConfig;
@Autowired
public TenantDatabaseUpgradeService(final TenantDetailsService detailsService,
@Qualifier("tenantDataSourceJndi") final DataSource dataSource, TenantDataSourcePortFixService tenantDataSourcePortFixService) {
public TenantDatabaseUpgradeService(final TenantDetailsService detailsService, @Qualifier("hikariTenantDataSource") final DataSource dataSource) {
this.tenantDetailsService = detailsService;
this.tenantDataSource = dataSource;
this.tenantDataSourcePortFixService = tenantDataSourcePortFixService;
}
@PostConstruct
@@ -104,8 +100,6 @@ public class TenantDatabaseUpgradeService {
"fineract_default_tenantdb_uid", dbUid,
"fineract_default_tenantdb_pwd", dbPwd));
flyway.migrate();
tenantDataSourcePortFixService.fixUpTenantsSchemaServerPort();
}
private String getEnvVar(String name, String defaultValue) {
@@ -18,14 +18,14 @@
*/
package org.apache.fineract.infrastructure.core.service;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.boot.JDBCDriverConfig;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@@ -48,7 +48,7 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
private JDBCDriverConfig driverConfig ;
@Autowired
public TomcatJdbcDataSourcePerTenantService(final @Qualifier("tenantDataSourceJndi") DataSource tenantDataSource) {
public TomcatJdbcDataSourcePerTenantService(final @Qualifier("hikariTenantDataSource") DataSource tenantDataSource) {
this.tenantDataSource = tenantDataSource;
}
@@ -85,42 +85,20 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
// http://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency
// see also org.apache.fineract.DataSourceProperties.setDefaults()
String jdbcUrl = this.driverConfig.constructProtocol(tenantConnectionObj.getSchemaServer(), tenantConnectionObj.getSchemaServerPort(), tenantConnectionObj.getSchemaName()) ;
//final String jdbcUrl = tenantConnectionObj.databaseURL();
final PoolConfiguration poolConfiguration = new PoolProperties();
poolConfiguration.setDriverClassName(this.driverConfig.getDriverClassName());
poolConfiguration.setName(tenantConnectionObj.getSchemaName() + "_pool");
poolConfiguration.setUrl(jdbcUrl);
poolConfiguration.setUsername(tenantConnectionObj.getSchemaUsername());
poolConfiguration.setPassword(tenantConnectionObj.getSchemaPassword());
String jdbcUrl = this.driverConfig.constructProtocol(tenantConnectionObj.getSchemaServer(), tenantConnectionObj.getSchemaServerPort(), tenantConnectionObj.getSchemaName());
poolConfiguration.setInitialSize(tenantConnectionObj.getInitialSize());
HikariConfig config = new HikariConfig();
config.setDriverClassName(this.driverConfig.getDriverClassName());
config.setPoolName(tenantConnectionObj.getSchemaName() + "_pool");
config.setJdbcUrl(jdbcUrl);
config.setUsername(tenantConnectionObj.getSchemaUsername());
config.setPassword(tenantConnectionObj.getSchemaPassword());
poolConfiguration.setTestOnBorrow(tenantConnectionObj.isTestOnBorrow());
poolConfiguration.setValidationQuery("SELECT 1");
poolConfiguration.setValidationInterval(tenantConnectionObj.getValidationInterval());
config.setConnectionTestQuery("SELECT 1");
config.setValidationTimeout(tenantConnectionObj.getValidationInterval());
poolConfiguration.setRemoveAbandoned(tenantConnectionObj.isRemoveAbandoned());
poolConfiguration.setRemoveAbandonedTimeout(tenantConnectionObj.getRemoveAbandonedTimeout());
poolConfiguration.setLogAbandoned(tenantConnectionObj.isLogAbandoned());
poolConfiguration.setAbandonWhenPercentageFull(tenantConnectionObj.getAbandonWhenPercentageFull());
poolConfiguration.setDefaultAutoCommit(true);
config.setAutoCommit(true);
/**
* Vishwas- Do we need to enable the below properties and add
* ResetAbandonedTimer for long running batch Jobs?
**/
// poolConfiguration.setMaxActive(tenant.getMaxActive());
// poolConfiguration.setMinIdle(tenant.getMinIdle());
// poolConfiguration.setMaxIdle(tenant.getMaxIdle());
// poolConfiguration.setSuspectTimeout(tenant.getSuspectTimeout());
// poolConfiguration.setTimeBetweenEvictionRunsMillis(tenant.getTimeBetweenEvictionRunsMillis());
// poolConfiguration.setMinEvictableIdleTimeMillis(tenant.getMinEvictableIdleTimeMillis());
poolConfiguration.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"
+ "org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport");
return new org.apache.tomcat.jdbc.pool.DataSource(poolConfiguration);
return new HikariDataSource(config);
}
}
@@ -42,7 +42,7 @@ public class BasicAuthTenantDetailsServiceJdbc implements BasicAuthTenantDetails
private final JdbcTemplate jdbcTemplate;
@Autowired
public BasicAuthTenantDetailsServiceJdbc(@Qualifier("tenantDataSourceJndi") final DataSource dataSource) {
public BasicAuthTenantDetailsServiceJdbc(@Qualifier("hikariTenantDataSource") final DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@@ -43,7 +43,7 @@ public class JdbcTenantDetailsService implements TenantDetailsService {
private final JdbcTemplate jdbcTemplate;
@Autowired
public JdbcTenantDetailsService(@Qualifier("tenantDataSourceJndi") final DataSource dataSource) {
public JdbcTenantDetailsService(@Qualifier("hikariTenantDataSource") final DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}