diff --git a/README.md b/README.md index b5980ef4593..be4a35051cb 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Instructions to build the JAR file The tenants database connection details are configured [via environment variables (as with Docker container)](#instructions-to-run-using-docker-and-docker-compose), e.g. like this: - export fineract_tenants_pwd=verysecret + export FINERACT_HIKARI_PASSWORD=verysecret ... java -jar fineract-provider.jar @@ -179,6 +179,13 @@ _(Note that in previous versions, the `mysqlserver` environment variable used at and the `mysqlserver` environment variable is now no longer supported.)_ +Connection pool configuration +============================= + +Please check `application.properties` to see which connection pool settings can be tweaked. The associated environment variables are prefixed with `FINERACT_HIKARI_*`. You can find more information about specific connection pool settings (Hikari) at https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby + +NOTE: we'll keep backwards compatibility until one of the next releases to ensure that things are working as expected. Environment variables prefixed `fineract_tenants_*` can still be used to configure the database connection, but we strongly encourage using `FINERACT_HIKARI_*` with more options. + Instructions to run on Kubernetes ================================= diff --git a/docker-compose.yml b/docker-compose.yml index b4d0af95da2..c38e6701745 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,19 +49,47 @@ services: fineractmysql: condition: service_healthy environment: - - DRIVERCLASS_NAME=org.mariadb.jdbc.Driver - - PROTOCOL=jdbc - - node_id=1 - - SUB_PROTOCOL=mariadb - - fineract_tenants_driver=org.mariadb.jdbc.Driver - - fineract_tenants_url=jdbc:mariadb://fineractmysql:3306/fineract_tenants - - fineract_tenants_uid=root - - fineract_tenants_pwd=skdcnwauicn2ucnaecasdsajdnizucawencascdca + # TODO: env vars prefixed with "fineract_tenants_*" will be removed with one of the next releases + #- fineract_tenants_driver=org.mariadb.jdbc.Driver + #- fineract_tenants_url=jdbc:mariadb://fineractmysql:3306/fineract_tenants + #- fineract_tenants_uid=root + #- fineract_tenants_pwd=skdcnwauicn2ucnaecasdsajdnizucawencascdca + # NOTE: node aware scheduler + - FINERACT_NODE_ID=1 + # NOTE: env vars prefixed "FINERACT_HIKARI_*" are used to configure the database connection pool + - FINERACT_HIKARI_DRIVER_CLASS_NAME=org.mariadb.jdbc.Driver + - FINERACT_HIKARI_JDBC_URL=jdbc:mariadb://fineractmysql:3306/fineract_tenants + - FINERACT_HIKARI_USERNAME=root + - FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca + # ... following variables are optional; "application.properties" contains reasonable defaults (same as here) + - FINERACT_HIKARI_MINIMUM_IDLE=3 + - FINERACT_HIKARI_MAXIMUM_POOL_SIZE=10 + - FINERACT_HIKARI_IDLE_TIMEOUT=60000 + - FINERACT_HIKARI_CONNECTION_TIMEOUT=20000 + - FINERACT_HIKARI_TEST_QUERY=SELECT 1 + - FINERACT_HIKARI_AUTO_COMMIT=true + - FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS=true + - FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE=250 + - FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT=2048 + - FINERACT_HIKARI_DS_PROPERTIES_USE_SERVER_PREP_STMTS=true + - FINERACT_HIKARI_DS_PROPERTIES_USE_LOCAL_SESSION_STATE=true + - FINERACT_HIKARI_DS_PROPERTIES_REWRITE_BATCHED_STATEMENTS=true + - FINERACT_HIKARI_DS_PROPERTIES_CACHE_RESULT_SET_METADATA=true + - FINERACT_HIKARI_DS_PROPERTIES_CACHE_SERVER_CONFIGURATION=true + - FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS=true + - FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS=false + - FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES=true + - FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION=true + # NOTE: env vars prefixed "FINERACT_DEFAULT_TENANTDB_*" are used to create the default tenant database - FINERACT_DEFAULT_TENANTDB_HOSTNAME=fineractmysql - FINERACT_DEFAULT_TENANTDB_PORT=3306 - FINERACT_DEFAULT_TENANTDB_UID=root - FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca - FINERACT_DEFAULT_TENANTDB_CONN_PARAMS= + - FINERACT_DEFAULT_TENANTDB_TIMEZONE=Asia/Kolkata + - FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default + - FINERACT_DEFAULT_TENANTDB_NAME=fineract_default + - FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant # Frontend service community-app: diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle index 24ac8a3e537..dc60d25cf63 100644 --- a/fineract-provider/build.gradle +++ b/fineract-provider/build.gradle @@ -201,7 +201,7 @@ configurations { driver } dependencies { - driver 'org.mariadb.jdbc:mariadb-java-client:2.7.3' + driver 'org.mariadb.jdbc:mariadb-java-client:2.7.4' } URLClassLoader loader = GroovyObject.class.classLoader @@ -238,7 +238,7 @@ bootRun { ] dependencies { - implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.3' + implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.4' } classpath += files("build/generated/swagger-ui") @@ -316,7 +316,7 @@ jib { allowInsecureRegistries = true dependencies { - implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.3' + implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.4' } extraDirectories { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java index 1f9d0a8f7e9..26e032ae4f7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/AbstractApplicationConfiguration.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.core.boot; +import org.apache.fineract.infrastructure.core.config.FineractProperties; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; @@ -25,9 +26,9 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.transaction.annotation.EnableTransactionManagement; @@ -36,12 +37,12 @@ */ @Configuration -@PropertySource(value = "classpath:META-INF/spring/jdbc.properties") @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, FlywayAutoConfiguration.class, GsonAutoConfiguration.class, JdbcTemplateAutoConfiguration.class }) @EnableTransactionManagement @EnableWebSecurity +@EnableConfigurationProperties({ FineractProperties.class }) @ComponentScan(basePackages = "org.apache.fineract.**") public abstract class AbstractApplicationConfiguration { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/JDBCDriverConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/JDBCDriverConfig.java deleted file mode 100644 index 91a5f794a6a..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/JDBCDriverConfig.java +++ /dev/null @@ -1,61 +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; - -import javax.annotation.PostConstruct; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Service; - -@Service -public class JDBCDriverConfig { - - private static final String DRIVER_CLASS_PROPERTYNAME = "DRIVERCLASS_NAME"; - private static final String PROTOCOL_PROPERTYNAME = "PROTOCOL"; - private static final String SUBPROTOCOL_PROPERTYNAME = "SUB_PROTOCOL"; - - private String driverClassName; - private String protocol; - private String subProtocol; - - @Autowired - ApplicationContext context; - - @PostConstruct - protected void init() { - Environment environment = context.getEnvironment(); - driverClassName = environment.getProperty(DRIVER_CLASS_PROPERTYNAME); - protocol = environment.getProperty(PROTOCOL_PROPERTYNAME); - subProtocol = environment.getProperty(SUBPROTOCOL_PROPERTYNAME); - } - - public String getDriverClassName() { - return this.driverClassName; - } - - public String constructProtocol(String schemaServer, String schemaServerPort, String schemaName, String schemaConnectionParameters) { - StringBuilder sb = new StringBuilder(protocol).append(":").append(subProtocol).append("://").append(schemaServer).append(":") - .append(schemaServerPort).append('/').append(schemaName); - if (schemaConnectionParameters != null && !schemaConnectionParameters.isEmpty()) { - sb.append('?').append(schemaConnectionParameters); - } - return sb.toString(); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CompatibilityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CompatibilityConfig.java new file mode 100644 index 00000000000..a33a0191f69 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/CompatibilityConfig.java @@ -0,0 +1,151 @@ +/** + * 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.config; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import java.util.Properties; +import javax.annotation.PostConstruct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +@ConditionalOnExpression("#{ systemEnvironment['fineract_tenants_driver'] != null }") +@Deprecated // NOTE: this will be removed in one of the next releases (probably around version 1.7.x or 1.8.x) +public class CompatibilityConfig { + + private static final Logger LOG = LoggerFactory.getLogger(CompatibilityConfig.class); + + @Autowired + ApplicationContext context; + + @PostConstruct + public void init() { + Environment environment = context.getEnvironment(); + + LOG.warn("===============================================================================================\n"); + LOG.warn("You are using a deprecated tenant DB configuration:\n"); + LOG.warn("- Env var 'fineract_tenants_driver': {}", + environment.getProperty("fineract_tenants_driver")); + LOG.warn("- Env var 'fineract_tenants_url': {}", + environment.getProperty("fineract_tenants_url")); + LOG.warn("- Env var 'fineract_tenants_uid': {}", + environment.getProperty("fineract_tenants_uid")); + LOG.warn("- Env var 'fineract_tenants_pwd': ****\n"); + LOG.warn("The preferred way to configure the tenant DB is now via these environment variables:\n"); + LOG.warn("- Env var 'FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME': {}", + environment.getProperty("FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME")); + LOG.warn("- Env var 'FINERACT_HIKARI_JDBC_URL': {}", + environment.getProperty("FINERACT_HIKARI_JDBC_URL")); + LOG.warn("- Env var 'FINERACT_HIKARI_USERNAME': {}", + environment.getProperty("FINERACT_HIKARI_USERNAME")); + LOG.warn("- Env var 'FINERACT_HIKARI_PASSWORD': ****"); + LOG.warn("- Env var 'FINERACT_HIKARI_MINIMUM_IDLE': {}", + environment.getProperty("FINERACT_HIKARI_MINIMUM_IDLE")); + LOG.warn("- Env var 'FINERACT_HIKARI_MAXIMUM_POOL_SIZE': {}", + environment.getProperty("FINERACT_HIKARI_MAXIMUM_POOL_SIZE")); + LOG.warn("- Env var 'FINERACT_HIKARI_IDLE_TIMEOUT': {}", + environment.getProperty("FINERACT_HIKARI_IDLE_TIMEOUT")); + LOG.warn("- Env var 'FINERACT_HIKARI_CONNECTION_TIMEOUT': {}", + environment.getProperty("FINERACT_HIKARI_CONNECTION_TIMEOUT")); + LOG.warn("- Env var 'FINERACT_HIKARI_TEST_QUERY': {}", + environment.getProperty("FINERACT_HIKARI_TEST_QUERY")); + LOG.warn("- Env var 'FINERACT_HIKARI_AUTO_COMMIT': {}", + environment.getProperty("FINERACT_HIKARI_AUTO_COMMIT")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_USE_SERVER_PREP_STMTS': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_USE_SERVER_PREP_STMTS")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_USE_LOCAL_SESSION_STATE': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_USE_LOCAL_SESSION_STATE")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_REWRITE_BATCHED_STATEMENTS': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_REWRITE_BATCHED_STATEMENTS")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_CACHE_RESULT_SET_METADATA': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_CACHE_RESULT_SET_METADATA")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_CACHE_SERVER_CONFIGURATION': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_CACHE_SERVER_CONFIGURATION")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES")); + LOG.warn("- Env var 'FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION': {}", + environment.getProperty("FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION")); + LOG.warn("===============================================================================================\n"); + } + + @Bean(destroyMethod = "close") + public HikariDataSource hikariTenantDataSource(HikariConfig hc) { + return new HikariDataSource(hc); + } + + @Bean + public HikariConfig hikariConfig() { + Environment environment = context.getEnvironment(); + HikariConfig hc = new HikariConfig(); + + hc.setDriverClassName(environment.getProperty("fineract_tenants_driver")); + hc.setJdbcUrl(environment.getProperty("fineract_tenants_url")); + hc.setUsername(environment.getProperty("fineract_tenants_uid")); + hc.setPassword(environment.getProperty("fineract_tenants_pwd")); + hc.setMinimumIdle(3); + hc.setMaximumPoolSize(10); + hc.setIdleTimeout(60000); + hc.setConnectionTestQuery("SELECT 1"); + hc.setDataSourceProperties(dataSourceProperties()); + + return hc; + } + + // These are the properties for the all Tenants DB; the same configuration is also (hard-coded) in the + // TomcatJdbcDataSourcePerTenantService class --> + private Properties dataSourceProperties() { + Properties props = new Properties(); + + props.setProperty("cachePrepStmts", "true"); + props.setProperty("prepStmtCacheSize", "250"); + props.setProperty("prepStmtCacheSqlLimit", "2048"); + props.setProperty("useServerPrepStmts", "true"); + props.setProperty("useLocalSessionState", "true"); + props.setProperty("rewriteBatchedStatements", "true"); + props.setProperty("cacheResultSetMetadata", "true"); + props.setProperty("cacheServerConfiguration", "true"); + props.setProperty("elideSetAutoCommits", "true"); + props.setProperty("maintainTimeStats", "false"); + + // https://github.com/brettwooldridge/HikariCP/wiki/JDBC-Logging#mysql-connectorj + // TODO FINERACT-890: com.mysql.cj.log.Slf4JLogger + props.setProperty("logSlowQueries", "true"); + props.setProperty("dumpQueriesOnException", "true"); + + return props; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java new file mode 100644 index 00000000000..2b7f535a156 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java @@ -0,0 +1,131 @@ +/** + * 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.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "fineract") +public class FineractProperties { + + private String nodeId; + + private FineractTenantProperties tenant; + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public FineractTenantProperties getTenant() { + return tenant; + } + + public void setTenant(FineractTenantProperties tenant) { + this.tenant = tenant; + } + + public static class FineractTenantProperties { + + private String host; + private Integer port; + private String username; + private String password; + private String parameters; + private String timezone; + private String identifier; + private String name; + private String description; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getParameters() { + return parameters; + } + + public void setParameters(String parameters) { + this.parameters = parameters; + } + + public String getTimezone() { + return timezone; + } + + public void setTimezone(String timezone) { + this.timezone = timezone; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/HikariCpConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/HikariCpConfig.java index 33a35c49e65..8086e569cd9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/HikariCpConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/HikariCpConfig.java @@ -21,63 +21,27 @@ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -import java.util.Properties; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; +import javax.sql.DataSource; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; @Configuration +@ConditionalOnExpression("#{ systemEnvironment['fineract_tenants_driver'] == null }") public class HikariCpConfig { - @Autowired - ApplicationContext context; - - @Bean(destroyMethod = "close") - public HikariDataSource hikariTenantDataSource(HikariConfig hc) { - return new HikariDataSource(hc); - } + // TODO: we can get rid of this config class by defining "spring.hikariTenantDataSource.hikari.*" in + // "application.properties" and enabling auto-configuration @Bean + @ConfigurationProperties(prefix = "spring.datasource.hikari") public HikariConfig hikariConfig() { - Environment environment = context.getEnvironment(); - HikariConfig hc = new HikariConfig(); - - hc.setDriverClassName(environment.getProperty("fineract_tenants_driver")); - hc.setJdbcUrl(environment.getProperty("fineract_tenants_url")); - hc.setUsername(environment.getProperty("fineract_tenants_uid")); - hc.setPassword(environment.getProperty("fineract_tenants_pwd")); - hc.setMinimumIdle(3); - hc.setMaximumPoolSize(10); - hc.setIdleTimeout(60000); - hc.setConnectionTestQuery("SELECT 1"); - hc.setDataSourceProperties(dataSourceProperties()); - - return hc; + return new HikariConfig(); } - // These are the properties for the all Tenants DB; the same configuration is also (hard-coded) in the - // TomcatJdbcDataSourcePerTenantService class --> - private Properties dataSourceProperties() { - Properties props = new Properties(); - - props.setProperty("cachePrepStmts", "true"); - props.setProperty("prepStmtCacheSize", "250"); - props.setProperty("prepStmtCacheSqlLimit", "2048"); - props.setProperty("useServerPrepStmts", "true"); - props.setProperty("useLocalSessionState", "true"); - props.setProperty("rewriteBatchedStatements", "true"); - props.setProperty("cacheResultSetMetadata", "true"); - props.setProperty("cacheServerConfiguration", "true"); - props.setProperty("elideSetAutoCommits", "true"); - props.setProperty("maintainTimeStats", "false"); - - // https://github.com/brettwooldridge/HikariCP/wiki/JDBC-Logging#mysql-connectorj - // TODO FINERACT-890: com.mysql.cj.log.Slf4JLogger - props.setProperty("logSlowQueries", "true"); - props.setProperty("dumpQueriesOnException", "true"); - - return props; + @Bean(destroyMethod = "close") + public DataSource hikariTenantDataSource(HikariConfig hikariConfig) { + return new HikariDataSource(hikariConfig); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/FineractPlatformTenantConnection.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/FineractPlatformTenantConnection.java index b07f5ca39ae..cfa1287bbda 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/FineractPlatformTenantConnection.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/FineractPlatformTenantConnection.java @@ -18,6 +18,9 @@ */ package org.apache.fineract.infrastructure.core.domain; +import javax.sql.DataSource; +import org.apache.commons.lang3.StringUtils; + /** * Holds Tenant's DB server connection connection details. */ @@ -181,4 +184,23 @@ public String toString() { } return sb.toString(); } + + public static String toJdbcUrl(String protocol, String host, String port, String db, String parameters) { + StringBuilder sb = new StringBuilder(protocol).append("://").append(host).append(":").append(port).append('/').append(db); + + if (!StringUtils.isEmpty(parameters)) { + sb.append('?').append(parameters); + } + + return sb.toString(); + } + + public static String toProtocol(DataSource dataSource) { + try { + String url = dataSource.getConnection().getMetaData().getURL(); + return url.substring(0, url.indexOf("://")); + } catch (Exception e) { + throw new RuntimeException(e); + } + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/DataSourceForTenants.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/DataSourceForTenants.java deleted file mode 100755 index 839e2c55003..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/DataSourceForTenants.java +++ /dev/null @@ -1,44 +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.service; - -import javax.sql.DataSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - -/** - * Implementation that returns connection pool datasource for tenants database - */ -@Service -public class DataSourceForTenants implements RoutingDataSourceService { - - private final DataSource tenantDataSource; - - @Autowired - public DataSourceForTenants(final @Qualifier("hikariTenantDataSource") DataSource tenantDataSource) { - this.tenantDataSource = tenantDataSource; - } - - @Override - public DataSource retrieveDataSource() { - return this.tenantDataSource; - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java index 877d2717d61..264f9e1adcc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java @@ -18,11 +18,15 @@ */ 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 java.util.List; import java.util.Map; import javax.annotation.PostConstruct; import javax.sql.DataSource; -import org.apache.fineract.infrastructure.core.boot.JDBCDriverConfig; +import org.apache.fineract.infrastructure.core.config.FineractProperties; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection; import org.apache.fineract.infrastructure.security.service.TenantDetailsService; @@ -45,17 +49,18 @@ public class TenantDatabaseUpgradeService { private static final Logger LOG = LoggerFactory.getLogger(TenantDatabaseUpgradeService.class); + private final HikariConfig hikariConfig; private final TenantDetailsService tenantDetailsService; protected final DataSource tenantDataSource; + protected final FineractProperties fineractProperties; @Autowired - private JDBCDriverConfig driverConfig; - - @Autowired - public TenantDatabaseUpgradeService(final TenantDetailsService detailsService, - @Qualifier("hikariTenantDataSource") final DataSource dataSource) { + public TenantDatabaseUpgradeService(final HikariConfig hikariConfig, final TenantDetailsService detailsService, + @Qualifier("hikariTenantDataSource") final DataSource dataSource, final FineractProperties fineractProperties) { + this.hikariConfig = hikariConfig; this.tenantDetailsService = detailsService; this.tenantDataSource = dataSource; + this.fineractProperties = fineractProperties; } @PostConstruct @@ -66,11 +71,11 @@ public void upgradeAllTenants() { final FineractPlatformTenantConnection connection = tenant.getConnection(); if (connection.isAutoUpdateEnabled()) { - String connectionProtocol = driverConfig.constructProtocol(connection.getSchemaServer(), connection.getSchemaServerPort(), + String protocol = toProtocol(this.tenantDataSource); + String jdbcUrl = toJdbcUrl(protocol, connection.getSchemaServer(), connection.getSchemaServerPort(), connection.getSchemaName(), connection.getSchemaConnectionParameters()); DriverDataSource source = new DriverDataSource(Thread.currentThread().getContextClassLoader(), - driverConfig.getDriverClassName(), connectionProtocol, connection.getSchemaUsername(), - connection.getSchemaPassword()); + hikariConfig.getDriverClassName(), jdbcUrl, connection.getSchemaUsername(), connection.getSchemaPassword()); final Flyway flyway = Flyway.configure().dataSource(source).locations("sql/migrations/core_db").outOfOrder(true) .placeholderReplacement(false).configuration(Map.of("flyway.table", "schema_version")) // FINERACT-979 @@ -84,7 +89,7 @@ public void upgradeAllTenants() { flyway.repair(); flyway.migrate(); } catch (FlywayException e) { - String betterMessage = e.getMessage() + "; for Tenant DB URL: " + connectionProtocol + ", username: " + String betterMessage = e.getMessage() + "; for Tenant DB URL: " + jdbcUrl + ", username: " + connection.getSchemaUsername(); throw new FlywayException(betterMessage, e); } @@ -96,18 +101,25 @@ public void upgradeAllTenants() { * Initializes, and if required upgrades (using Flyway) the Tenant DB itself. */ private void upgradeTenantDB() { - String dbHostname = getEnvVar("FINERACT_DEFAULT_TENANTDB_HOSTNAME", "localhost"); - String dbPort = getEnvVar("FINERACT_DEFAULT_TENANTDB_PORT", "3306"); - String dbUid = getEnvVar("FINERACT_DEFAULT_TENANTDB_UID", "root"); - String dbPwd = getEnvVar("FINERACT_DEFAULT_TENANTDB_PWD", "mysql"); - String dbConnParams = getEnvVar("FINERACT_DEFAULT_TENANTDB_CONN_PARAMS", ""); - LOG.info("upgradeTenantDB: FINERACT_DEFAULT_TENANTDB_HOSTNAME = {}, FINERACT_DEFAULT_TENANTDB_PORT = {}", dbHostname, dbPort); + LOG.info("Upgrade tenant DB: {}:{}", fineractProperties.getTenant().getHost(), fineractProperties.getTenant().getPort()); + LOG.info("- fineract.tenant.username: {}", fineractProperties.getTenant().getUsername()); + LOG.info("- fineract.tenant.password: ****"); + LOG.info("- fineract.tenant.parameters: {}", fineractProperties.getTenant().getParameters()); + LOG.info("- fineract.tenant.timezone: {}", fineractProperties.getTenant().getTimezone()); + LOG.info("- fineract.tenant.description: {}", fineractProperties.getTenant().getDescription()); + LOG.info("- fineract.tenant.identifier: {}", fineractProperties.getTenant().getIdentifier()); + LOG.info("- fineract.tenant.name: {}", fineractProperties.getTenant().getName()); final Flyway flyway = Flyway.configure().dataSource(tenantDataSource).locations("sql/migrations/list_db").outOfOrder(true) // FINERACT-773 - .placeholders(Map.of("fineract_default_tenantdb_hostname", dbHostname, "fineract_default_tenantdb_port", dbPort, - "fineract_default_tenantdb_uid", dbUid, "fineract_default_tenantdb_pwd", dbPwd, - "fineract_default_tenantdb_conn_params", dbConnParams)) + .placeholders(Map.of("fineract.tenant.host", fineractProperties.getTenant().getHost(), "fineract.tenant.port", + fineractProperties.getTenant().getPort().toString(), "fineract.tenant.username", + fineractProperties.getTenant().getUsername(), "fineract.tenant.password", + fineractProperties.getTenant().getPassword(), "fineract.tenant.parameters", + fineractProperties.getTenant().getParameters(), "fineract.tenant.timezone", + fineractProperties.getTenant().getTimezone(), "fineract.tenant.description", + fineractProperties.getTenant().getDescription(), "fineract.tenant.identifier", + fineractProperties.getTenant().getIdentifier(), "fineract.tenant.name", fineractProperties.getTenant().getName())) .configuration(Map.of("flyway.table", "schema_version")) // FINERACT-979 .load(); @@ -119,14 +131,6 @@ private void upgradeTenantDB() { flyway.migrate(); } - private String getEnvVar(String name, String defaultValue) { - String value = System.getenv(name); - if (value == null) { - return defaultValue; - } - return value; - } - private void repairFlywayVersionSkip(DataSource source) { JdbcTemplate template = new JdbcTemplate(source); LOG.info("repairFlywayVersionSkip: Check whether the version table is in old format "); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TomcatJdbcDataSourcePerTenantService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TomcatJdbcDataSourcePerTenantService.java index 99a5b5ab5e9..8be95f24e99 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TomcatJdbcDataSourcePerTenantService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TomcatJdbcDataSourcePerTenantService.java @@ -18,12 +18,14 @@ */ 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; -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.springframework.beans.factory.annotation.Autowired; @@ -43,7 +45,7 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe private final DataSource tenantDataSource; @Autowired - private JDBCDriverConfig driverConfig; + private HikariConfig hikariConfig; @Autowired public TomcatJdbcDataSourcePerTenantService(final @Qualifier("hikariTenantDataSource") DataSource tenantDataSource) { @@ -77,21 +79,21 @@ public DataSource retrieveDataSource() { // creates the tenant data source for the oltp and report database private DataSource createNewDataSourceFor(final FineractPlatformTenantConnection tenantConnectionObj) { - String jdbcUrl = this.driverConfig.constructProtocol(tenantConnectionObj.getSchemaServer(), - tenantConnectionObj.getSchemaServerPort(), tenantConnectionObj.getSchemaName(), - tenantConnectionObj.getSchemaConnectionParameters()); + String protocol = toProtocol(this.tenantDataSource); + String jdbcUrl = toJdbcUrl(protocol, tenantConnectionObj.getSchemaServer(), tenantConnectionObj.getSchemaServerPort(), + tenantConnectionObj.getSchemaName(), tenantConnectionObj.getSchemaConnectionParameters()); HikariConfig config = new HikariConfig(); - config.setDriverClassName(this.driverConfig.getDriverClassName()); + 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("SELECT 1"); + config.setConnectionTestQuery(hikariConfig.getConnectionTestQuery()); config.setValidationTimeout(tenantConnectionObj.getValidationInterval()); - config.setAutoCommit(true); + config.setAutoCommit(hikariConfig.isAutoCommit()); // https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management config.setRegisterMbeans(true); @@ -100,22 +102,7 @@ private DataSource createNewDataSourceFor(final FineractPlatformTenantConnection // 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.addDataSourceProperty("cachePrepStmts", "true"); - config.addDataSourceProperty("prepStmtCacheSize", "250"); - config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); - config.addDataSourceProperty("useServerPrepStmts", "true"); - config.addDataSourceProperty("useLocalSessionState", "true"); - config.addDataSourceProperty("rewriteBatchedStatements", "true"); - config.addDataSourceProperty("cacheResultSetMetadata", "true"); - config.addDataSourceProperty("cacheServerConfiguration", "true"); - config.addDataSourceProperty("elideSetAutoCommits", "true"); - config.addDataSourceProperty("maintainTimeStats", "false"); - - // https://github.com/brettwooldridge/HikariCP/wiki/JDBC-Logging#mysql-connectorj - // TODO FINERACT-890: config.addDataSourceProperty("logger", - // "com.mysql.cj.log.Slf4JLogger"); - config.addDataSourceProperty("logSlowQueries", "true"); - config.addDataSourceProperty("dumpQueriesOnException", "true"); + config.setDataSourceProperties(hikariConfig.getDataSourceProperties()); return new HikariDataSource(config); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java index 51ac1a4016f..cc95ea300af 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java @@ -28,6 +28,7 @@ import java.util.Properties; import java.util.TimeZone; import javax.annotation.PostConstruct; +import org.apache.fineract.infrastructure.core.config.FineractProperties; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.exception.PlatformInternalServerException; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; @@ -51,7 +52,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; @@ -92,15 +92,16 @@ public class JobRegisterServiceImpl implements JobRegisterService, ApplicationLi // This cannot be injected as Autowired due to circular dependency private SchedulerStopListener schedulerStopListener = new SchedulerStopListener(this); - @Value("${node_id:1}") - private String nodeId; + @Autowired + private FineractProperties fineractProperties; @PostConstruct public void loadAllJobs() { final List allTenants = this.tenantDetailsService.findAllTenants(); for (final FineractPlatformTenant tenant : allTenants) { ThreadLocalContextUtil.setTenant(tenant); - final List scheduledJobDetails = this.schedularWritePlatformService.retrieveAllJobs(nodeId); + final List scheduledJobDetails = this.schedularWritePlatformService + .retrieveAllJobs(fineractProperties.getNodeId()); for (final ScheduledJobDetail jobDetails : scheduledJobDetails) { scheduleJob(jobDetails); jobDetails.updateTriggerMisfired(false); @@ -180,7 +181,8 @@ public void startScheduler() { schedulerDetail.updateSuspendedState(false); this.schedularWritePlatformService.updateSchedulerDetail(schedulerDetail); if (schedulerDetail.isExecuteInstructionForMisfiredJobs()) { - final List scheduledJobDetails = this.schedularWritePlatformService.retrieveAllJobs(this.nodeId); + final List scheduledJobDetails = this.schedularWritePlatformService + .retrieveAllJobs(fineractProperties.getNodeId()); for (final ScheduledJobDetail jobDetail : scheduledJobDetails) { if (jobDetail.isTriggerMisfired()) { if (jobDetail.isActiveSchedular()) { @@ -215,12 +217,12 @@ public void startScheduler() { public void rescheduleJob(final Long jobId) { final ScheduledJobDetail scheduledJobDetail = this.schedularWritePlatformService.findByJobId(jobId); final String nodeIdStored = scheduledJobDetail.getNodeId().toString(); - if (nodeIdStored.equals(this.nodeId) || nodeIdStored.equals("0")) { + if (nodeIdStored.equals(fineractProperties.getNodeId()) || nodeIdStored.equals("0")) { rescheduleJob(scheduledJobDetail); } else { scheduledJobDetail.setIsMismatchedJob(true); this.schedularWritePlatformService.saveOrUpdate(scheduledJobDetail); - throw new JobNodeIdMismatchingException(nodeIdStored, this.nodeId); + throw new JobNodeIdMismatchingException(nodeIdStored, fineractProperties.getNodeId()); } } @@ -232,12 +234,12 @@ public void executeJob(final Long jobId) { } final String nodeIdStored = scheduledJobDetail.getNodeId().toString(); - if (nodeIdStored.equals(this.nodeId) || nodeIdStored.equals("0")) { + if (nodeIdStored.equals(fineractProperties.getNodeId()) || nodeIdStored.equals("0")) { executeJob(scheduledJobDetail, null); } else { scheduledJobDetail.setIsMismatchedJob(true); this.schedularWritePlatformService.saveOrUpdate(scheduledJobDetail); - throw new JobNodeIdMismatchingException(nodeIdStored, this.nodeId); + throw new JobNodeIdMismatchingException(nodeIdStored, fineractProperties.getNodeId()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/scheduledjobs/service/ScheduledJobRunnerServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/scheduledjobs/service/ScheduledJobRunnerServiceImpl.java index 24a4655d5a9..434a9b8f26c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/scheduledjobs/service/ScheduledJobRunnerServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/scheduledjobs/service/ScheduledJobRunnerServiceImpl.java @@ -32,6 +32,7 @@ import java.util.Map; import org.apache.fineract.accounting.glaccount.domain.TrialBalance; import org.apache.fineract.accounting.glaccount.domain.TrialBalanceRepositoryWrapper; +import org.apache.fineract.infrastructure.core.config.FineractProperties; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.service.DateUtils; @@ -56,7 +57,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @@ -81,9 +81,7 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService private final TrialBalanceRepositoryWrapper trialBalanceRepositoryWrapper; private final JobRegisterService jobRegisterService; private final ScheduledJobDetailRepository scheduledJobDetailsRepository; - - @Value("${node_id:1}") - private String nodeId; + private final FineractProperties fineractProperties; @Autowired public ScheduledJobRunnerServiceImpl(final RoutingDataSourceServiceFactory dataSourceServiceFactory, @@ -94,7 +92,7 @@ public ScheduledJobRunnerServiceImpl(final RoutingDataSourceServiceFactory dataS final ShareAccountDividendReadPlatformService shareAccountDividendReadPlatformService, final ShareAccountSchedularService shareAccountSchedularService, final TrialBalanceRepositoryWrapper trialBalanceRepositoryWrapper, @Lazy final JobRegisterService jobRegisterService, - final ScheduledJobDetailRepository scheduledJobDetailsRepository) { + final ScheduledJobDetailRepository scheduledJobDetailsRepository, final FineractProperties fineractProperties) { this.dataSourceServiceFactory = dataSourceServiceFactory; this.savingsAccountWritePlatformService = savingsAccountWritePlatformService; this.savingsAccountChargeReadPlatformService = savingsAccountChargeReadPlatformService; @@ -105,6 +103,7 @@ public ScheduledJobRunnerServiceImpl(final RoutingDataSourceServiceFactory dataS this.trialBalanceRepositoryWrapper = trialBalanceRepositoryWrapper; this.jobRegisterService = jobRegisterService; this.scheduledJobDetailsRepository = scheduledJobDetailsRepository; + this.fineractProperties = fineractProperties; } @Transactional @@ -500,7 +499,7 @@ public void executeMissMatchedJobs() throws JobExecutionException { List jobDetails = this.scheduledJobDetailsRepository.findAllMismatchedJobs(true); for (ScheduledJobDetail scheduledJobDetail : jobDetails) { - if (scheduledJobDetail.getNodeId().toString().equals(this.nodeId)) { + if (scheduledJobDetail.getNodeId().toString().equals(fineractProperties.getNodeId())) { jobRegisterService.executeJob(scheduledJobDetail.getId()); } } diff --git a/fineract-provider/src/main/resources/META-INF/spring/jdbc.properties b/fineract-provider/src/main/resources/META-INF/spring/jdbc.properties deleted file mode 100644 index d6c9908e1fc..00000000000 --- a/fineract-provider/src/main/resources/META-INF/spring/jdbc.properties +++ /dev/null @@ -1,27 +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. -# - -DRIVERCLASS_NAME:org.mariadb.jdbc.Driver -PROTOCOL:jdbc -SUB_PROTOCOL:mariadb - -fineract_tenants_driver:org.mariadb.jdbc.Driver -fineract_tenants_url:jdbc:mariadb://localhost:3306/fineract_tenants -fineract_tenants_uid:root -fineract_tenants_pwd:mysql diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index b4e3949b13c..208a7221091 100644 --- a/fineract-provider/src/main/resources/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -17,10 +17,22 @@ # under the License. # +fineract.node-id=${FINERACT_NODE_ID:1} + fineract.security.basicauth.enabled=${FINERACT_SECURITY_BASICAUTH_ENABLED:true} fineract.security.oauth.enabled=${FINERACT_SECURITY_OAUTH_ENABLED:false} fineract.security.2fa.enabled=${FINERACT_SECURITY_2FA_ENABLED:false} +fineract.tenant.host=${FINERACT_DEFAULT_TENANTDB_HOSTNAME:localhost} +fineract.tenant.port=${FINERACT_DEFAULT_TENANTDB_PORT:3306} +fineract.tenant.username=${FINERACT_DEFAULT_TENANTDB_UID:root} +fineract.tenant.password=${FINERACT_DEFAULT_TENANTDB_PWD:mysql} +fineract.tenant.parameters=${FINERACT_DEFAULT_TENANTDB_CONN_PARAMS:} +fineract.tenant.timezone=${FINERACT_DEFAULT_TENANTDB_TIMEZONE:Asia/Kolkata} +fineract.tenant.identifier=${FINERACT_DEFAULT_TENANTDB_IDENTIFIER:default} +fineract.tenant.name=${FINERACT_DEFAULT_TENANTDB_NAME:fineract_default} +fineract.tenant.description=${FINERACT_DEFAULT_TENANTDB_DESCRIPTION:Default Demo Tenant} + management.health.jms.enabled=false # FINERACT 1296 @@ -37,3 +49,28 @@ server.forward-headers-strategy=framework # OAuth authorisation server endpoint spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000/auth/realms/fineract + +spring.datasource.hikari.driverClassName=${FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME:org.mariadb.jdbc.Driver} +spring.datasource.hikari.jdbcUrl=${FINERACT_HIKARI_JDBC_URL:'jdbc:mariadb://localhost:3306/fineract_tenants'} +spring.datasource.hikari.username=${FINERACT_HIKARI_USERNAME:root} +spring.datasource.hikari.password=${FINERACT_HIKARI_PASSWORD:mysql} +spring.datasource.hikari.minimumIdle=${FINERACT_HIKARI_MINIMUM_IDLE:3} +spring.datasource.hikari.maximumPoolSize=${FINERACT_HIKARI_MAXIMUM_POOL_SIZE:10} +spring.datasource.hikari.idleTimeout=${FINERACT_HIKARI_IDLE_TIMEOUT:60000} +spring.datasource.hikari.connectionTimeout=${FINERACT_HIKARI_CONNECTION_TIMEOUT:20000} +spring.datasource.hikari.connectionTestquery=${FINERACT_HIKARI_TEST_QUERY:SELECT 1} +spring.datasource.hikari.autoCommit=${FINERACT_HIKARI_AUTO_COMMIT:true} +spring.datasource.hikari.dataSourceProperties['cachePrepStmts']=${FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS:true} +spring.datasource.hikari.dataSourceProperties['prepStmtCacheSize']=${FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE:250} +spring.datasource.hikari.dataSourceProperties['prepStmtCacheSqlLimit']=${FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT:2048} +spring.datasource.hikari.dataSourceProperties['useServerPrepStmts']=${FINERACT_HIKARI_DS_PROPERTIES_USE_SERVER_PREP_STMTS:true} +spring.datasource.hikari.dataSourceProperties['useLocalSessionState']=${FINERACT_HIKARI_DS_PROPERTIES_USE_LOCAL_SESSION_STATE:true} +spring.datasource.hikari.dataSourceProperties['rewriteBatchedStatements']=${FINERACT_HIKARI_DS_PROPERTIES_REWRITE_BATCHED_STATEMENTS:true} +spring.datasource.hikari.dataSourceProperties['cacheResultSetMetadata']=${FINERACT_HIKARI_DS_PROPERTIES_CACHE_RESULT_SET_METADATA:true} +spring.datasource.hikari.dataSourceProperties['cacheServerConfiguration']=${FINERACT_HIKARI_DS_PROPERTIES_CACHE_SERVER_CONFIGURATION:true} +spring.datasource.hikari.dataSourceProperties['elideSetAutoCommits']=${FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS:true} +spring.datasource.hikari.dataSourceProperties['maintainTimeStats']=${FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS:false} +# https://github.com/brettwooldridge/HikariCP/wiki/JDBC-Logging#mysql-connectorj +# TODO FINERACT-890: com.mysql.cj.log.Slf4JLogger +spring.datasource.hikari.dataSourceProperties['logSlowQueries']=${FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES:true} +spring.datasource.hikari.dataSourceProperties['dumpQueriesOnException']=${FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION:true} diff --git a/fineract-provider/src/main/resources/sql/migrations/list_db/V1__mifos-platform-shared-tenants.sql b/fineract-provider/src/main/resources/sql/migrations/list_db/V1__mifos-platform-shared-tenants.sql index d0ee516100e..447092451f3 100644 --- a/fineract-provider/src/main/resources/sql/migrations/list_db/V1__mifos-platform-shared-tenants.sql +++ b/fineract-provider/src/main/resources/sql/migrations/list_db/V1__mifos-platform-shared-tenants.sql @@ -66,7 +66,7 @@ CREATE TABLE `tenants` ( LOCK TABLES `tenants` WRITE; /*!40000 ALTER TABLE `tenants` DISABLE KEYS */; -INSERT INTO `tenants` VALUES (1,'default','Default Demo Tenant','fineract_default','Asia/Kolkata',NULL,NULL,NULL,NULL,'${fineract_default_tenantdb_hostname}','${fineract_default_tenantdb_port}','${fineract_default_tenantdb_uid}','${fineract_default_tenantdb_pwd}',1); +INSERT INTO `tenants` VALUES (1,'${fineract.tenant.identifier}','${fineract.tenant.description}','${fineract.tenant.name}','${fineract.tenant.timezone}',NULL,NULL,NULL,NULL,'${fineract.tenant.host}','${fineract.tenant.port}','${fineract.tenant.username}','${fineract.tenant.password}',1); -- Add tenants to support interoperation multi-tenancy -- INSERT INTO `tenants` VALUES (2,'tn01','Buffalo','tn01','Africa/Bujumbura',NULL,NULL,NULL,NULL,'localhost','3306','root','mysql',1); -- INSERT INTO `tenants` VALUES (3,'tn02','Lion','tn02','Africa/Bujumbura',NULL,NULL,NULL,NULL,'localhost','3306','root','mysql',1); diff --git a/fineract-provider/src/main/resources/sql/migrations/list_db/V5__add_schema_connection_parameters.sql b/fineract-provider/src/main/resources/sql/migrations/list_db/V5__add_schema_connection_parameters.sql index 021b9fba7d1..89d90f44503 100644 --- a/fineract-provider/src/main/resources/sql/migrations/list_db/V5__add_schema_connection_parameters.sql +++ b/fineract-provider/src/main/resources/sql/migrations/list_db/V5__add_schema_connection_parameters.sql @@ -20,5 +20,5 @@ ALTER TABLE `tenant_server_connections` ADD COLUMN `schema_connection_parameters` TEXT NULL DEFAULT NULL; UPDATE `tenant_server_connections` - SET `schema_connection_parameters`='${fineract_default_tenantdb_conn_params}' + SET `schema_connection_parameters`='${fineract.tenant.parameters}' WHERE `id`=1; diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/TestsWithoutDatabaseAndNoJobsConfiguration.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/TestsWithoutDatabaseAndNoJobsConfiguration.java index 1f5190098b8..760b54b753e 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/TestsWithoutDatabaseAndNoJobsConfiguration.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/configuration/spring/TestsWithoutDatabaseAndNoJobsConfiguration.java @@ -20,9 +20,11 @@ import javax.sql.DataSource; import org.apache.fineract.infrastructure.core.boot.AbstractApplicationConfiguration; +import org.apache.fineract.infrastructure.core.config.FineractProperties; import org.apache.fineract.infrastructure.core.service.TenantDatabaseUpgradeService; import org.apache.fineract.infrastructure.jobs.service.JobRegisterService; import org.mockito.Mockito; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -33,6 +35,7 @@ * are in the DB), thus nor starts any background jobs. For some integration tests, this may be perfectly sufficient * (and faster to run such tests). */ +@EnableConfigurationProperties({ FineractProperties.class }) public class TestsWithoutDatabaseAndNoJobsConfiguration extends AbstractApplicationConfiguration { /** @@ -41,7 +44,7 @@ public class TestsWithoutDatabaseAndNoJobsConfiguration extends AbstractApplicat */ @Bean public TenantDatabaseUpgradeService tenantDatabaseUpgradeService() { - return new TenantDatabaseUpgradeService(null, null) { + return new TenantDatabaseUpgradeService(null, null, null, null) { @Override public void upgradeAllTenants() { diff --git a/fineract-provider/src/test/resources/application-test.properties b/fineract-provider/src/test/resources/application-test.properties index 30b680b8c51..6a6f7654c57 100644 --- a/fineract-provider/src/test/resources/application-test.properties +++ b/fineract-provider/src/test/resources/application-test.properties @@ -17,10 +17,22 @@ # under the License. # +fineract.node-id=1 + fineract.security.basicauth.enabled=true fineract.security.oauth.enabled=false fineract.security.2fa.enabled=false +fineract.tenant.host=localhost +fineract.tenant.port=3306 +fineract.tenant.username=root +fineract.tenant.password=mysql +fineract.tenant.parameters= +fineract.tenant.timezone=Asia/Kolkata +fineract.tenant.identifier=default +fineract.tenant.name=fineract_default +fineract.tenant.description=Default Demo Tenant + management.health.jms.enabled=false # FINERACT 1296 @@ -34,3 +46,26 @@ management.endpoints.web.exposure.include=health,info # FINERACT-914 server.forward-headers-strategy=framework + +spring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver +spring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants +spring.datasource.hikari.username=root +spring.datasource.hikari.password=mysql +spring.datasource.hikari.minimumIdle=3 +spring.datasource.hikari.maximumPoolSize=10 +spring.datasource.hikari.idleTimeout=60000 +spring.datasource.hikari.connectionTimeout=20000 +spring.datasource.hikari.connectionTestQuery=SELECT 1 +spring.datasource.hikari.autoCommit=true +spring.datasource.hikari.dataSourceProperties['cachePrepStmts']=true +spring.datasource.hikari.dataSourceProperties['prepStmtCacheSize']=250 +spring.datasource.hikari.dataSourceProperties['prepStmtCacheSqlLimit']=2048 +spring.datasource.hikari.dataSourceProperties['useServerPrepStmts']=true +spring.datasource.hikari.dataSourceProperties['useLocalSessionState']=true +spring.datasource.hikari.dataSourceProperties['rewriteBatchedStatements']=true +spring.datasource.hikari.dataSourceProperties['cacheResultSetMetadata']=true +spring.datasource.hikari.dataSourceProperties['cacheServerConfiguration']=true +spring.datasource.hikari.dataSourceProperties['elideSetAutoCommits']=true +spring.datasource.hikari.dataSourceProperties['maintainTimeStats']=false +spring.datasource.hikari.dataSourceProperties['logSlowQueries']=true +spring.datasource.hikari.dataSourceProperties['dumpQueriesOnException']=true diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index 87082026c31..35908694c3d 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -45,7 +45,7 @@ cargo { } startStopTimeout = 240000 containerProperties { - property 'cargo.start.jvmargs', '--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED' + property 'cargo.start.jvmargs', '--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dspring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=mysql -Dfineract.tenant.host=localhost -Dfineract.tenant.port=3306 -Dfineract.tenant.username=root -Dfineract.tenant.password=mysql' property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks") property 'cargo.tomcat.connector.keystorePass', 'openmf' property 'cargo.tomcat.httpSecure', true diff --git a/kubernetes/fineract-server-deployment.yml b/kubernetes/fineract-server-deployment.yml index 6b45ab8e198..3754d97f9a6 100644 --- a/kubernetes/fineract-server-deployment.yml +++ b/kubernetes/fineract-server-deployment.yml @@ -81,24 +81,18 @@ spec: initialDelaySeconds: 180 periodSeconds: 1 env: - - name: DRIVERCLASS_NAME - value: org.mariadb.jdbc.Driver - - name: PROTOCOL - value: jdbc - - name: SUB_PROTOCOL - value: mariadb - - name: node_id + - name: FINERACT_NODE_ID value: '1' - - name: fineract_tenants_driver + - name: FINERACT_HIKARI_DRIVER_CLASS_NAME value: org.mariadb.jdbc.Driver - - name: fineract_tenants_url + - name: FINERACT_HIKARI_JDBC_URL value: jdbc:mariadb://fineractmysql:3306/fineract_tenants - - name: fineract_tenants_uid + - name: FINERACT_HIKARI_USERNAME valueFrom: secretKeyRef: name: fineract-tenants-db-secret key: username - - name: fineract_tenants_pwd + - name: FINERACT_HIKARI_PASSWORD valueFrom: secretKeyRef: name: fineract-tenants-db-secret diff --git a/oauth2-tests/build.gradle b/oauth2-tests/build.gradle index 81e369ef487..9225755e827 100644 --- a/oauth2-tests/build.gradle +++ b/oauth2-tests/build.gradle @@ -45,7 +45,7 @@ cargo { } startStopTimeout = 240000 containerProperties { - property 'cargo.start.jvmargs', '-Dfineract.security.basicauth.enabled=false -Dfineract.security.oauth.enabled=true -Dfineract.security.2fa.enabled=false --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED' + property 'cargo.start.jvmargs', '-Dfineract.security.basicauth.enabled=false -Dfineract.security.oauth.enabled=true -Dfineract.security.2fa.enabled=false -Dspring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=mysql -Dfineract.tenant.host=localhost -Dfineract.tenant.port=3306 -Dfineract.tenant.username=root -Dfineract.tenant.password=mysql --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED' property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks") property 'cargo.tomcat.connector.keystorePass', 'openmf' property 'cargo.tomcat.httpSecure', true diff --git a/twofactor-tests/build.gradle b/twofactor-tests/build.gradle index f2d4cbc82f2..3b60a860abe 100644 --- a/twofactor-tests/build.gradle +++ b/twofactor-tests/build.gradle @@ -45,7 +45,7 @@ cargo { } startStopTimeout = 240000 containerProperties { - property 'cargo.start.jvmargs', '-Dfineract.security.basicauth.enabled=true -Dfineract.security.oauth.enabled=false -Dfineract.security.2fa.enabled=true --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED' + property 'cargo.start.jvmargs', '-Dfineract.security.basicauth.enabled=true -Dfineract.security.oauth.enabled=false -Dfineract.security.2fa.enabled=true -Dspring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=mysql -Dfineract.tenant.host=localhost -Dfineract.tenant.port=3306 -Dfineract.tenant.username=root -Dfineract.tenant.password=mysql --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED' property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks") property 'cargo.tomcat.connector.keystorePass', 'openmf' property 'cargo.tomcat.httpSecure', true