From 59409550a77bc7bd8e37d12049faad7983104947 Mon Sep 17 00:00:00 2001 From: Adam Saghy Date: Mon, 21 Jul 2025 14:53:25 +0200 Subject: [PATCH] FINERACT-2181: Money helper exception handling --- .../tenant/JdbcTenantDetailsService.java | 2 +- .../monetary/domain/MoneyHelper.java | 7 +- .../MoneyHelperInitializationService.java | 25 +------ ...neyHelperStartupInitializationService.java | 74 +++++++------------ 4 files changed, 32 insertions(+), 76 deletions(-) diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/tenant/JdbcTenantDetailsService.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/tenant/JdbcTenantDetailsService.java index 3cc6167ed..e248b301a 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/tenant/JdbcTenantDetailsService.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/tenant/JdbcTenantDetailsService.java @@ -35,7 +35,7 @@ import org.springframework.stereotype.Service; * A JDBC implementation of {@link TenantDetailsService} for loading a tenants details by a * tenantIdentifier. */ -@Service +@Service("tenantDetailsService") public class JdbcTenantDetailsService implements TenantDetailsService { private final JdbcTemplate jdbcTemplate; diff --git a/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MoneyHelper.java b/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MoneyHelper.java index f605f8e8d..10e55688d 100644 --- a/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MoneyHelper.java +++ b/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MoneyHelper.java @@ -33,7 +33,6 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; public final class MoneyHelper { public static final int PRECISION = 19; - private static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_EVEN; private static final ConcurrentHashMap roundingModeCache = new ConcurrentHashMap<>(); private static final ConcurrentHashMap mathContextCache = new ConcurrentHashMap<>(); @@ -62,7 +61,7 @@ public final class MoneyHelper { // Clear math context cache to force recreation with new rounding mode 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); if (roundingMode == null) { - // For integration tests and development, use default if not initialized - log.warn("Rounding mode not initialized for tenant: {}. Using default: {}", tenantId, DEFAULT_ROUNDING_MODE); - return DEFAULT_ROUNDING_MODE; + throw new IllegalStateException("Rounding mode is not initialized for tenant: " + tenantId); } return roundingMode; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/MoneyHelperInitializationService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/MoneyHelperInitializationService.java index 617ef4a28..04eac2f3d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/MoneyHelperInitializationService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/MoneyHelperInitializationService.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.infrastructure.configuration.service; -import java.math.RoundingMode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; @@ -66,9 +65,6 @@ public class MoneyHelperInitializationService { // Initialize MoneyHelper for this tenant MoneyHelper.initializeTenantRoundingMode(tenantIdentifier, roundingModeValue); - - log.info("MoneyHelper initialized for tenant '{}' with rounding mode: {}", tenantIdentifier, roundingModeValue); - } catch (Exception e) { log.error("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 - * configuration might not be available. + * Get the rounding mode from configuration with fallback to default. * * @return the rounding mode value */ private int getRoundingModeFromConfiguration() { - try { - GlobalConfigurationProperty roundingModeProperty = globalConfigurationRepository - .findOneByNameWithNotFoundDetection(GlobalConfigurationConstants.ROUNDING_MODE); - - 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; + GlobalConfigurationProperty roundingModeProperty = globalConfigurationRepository + .findOneByNameWithNotFoundDetection(GlobalConfigurationConstants.ROUNDING_MODE); + return roundingModeProperty.getValue().intValue(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/MoneyHelperStartupInitializationService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/MoneyHelperStartupInitializationService.java index 7215d9616..bdef68fa6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/MoneyHelperStartupInitializationService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/MoneyHelperStartupInitializationService.java @@ -23,9 +23,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; -import org.springframework.core.annotation.Order; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Service; /** @@ -35,7 +34,8 @@ import org.springframework.stereotype.Service; @Service @Slf4j @RequiredArgsConstructor -public class MoneyHelperStartupInitializationService { +@DependsOn({ "tenantDetailsService", "moneyHelperInitializationService", "tenantDatabaseUpgradeService" }) +public class MoneyHelperStartupInitializationService implements InitializingBean { private final TenantDetailsService tenantDetailsService; 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 * 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) - @Order(1000) // Run after other startup processes - public void initializeMoneyHelperForAllTenants() { + @Override + public void afterPropertiesSet() throws Exception { log.info("Starting MoneyHelper initialization for all tenants..."); - try { - List tenants = tenantDetailsService.findAllTenants(); - - if (tenants.isEmpty()) { - 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); + List tenants = tenantDetailsService.findAllTenants(); + if (tenants.isEmpty()) { + log.warn("No tenants found during MoneyHelper initialization"); + return; } + + 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"); } }