FINERACT-1724: Ability to run Fineract in Liquibase only mode for scaled environments

This commit is contained in:
Arnold Galovics
2023-02-17 16:31:16 +01:00
committed by Arnold Gálovics
parent f927dd4ff9
commit 6c86e15eb7
45 changed files with 288 additions and 71 deletions
@@ -22,8 +22,8 @@ import static org.mockito.Mockito.mock;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.group.domain.GroupRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
@@ -21,8 +21,8 @@ package com.acme.fineract.portfolio.note.starter;
import static org.mockito.Mockito.mock;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.group.domain.GroupRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
@@ -48,4 +48,9 @@
|FINERACT_DEFAULT_TENANTDB_DESCRIPTION
|Default Demo Tenant
|TBD
|spring.liquibase.enabled
|FINERACT_LIQUIBASE_ENABLED
|true
|TBD
|===
@@ -1,3 +1,11 @@
= Kubernetes
TBD
In a scaled Kubernetes environment where multiple Fineract instances are deployed, doing the database migrations properly is essential.
Fineract provides a way to run only the Liquibase migrations instead of starting up the whole application server so that you can easily do the migrations before actually upgrading a Fineract instance.
The `FINERACT_LIQUIBASE_ENABLED` flag controls whether Liquibase is enabled or not. For regular read/write/batch manager/batch worker instances this should be disabled.
There's a special Spring profile that should be enabled for running Liquibase only. In can be done via `SPRING_PROFILES_ACTIVE` environment variable. The profile name is `liquibase-only`. At the end of the migration process, the application will exit.
For the instance running the Liquibase migrations, the profile should be activated.
@@ -19,10 +19,12 @@
package org.apache.fineract;
import java.io.IOException;
import org.apache.fineract.infrastructure.core.boot.AbstractApplicationConfiguration;
import org.apache.fineract.infrastructure.core.boot.FineractLiquibaseOnlyApplicationConfiguration;
import org.apache.fineract.infrastructure.core.boot.FineractWebApplicationConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Import;
/**
* Fineract main() application which launches Fineract in an embedded Tomcat HTTP (using Spring Boot).
@@ -39,11 +41,12 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
public class ServerApplication extends SpringBootServletInitializer {
private static class Configuration extends AbstractApplicationConfiguration {}
@Import({ FineractWebApplicationConfiguration.class, FineractLiquibaseOnlyApplicationConfiguration.class })
private static class Configuration {}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Configuration.class);
return configureApplication(builder);
}
private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
@@ -52,6 +55,5 @@ public class ServerApplication extends SpringBootServletInitializer {
public static void main(String[] args) throws IOException {
configureApplication(new SpringApplicationBuilder(ServerApplication.class)).run(args);
// ApplicationExitUtil.waitForKeyPressToCleanlyExit(ctx);
}
}
@@ -19,7 +19,7 @@
package org.apache.fineract.accounting.glaccount.jobs.updatetrialbalancedetails;
import org.apache.fineract.accounting.glaccount.domain.TrialBalanceRepositoryWrapper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
@@ -27,8 +27,8 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.accounting.glaccount.domain.TrialBalance;
import org.apache.fineract.accounting.glaccount.domain.TrialBalanceRepositoryWrapper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
@@ -33,10 +33,10 @@ import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandler
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.apache.fineract.infrastructure.documentmanagement.command.DocumentCommand;
import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
import org.apache.fineract.infrastructure.documentmanagement.service.DocumentWritePlatformService;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -0,0 +1,45 @@
/**
* 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 lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.condition.FineractLiquibaseOnlyApplicationCondition;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.config.HikariCpConfig;
import org.apache.fineract.infrastructure.core.config.JdbcConfig;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Import;
@Conditional(FineractLiquibaseOnlyApplicationCondition.class)
@Slf4j
@EnableConfigurationProperties({ FineractProperties.class, LiquibaseProperties.class })
@Import({ HikariCpConfig.class, JdbcConfig.class })
@ComponentScan(basePackages = { "org.apache.fineract.infrastructure.core.service.migration",
"org.apache.fineract.infrastructure.core.service.database", "org.apache.fineract.infrastructure.core.service.tenant" })
public class FineractLiquibaseOnlyApplicationConfiguration implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
log.warn("Fineract is running in Liquibase only mode");
}
}
@@ -0,0 +1,26 @@
/**
* 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;
public final class FineractProfiles {
public static final String LIQUIBASE_ONLY = "liquibase-only";
private FineractProfiles() {}
}
@@ -18,7 +18,10 @@
*/
package org.apache.fineract.infrastructure.core.boot;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.condition.FineractWebApplicationCondition;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@@ -29,6 +32,7 @@ import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
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.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -47,6 +51,13 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableConfigurationProperties({ FineractProperties.class, LiquibaseProperties.class })
@ComponentScan(basePackages = "org.apache.fineract.**")
@IntegrationComponentScan(basePackages = "org.apache.fineract.**")
public abstract class AbstractApplicationConfiguration {
@Conditional(FineractWebApplicationCondition.class)
@Slf4j
// The class needs to be abstract for some reason, otherwise the tests start to fail...
public abstract class FineractWebApplicationConfiguration implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
log.warn("Fineract is running in web application mode");
}
}
@@ -0,0 +1,30 @@
/**
* 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.condition;
import java.util.List;
import org.apache.fineract.infrastructure.core.boot.FineractProfiles;
public class FineractLiquibaseOnlyApplicationCondition extends ProfileCondition {
@Override
protected boolean matches(List<String> activeProfiles) {
return activeProfiles.contains(FineractProfiles.LIQUIBASE_ONLY);
}
}
@@ -0,0 +1,30 @@
/**
* 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.condition;
import java.util.List;
import org.apache.fineract.infrastructure.core.boot.FineractProfiles;
public class FineractWebApplicationCondition extends ProfileCondition {
@Override
protected boolean matches(List<String> activeProfiles) {
return !activeProfiles.contains(FineractProfiles.LIQUIBASE_ONLY);
}
}
@@ -0,0 +1,36 @@
/**
* 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.condition;
import java.util.Arrays;
import java.util.List;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public abstract class ProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String[] activeProfiles = context.getEnvironment().getActiveProfiles();
return matches(Arrays.asList(activeProfiles));
}
protected abstract boolean matches(List<String> activeProfiles);
}
@@ -21,7 +21,6 @@ package org.apache.fineract.infrastructure.core.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -41,7 +40,7 @@ public class HikariCpConfig {
}
@Bean(destroyMethod = "close")
public DataSource hikariTenantDataSource(HikariConfig hikariConfig) {
public HikariDataSource hikariTenantDataSource(HikariConfig hikariConfig) {
return new HikariDataSource(hikariConfig);
}
}
@@ -18,7 +18,7 @@
*/
package org.apache.fineract.infrastructure.core.config;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -27,8 +27,8 @@ import java.util.Set;
import org.apache.fineract.infrastructure.core.auditing.JpaAuditingHandlerRegistrar;
import org.apache.fineract.infrastructure.core.domain.AuditorAwareImpl;
import org.apache.fineract.infrastructure.core.persistence.DatabaseSelectingPersistenceUnitPostProcessor;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilderCustomizer;
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.service;
package org.apache.fineract.infrastructure.core.service.database;
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toJdbcUrl;
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toProtocol;
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.service;
package org.apache.fineract.infrastructure.core.service.database;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.service;
package org.apache.fineract.infrastructure.core.service.database;
import java.sql.Connection;
import java.sql.SQLException;
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.service;
package org.apache.fineract.infrastructure.core.service.database;
import javax.sql.DataSource;
@@ -16,8 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.service;
package org.apache.fineract.infrastructure.core.service.database;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@@ -16,13 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.service;
package org.apache.fineract.infrastructure.core.service.database;
import java.util.HashMap;
import java.util.Map;
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.core.service.ThreadLocalContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@@ -22,7 +22,6 @@ import java.util.Map;
import java.util.Objects;
import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.service.database.DatabaseIndependentQueryService;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@@ -42,8 +41,6 @@ public class TenantDatabaseStateVerifier {
private final LiquibaseProperties liquibaseProperties;
private final DatabaseIndependentQueryService dbQueryService;
private final FineractProperties fineractProperties;
public boolean isFirstLiquibaseMigration(DataSource dataSource) {
boolean databaseChangelogTableExists = dbQueryService.isTablePresent(dataSource, "DATABASECHANGELOG");
return !databaseChangelogTableExists;
@@ -20,18 +20,21 @@ package org.apache.fineract.infrastructure.core.service.migration;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import javax.sql.DataSource;
import liquibase.exception.LiquibaseException;
import liquibase.integration.spring.SpringLiquibase;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.boot.FineractProfiles;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
/**
@@ -39,6 +42,7 @@ import org.springframework.stereotype.Service;
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class TenantDatabaseUpgradeService implements InitializingBean {
private static final String TENANT_STORE_DB_CONTEXT = "tenant_store_db";
@@ -47,33 +51,24 @@ public class TenantDatabaseUpgradeService implements InitializingBean {
private static final String CUSTOM_CHANGELOG_CONTEXT = "custom_changelog";
private final TenantDetailsService tenantDetailsService;
@Qualifier("hikariTenantDataSource")
private final DataSource tenantDataSource;
private final FineractProperties fineractProperties;
private final TenantDatabaseStateVerifier databaseStateVerifier;
private final ExtendedSpringLiquibaseFactory liquibaseFactory;
private final TenantDataSourceFactory tenantDataSourceFactory;
@Autowired
public TenantDatabaseUpgradeService(final TenantDetailsService detailsService,
@Qualifier("hikariTenantDataSource") final DataSource tenantDataSource, final FineractProperties fineractProperties,
TenantDatabaseStateVerifier databaseStateVerifier, ExtendedSpringLiquibaseFactory liquibaseFactory,
TenantDataSourceFactory tenantDataSourceFactory) {
this.tenantDetailsService = detailsService;
this.tenantDataSource = tenantDataSource;
this.fineractProperties = fineractProperties;
this.databaseStateVerifier = databaseStateVerifier;
this.liquibaseFactory = liquibaseFactory;
this.tenantDataSourceFactory = tenantDataSourceFactory;
}
private final Environment environment;
@Override
public void afterPropertiesSet() throws Exception {
if (databaseStateVerifier.isLiquibaseDisabled() || !fineractProperties.getMode().isWriteEnabled()) {
log.warn("Liquibase is disabled. Not upgrading any database.");
if (!fineractProperties.getMode().isWriteEnabled()) {
log.warn("Liquibase is disabled because the current instance is configured as a non-write Fineract instance");
if (notLiquibaseOnlyMode()) {
if (databaseStateVerifier.isLiquibaseDisabled() || !fineractProperties.getMode().isWriteEnabled()) {
log.warn("Liquibase is disabled. Not upgrading any database.");
if (!fineractProperties.getMode().isWriteEnabled()) {
log.warn("Liquibase is disabled because the current instance is configured as a non-write Fineract instance");
}
return;
}
return;
}
try {
upgradeTenantStore();
@@ -83,6 +78,11 @@ public class TenantDatabaseUpgradeService implements InitializingBean {
}
}
private boolean notLiquibaseOnlyMode() {
List<String> activeProfiles = Arrays.asList(environment.getActiveProfiles());
return !activeProfiles.contains(FineractProfiles.LIQUIBASE_ONLY);
}
private void upgradeTenantStore() throws LiquibaseException {
log.warn("Upgrading tenant store DB at {}:{}", fineractProperties.getTenant().getHost(), fineractProperties.getTenant().getPort());
logTenantStoreDetails();
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.security.service;
package org.apache.fineract.infrastructure.core.service.tenant;
import java.util.List;
import javax.sql.DataSource;
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.security.service;
package org.apache.fineract.infrastructure.core.service.tenant;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
@@ -17,7 +17,7 @@
* under the License.
*/
package org.apache.fineract.infrastructure.security.service;
package org.apache.fineract.infrastructure.core.service.tenant;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -44,7 +44,7 @@ public final class TenantMapper implements RowMapper<FineractPlatformTenant> {
+ " from tenants t left join tenant_server_connections ts ";
private final StringBuilder sqlBuilder = new StringBuilder(TENANT_SERVER_CONNECTION_BUILDER);
TenantMapper(boolean isReport) {
public TenantMapper(boolean isReport) {
this.isReport = isReport;
}
@@ -28,9 +28,9 @@ import java.util.List;
import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.DatabaseIndependentQueryService;
import org.apache.fineract.infrastructure.core.service.database.IndexDetail;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource;
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnValueData;
@@ -29,11 +29,11 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.apache.fineract.infrastructure.event.business.domain.BulkBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
import org.apache.fineract.infrastructure.event.external.exception.ExternalEventConfigurationNotFoundException;
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventSourceService;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
@@ -19,7 +19,7 @@
package org.apache.fineract.infrastructure.jobs;
import org.apache.fineract.infrastructure.core.persistence.ExtendedJpaTransactionManager;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
@@ -29,9 +29,9 @@ import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.domain.ActionContext;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
import org.apache.fineract.infrastructure.jobs.domain.SchedulerDetail;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@@ -27,7 +27,7 @@ import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadP
import org.apache.fineract.infrastructure.core.domain.ActionContext;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Trigger;
@@ -27,10 +27,10 @@ import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadP
import org.apache.fineract.infrastructure.core.domain.ActionContext;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.apache.fineract.infrastructure.event.external.service.JdbcTemplateFactory;
import org.apache.fineract.infrastructure.jobs.domain.JobExecutionRepository;
import org.apache.fineract.infrastructure.jobs.service.jobname.JobNameProvider;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationListener;
@@ -18,9 +18,9 @@
*/
package org.apache.fineract.infrastructure.jobs.service.updatenpa;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.springframework.batch.core.Job;
@@ -21,10 +21,10 @@ package org.apache.fineract.infrastructure.jobs.service.updatenpa;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.batch.core.StepContribution;
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.security.service;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.tenant.TenantMapper;
import org.apache.fineract.infrastructure.security.exception.InvalidTenantIdentifierException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -18,7 +18,7 @@
*/
package org.apache.fineract.portfolio.savings.jobs.generaterdschedule;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.portfolio.savings.service.DepositAccountReadPlatformService;
import org.springframework.batch.core.Job;
@@ -26,7 +26,7 @@ import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.portfolio.savings.DepositAccountUtils;
import org.apache.fineract.portfolio.savings.service.DepositAccountReadPlatformService;
import org.springframework.batch.core.StepContribution;
@@ -0,0 +1,20 @@
#
# 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.
#
spring.main.web-application-type=none
@@ -159,7 +159,7 @@ spring.datasource.hikari.dataSourceProperties['dumpQueriesOnException']=${FINERA
spring.jpa.open-in-view=false
# Liquibase configuration
spring.liquibase.enabled=true
spring.liquibase.enabled=${FINERACT_LIQUIBASE_ENABLED:true}
spring.liquibase.changeLog=classpath:/db/changelog/db.changelog-master.xml
spring.liquibase.parameters.fineract.tenant.identifier=${fineract.tenant.identifier}
@@ -30,9 +30,9 @@ import org.apache.fineract.infrastructure.core.service.migration.ExtendedSpringL
import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory;
import org.apache.fineract.infrastructure.core.service.migration.TenantDatabaseStateVerifier;
import org.apache.fineract.infrastructure.core.service.migration.TenantDatabaseUpgradeService;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.apache.fineract.infrastructure.jobs.ScheduledJobRunnerConfig;
import org.apache.fineract.infrastructure.jobs.service.JobRegisterService;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -59,6 +59,7 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -138,8 +139,8 @@ public class TestConfiguration {
@Bean
public TenantDatabaseStateVerifier tenantDatabaseStateVerifier(DatabaseIndependentQueryService databaseIndependentQueryService,
LiquibaseProperties liquibaseProperties, FineractProperties fineractProperties) {
return new TenantDatabaseStateVerifier(liquibaseProperties, databaseIndependentQueryService, fineractProperties);
LiquibaseProperties liquibaseProperties) {
return new TenantDatabaseStateVerifier(liquibaseProperties, databaseIndependentQueryService);
}
/**
@@ -150,9 +151,9 @@ public class TestConfiguration {
public TenantDatabaseUpgradeService tenantDatabaseUpgradeService(TenantDetailsService tenantDetailsService,
HikariDataSource tenantDataSource, TenantDatabaseStateVerifier tenantDatabaseStateVerifier,
ExtendedSpringLiquibaseFactory liquibaseFactory, TenantDataSourceFactory tenantDataSourceFactory,
FineractProperties fineractProperties) {
FineractProperties fineractProperties, Environment environment) {
return new TenantDatabaseUpgradeService(tenantDetailsService, tenantDataSource, fineractProperties, tenantDatabaseStateVerifier,
liquibaseFactory, tenantDataSourceFactory);
liquibaseFactory, tenantDataSourceFactory, environment);
}
/**
@@ -37,8 +37,8 @@ import javax.sql.DataSource;
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.core.service.DataSourcePerTenantServiceFactory;
import org.apache.fineract.infrastructure.core.service.HikariDataSourceFactory;
import org.apache.fineract.infrastructure.core.service.database.DataSourcePerTenantServiceFactory;
import org.apache.fineract.infrastructure.core.service.database.HikariDataSourceFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -39,8 +39,10 @@ import org.apache.fineract.infrastructure.core.service.migration.SchemaUpgradeNe
import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory;
import org.apache.fineract.infrastructure.core.service.migration.TenantDatabaseStateVerifier;
import org.apache.fineract.infrastructure.core.service.migration.TenantDatabaseUpgradeService;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.mock.env.MockEnvironment;
public class LiquibaseStepDefinitions implements En {
@@ -61,6 +63,7 @@ public class LiquibaseStepDefinitions implements En {
private List<FineractPlatformTenant> allTenants;
private SchemaUpgradeNeededException executionException;
private DataSource defaultTenantDataSource;
private Environment environment;
public LiquibaseStepDefinitions() {
Given("Liquibase is disabled with a default tenant", () -> {
@@ -148,6 +151,7 @@ public class LiquibaseStepDefinitions implements En {
tenantDataSourceFactory = mock(TenantDataSourceFactory.class);
tenantDetailsService = mock(TenantDetailsService.class);
databaseStateVerifier = mock(TenantDatabaseStateVerifier.class);
environment = new MockEnvironment();
liquibaseFactory = mock(ExtendedSpringLiquibaseFactory.class);
@@ -176,6 +180,6 @@ public class LiquibaseStepDefinitions implements En {
given(liquibaseFactory.create(defaultTenantDataSource, "tenant_db", "custom_changelog")).willReturn(customChangeLogLiquibase);
tenantDatabaseUpgradeService = new TenantDatabaseUpgradeService(tenantDetailsService, tenantStoreDataSource, fineractProperties,
databaseStateVerifier, liquibaseFactory, tenantDataSourceFactory);
databaseStateVerifier, liquibaseFactory, tenantDataSourceFactory, environment);
}
}
@@ -31,9 +31,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
import org.apache.fineract.infrastructure.event.external.exception.ExternalEventConfigurationNotFoundException;
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventSourceService;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;