FINERACT-2389: Fix for rounding mode not being initialized whenever a new tenant is added to the system without a restart
This commit is contained in:
committed by
Arnold Gálovics
parent
63c220e5d2
commit
5079203d57
+12
-3
@@ -26,6 +26,8 @@ import org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurati
|
|||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +42,10 @@ import org.springframework.stereotype.Service;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MoneyHelperInitializationService {
|
public class MoneyHelperInitializationService {
|
||||||
|
|
||||||
private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
|
// TODO: this is preventing the circular dependency...
|
||||||
|
@Lazy
|
||||||
|
@Autowired
|
||||||
|
private GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize MoneyHelper for a specific tenant. This method should be called during tenant setup and whenever
|
* Initialize MoneyHelper for a specific tenant. This method should be called during tenant setup and whenever
|
||||||
@@ -56,6 +61,7 @@ public class MoneyHelperInitializationService {
|
|||||||
|
|
||||||
String tenantIdentifier = tenant.getTenantIdentifier();
|
String tenantIdentifier = tenant.getTenantIdentifier();
|
||||||
|
|
||||||
|
FineractPlatformTenant originalTenant = ThreadLocalContextUtil.getTenant();
|
||||||
try {
|
try {
|
||||||
// Set tenant context to read configuration
|
// Set tenant context to read configuration
|
||||||
ThreadLocalContextUtil.setTenant(tenant);
|
ThreadLocalContextUtil.setTenant(tenant);
|
||||||
@@ -69,8 +75,7 @@ public class MoneyHelperInitializationService {
|
|||||||
log.error("Failed to initialize MoneyHelper for tenant '{}'", tenantIdentifier, e);
|
log.error("Failed to initialize MoneyHelper for tenant '{}'", tenantIdentifier, e);
|
||||||
throw new RuntimeException("Failed to initialize MoneyHelper for tenant: " + tenantIdentifier, e);
|
throw new RuntimeException("Failed to initialize MoneyHelper for tenant: " + tenantIdentifier, e);
|
||||||
} finally {
|
} finally {
|
||||||
// Clear tenant context
|
ThreadLocalContextUtil.setTenant(originalTenant);
|
||||||
ThreadLocalContextUtil.clearTenant();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +90,10 @@ public class MoneyHelperInitializationService {
|
|||||||
return MoneyHelper.isTenantInitialized(tenantIdentifier);
|
return MoneyHelper.isTenantInitialized(tenantIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isTenantInitialized(FineractPlatformTenant tenant) {
|
||||||
|
return isTenantInitialized(tenant.getTenantIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the rounding mode from configuration with fallback to default.
|
* Get the rounding mode from configuration with fallback to default.
|
||||||
*
|
*
|
||||||
+22
@@ -18,14 +18,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.core.service.database;
|
package org.apache.fineract.infrastructure.core.service.database;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.fineract.infrastructure.configuration.service.MoneyHelperInitializationService;
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
@@ -53,6 +56,9 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
|
|||||||
|
|
||||||
private final DataSourcePerTenantServiceFactory dataSourcePerTenantServiceFactory;
|
private final DataSourcePerTenantServiceFactory dataSourcePerTenantServiceFactory;
|
||||||
|
|
||||||
|
private final MoneyHelperInitializationService moneyHelperInitializationService;
|
||||||
|
private final Set<Long> tenantMoneyInitializingSet = Sets.newConcurrentHashSet();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSource retrieveDataSource() {
|
public DataSource retrieveDataSource() {
|
||||||
// default to tenant database datasource
|
// default to tenant database datasource
|
||||||
@@ -66,7 +72,23 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
|
|||||||
// appropriate datasource for that tenant.
|
// appropriate datasource for that tenant.
|
||||||
actualDataSource = TENANT_TO_DATA_SOURCE_MAP.computeIfAbsent(tenantConnectionKey,
|
actualDataSource = TENANT_TO_DATA_SOURCE_MAP.computeIfAbsent(tenantConnectionKey,
|
||||||
(key) -> dataSourcePerTenantServiceFactory.createNewDataSourceFor(tenant, tenantConnection));
|
(key) -> dataSourcePerTenantServiceFactory.createNewDataSourceFor(tenant, tenantConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This is definitely not the optimal place to initialize the rounding modes
|
||||||
|
// Preferably nothing should use a statically referenced context and the initialization
|
||||||
|
// should happen within the rounding mode retrieval
|
||||||
|
if (tenant != null) {
|
||||||
|
Long connectionId = tenant.getConnection().getConnectionId();
|
||||||
|
if (!tenantMoneyInitializingSet.contains(connectionId) && !moneyHelperInitializationService.isTenantInitialized(tenant)) {
|
||||||
|
// Double check to prevent visibility and race-condition issues
|
||||||
|
synchronized (tenantMoneyInitializingSet) {
|
||||||
|
if (!tenantMoneyInitializingSet.contains(connectionId)) {
|
||||||
|
tenantMoneyInitializingSet.add(connectionId);
|
||||||
|
moneyHelperInitializationService.initializeTenantRoundingMode(tenant);
|
||||||
|
tenantMoneyInitializingSet.remove(connectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return actualDataSource;
|
return actualDataSource;
|
||||||
|
|||||||
Reference in New Issue
Block a user