FINERACT-2181: Money helper exception handling
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@ import org.springframework.stereotype.Service;
|
|||||||
* A JDBC implementation of {@link TenantDetailsService} for loading a tenants details by a
|
* A JDBC implementation of {@link TenantDetailsService} for loading a tenants details by a
|
||||||
* <code>tenantIdentifier</code>.
|
* <code>tenantIdentifier</code>.
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service("tenantDetailsService")
|
||||||
public class JdbcTenantDetailsService implements TenantDetailsService {
|
public class JdbcTenantDetailsService implements TenantDetailsService {
|
||||||
|
|
||||||
private final JdbcTemplate jdbcTemplate;
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
|||||||
+2
-5
@@ -33,7 +33,6 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
|||||||
public final class MoneyHelper {
|
public final class MoneyHelper {
|
||||||
|
|
||||||
public static final int PRECISION = 19;
|
public static final int PRECISION = 19;
|
||||||
private static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_EVEN;
|
|
||||||
|
|
||||||
private static final ConcurrentHashMap<String, RoundingMode> roundingModeCache = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<String, RoundingMode> roundingModeCache = new ConcurrentHashMap<>();
|
||||||
private static final ConcurrentHashMap<String, MathContext> mathContextCache = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<String, MathContext> mathContextCache = new ConcurrentHashMap<>();
|
||||||
@@ -62,7 +61,7 @@ public final class MoneyHelper {
|
|||||||
// Clear math context cache to force recreation with new rounding mode
|
// Clear math context cache to force recreation with new rounding mode
|
||||||
mathContextCache.remove(tenantIdentifier);
|
mathContextCache.remove(tenantIdentifier);
|
||||||
|
|
||||||
log.info("Initialized rounding mode for tenant {}: {}", tenantIdentifier, roundingMode.name());
|
log.info("Initialized rounding mode for tenant `{}`: {}", tenantIdentifier, roundingMode.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,9 +76,7 @@ public final class MoneyHelper {
|
|||||||
RoundingMode roundingMode = roundingModeCache.get(tenantId);
|
RoundingMode roundingMode = roundingModeCache.get(tenantId);
|
||||||
|
|
||||||
if (roundingMode == null) {
|
if (roundingMode == null) {
|
||||||
// For integration tests and development, use default if not initialized
|
throw new IllegalStateException("Rounding mode is not initialized for tenant: " + tenantId);
|
||||||
log.warn("Rounding mode not initialized for tenant: {}. Using default: {}", tenantId, DEFAULT_ROUNDING_MODE);
|
|
||||||
return DEFAULT_ROUNDING_MODE;
|
|
||||||
}
|
}
|
||||||
return roundingMode;
|
return roundingMode;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-21
@@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.configuration.service;
|
package org.apache.fineract.infrastructure.configuration.service;
|
||||||
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants;
|
import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants;
|
||||||
@@ -66,9 +65,6 @@ public class MoneyHelperInitializationService {
|
|||||||
|
|
||||||
// Initialize MoneyHelper for this tenant
|
// Initialize MoneyHelper for this tenant
|
||||||
MoneyHelper.initializeTenantRoundingMode(tenantIdentifier, roundingModeValue);
|
MoneyHelper.initializeTenantRoundingMode(tenantIdentifier, roundingModeValue);
|
||||||
|
|
||||||
log.info("MoneyHelper initialized for tenant '{}' with rounding mode: {}", tenantIdentifier, roundingModeValue);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
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);
|
||||||
@@ -90,26 +86,13 @@ public class MoneyHelperInitializationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the rounding mode from configuration with fallback to default. This method safely handles cases where
|
* Get the rounding mode from configuration with fallback to default.
|
||||||
* configuration might not be available.
|
|
||||||
*
|
*
|
||||||
* @return the rounding mode value
|
* @return the rounding mode value
|
||||||
*/
|
*/
|
||||||
private int getRoundingModeFromConfiguration() {
|
private int getRoundingModeFromConfiguration() {
|
||||||
try {
|
GlobalConfigurationProperty roundingModeProperty = globalConfigurationRepository
|
||||||
GlobalConfigurationProperty roundingModeProperty = globalConfigurationRepository
|
.findOneByNameWithNotFoundDetection(GlobalConfigurationConstants.ROUNDING_MODE);
|
||||||
.findOneByNameWithNotFoundDetection(GlobalConfigurationConstants.ROUNDING_MODE);
|
return roundingModeProperty.getValue().intValue();
|
||||||
|
|
||||||
if (roundingModeProperty != null && roundingModeProperty.getValue() != null) {
|
|
||||||
return roundingModeProperty.getValue().intValue();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Failed to read rounding mode from configuration: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to HALF_UP if configuration is not available
|
|
||||||
int defaultRoundingMode = RoundingMode.HALF_UP.ordinal();
|
|
||||||
log.info("Using default rounding mode: {} (HALF_UP)", defaultRoundingMode);
|
|
||||||
return defaultRoundingMode;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-49
@@ -23,9 +23,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||||
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
|
import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.annotation.DependsOn;
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +34,8 @@ import org.springframework.stereotype.Service;
|
|||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MoneyHelperStartupInitializationService {
|
@DependsOn({ "tenantDetailsService", "moneyHelperInitializationService", "tenantDatabaseUpgradeService" })
|
||||||
|
public class MoneyHelperStartupInitializationService implements InitializingBean {
|
||||||
|
|
||||||
private final TenantDetailsService tenantDetailsService;
|
private final TenantDetailsService tenantDetailsService;
|
||||||
private final MoneyHelperInitializationService moneyHelperInitializationService;
|
private final MoneyHelperInitializationService moneyHelperInitializationService;
|
||||||
@@ -43,54 +43,30 @@ public class MoneyHelperStartupInitializationService {
|
|||||||
/**
|
/**
|
||||||
* Initialize MoneyHelper for all tenants after the application is ready. This method runs after
|
* Initialize MoneyHelper for all tenants after the application is ready. This method runs after
|
||||||
* ApplicationReadyEvent to ensure all database migrations and tenant configurations are complete.
|
* ApplicationReadyEvent to ensure all database migrations and tenant configurations are complete.
|
||||||
|
*
|
||||||
|
* If it fails (for any reason), it will fail the application startup!
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
@EventListener(ApplicationReadyEvent.class)
|
@Override
|
||||||
@Order(1000) // Run after other startup processes
|
public void afterPropertiesSet() throws Exception {
|
||||||
public void initializeMoneyHelperForAllTenants() {
|
|
||||||
log.info("Starting MoneyHelper initialization for all tenants...");
|
log.info("Starting MoneyHelper initialization for all tenants...");
|
||||||
|
|
||||||
try {
|
List<FineractPlatformTenant> tenants = tenantDetailsService.findAllTenants();
|
||||||
List<FineractPlatformTenant> tenants = tenantDetailsService.findAllTenants();
|
if (tenants.isEmpty()) {
|
||||||
|
log.warn("No tenants found during MoneyHelper initialization");
|
||||||
if (tenants.isEmpty()) {
|
return;
|
||||||
log.warn("No tenants found during MoneyHelper initialization");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int successCount = 0;
|
|
||||||
int failureCount = 0;
|
|
||||||
|
|
||||||
for (FineractPlatformTenant tenant : tenants) {
|
|
||||||
try {
|
|
||||||
String tenantIdentifier = tenant.getTenantIdentifier();
|
|
||||||
|
|
||||||
// Check if already initialized (in case of restart scenarios)
|
|
||||||
if (moneyHelperInitializationService.isTenantInitialized(tenantIdentifier)) {
|
|
||||||
log.debug("MoneyHelper already initialized for tenant: {}", tenantIdentifier);
|
|
||||||
successCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize MoneyHelper for this tenant
|
|
||||||
moneyHelperInitializationService.initializeTenantRoundingMode(tenant);
|
|
||||||
successCount++;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
failureCount++;
|
|
||||||
log.error("Failed to initialize MoneyHelper for tenant '{}'", tenant.getTenantIdentifier(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("MoneyHelper initialization completed - Success: {}, Failures: {}, Total: {}", successCount, failureCount,
|
|
||||||
tenants.size());
|
|
||||||
|
|
||||||
if (failureCount > 0) {
|
|
||||||
log.warn("Some tenants failed MoneyHelper initialization. "
|
|
||||||
+ "These tenants may experience issues with rounding mode configuration.");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Critical error during MoneyHelper initialization for all tenants", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (FineractPlatformTenant tenant : tenants) {
|
||||||
|
String tenantIdentifier = tenant.getTenantIdentifier();
|
||||||
|
// Check if already initialized (in case of restart scenarios)
|
||||||
|
if (moneyHelperInitializationService.isTenantInitialized(tenantIdentifier)) {
|
||||||
|
log.debug("MoneyHelper already initialized for tenant: {}", tenantIdentifier);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Initialize MoneyHelper for this tenant
|
||||||
|
moneyHelperInitializationService.initializeTenantRoundingMode(tenant);
|
||||||
|
}
|
||||||
|
log.info("MoneyHelper initialization completed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user