This is an automated email from the ASF dual-hosted git repository.

arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 1c944dd83 FINERACT-1694-Validating-event-configuration
1c944dd83 is described below

commit 1c944dd83026319080eeaf2ac822db6eebda2a96
Author: Ruchi Dhamankar <[email protected]>
AuthorDate: Thu Oct 27 19:03:48 2022 +0530

    FINERACT-1694-Validating-event-configuration
---
 ...xternalEventConfigurationNotFoundException.java |   4 +
 ...xternalEventConfigurationValidationService.java |  98 +++++++++++
 .../JdbcTemplateFactory.java}                      |  20 ++-
 ...nalEventConfigurationValidationServiceTest.java | 182 +++++++++++++++++++++
 4 files changed, 300 insertions(+), 4 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/exception/ExternalEventConfigurationNotFoundException.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/exception/ExternalEventConfigurationNotFoundException.java
index ce56b9e1e..2d30a01fc 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/exception/ExternalEventConfigurationNotFoundException.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/exception/ExternalEventConfigurationNotFoundException.java
@@ -20,6 +20,10 @@ package 
org.apache.fineract.infrastructure.event.external.exception;
 
 public class ExternalEventConfigurationNotFoundException extends 
RuntimeException {
 
+    public ExternalEventConfigurationNotFoundException() {
+        super("All external events are not configured");
+    }
+
     public ExternalEventConfigurationNotFoundException(final String 
externalEventType) {
         super("Configuration not found for external event " + 
externalEventType);
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java
new file mode 100644
index 000000000..68dcd6cc9
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java
@@ -0,0 +1,98 @@
+/**
+ * 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.event.external.service;
+
+import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
+
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ClassInfoList;
+import io.github.classgraph.ScanResult;
+import java.util.List;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
+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.security.service.TenantDetailsService;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ExternalEventConfigurationValidationService implements 
InitializingBean {
+
+    private static final String EXTERNAL_EVENT_CLASSES_BASE_PACKAGE = 
"org.apache.fineract.infrastructure.event.business.domain";
+    private static final String EXTERNAL_EVENT_BUSINESS_INTERFACE = 
BusinessEvent.class.getName();
+    private static final String BULK_BUSINESS_EVENT = 
BulkBusinessEvent.class.getName();
+    private final TenantDetailsService tenantDetailsService;
+    private final JdbcTemplateFactory jdbcTemplateFactory;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        validateEventConfigurationForAllTenants();
+    }
+
+    private void validateEventConfigurationForAllTenants() throws 
ExternalEventConfigurationNotFoundException {
+        List<String> eventClasses = getAllEventClasses();
+        List<FineractPlatformTenant> tenants = 
tenantDetailsService.findAllTenants();
+
+        if (isNotEmpty(tenants)) {
+            for (FineractPlatformTenant tenant : tenants) {
+                validateEventConfigurationForIndividualTenant(tenant, 
eventClasses);
+            }
+        }
+    }
+
+    private void 
validateEventConfigurationForIndividualTenant(FineractPlatformTenant tenant, 
List<String> eventClasses)
+            throws ExternalEventConfigurationNotFoundException {
+        log.info("Validating external event configuration for {}", 
tenant.getTenantIdentifier());
+        List<String> eventConfigurations = 
getExternalEventConfigurationsForTenant(tenant);
+
+        if (eventClasses.size() != eventConfigurations.size()) {
+            throw new ExternalEventConfigurationNotFoundException();
+        }
+
+        for (String eventTypeClass : eventClasses) {
+            if (!eventConfigurations.contains(eventTypeClass)) {
+                throw new 
ExternalEventConfigurationNotFoundException(eventTypeClass);
+            }
+        }
+    }
+
+    private List<String> 
getExternalEventConfigurationsForTenant(FineractPlatformTenant tenant) {
+        final JdbcTemplate jdbcTemplate = jdbcTemplateFactory.create(tenant);
+        final StringBuilder eventConfigurations = new StringBuilder();
+        eventConfigurations.append("select me.type as type from 
m_external_event_configuration me");
+        List<String> configuredEventTypes = 
jdbcTemplate.queryForList(eventConfigurations.toString(), String.class);
+        return configuredEventTypes;
+    }
+
+    private List<String> getAllEventClasses() {
+        try (ScanResult scanResult = new 
ClassGraph().enableAllInfo().acceptPackages(EXTERNAL_EVENT_CLASSES_BASE_PACKAGE).scan())
 {
+            ClassInfoList businessEventClasses = 
scanResult.getClassesImplementing(EXTERNAL_EVENT_BUSINESS_INTERFACE)
+                    .filter(classInfo -> (!classInfo.isInterface() && 
!classInfo.isAbstract()
+                            && 
!classInfo.getName().equalsIgnoreCase(BULK_BUSINESS_EVENT)));
+            return businessEventClasses.stream().map(classInfo -> 
classInfo.getSimpleName()).collect(Collectors.toList());
+        }
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/exception/ExternalEventConfigurationNotFoundException.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/JdbcTemplateFactory.java
similarity index 52%
copy from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/exception/ExternalEventConfigurationNotFoundException.java
copy to 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/JdbcTemplateFactory.java
index ce56b9e1e..4929e050e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/exception/ExternalEventConfigurationNotFoundException.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/JdbcTemplateFactory.java
@@ -16,11 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.fineract.infrastructure.event.external.exception;
+package org.apache.fineract.infrastructure.event.external.service;
 
-public class ExternalEventConfigurationNotFoundException extends 
RuntimeException {
+import javax.sql.DataSource;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
+import 
org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
 
-    public ExternalEventConfigurationNotFoundException(final String 
externalEventType) {
-        super("Configuration not found for external event " + 
externalEventType);
+@RequiredArgsConstructor
+@Component
+public class JdbcTemplateFactory {
+
+    private final TenantDataSourceFactory tenantDataSourceFactory;
+
+    public JdbcTemplate create(FineractPlatformTenant tenant) {
+        DataSource tenantDataSource = tenantDataSourceFactory.create(tenant);
+        return new JdbcTemplate(tenantDataSource);
     }
 }
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
new file mode 100644
index 000000000..f9bb17f03
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
@@ -0,0 +1,182 @@
+/**
+ * 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.event.external.service;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+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.event.external.exception.ExternalEventConfigurationNotFoundException;
+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;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+@ExtendWith(MockitoExtension.class)
+public class ExternalEventConfigurationValidationServiceTest {
+
+    @Mock
+    private JdbcTemplateFactory jdbcTemplateFactory;
+
+    @Mock
+    private TenantDetailsService tenantDetailsService;
+
+    private ExternalEventConfigurationValidationService underTest;
+
+    @BeforeEach
+    public void setUp() {
+        underTest = new 
ExternalEventConfigurationValidationService(tenantDetailsService, 
jdbcTemplateFactory);
+    }
+
+    @Test
+    public void givenAllConfigurationWhenValidatedThenValidationSuccessful() 
throws Exception {
+
+        // given
+        List<String> configurations = 
Arrays.asList("CentersCreateBusinessEvent", "ClientActivateBusinessEvent",
+                "ClientCreateBusinessEvent", "ClientRejectBusinessEvent", 
"FixedDepositAccountCreateBusinessEvent",
+                "GroupsCreateBusinessEvent", 
"LoanAcceptTransferBusinessEvent", "LoanAddChargeBusinessEvent",
+                "LoanAdjustTransactionBusinessEvent", 
"LoanApplyOverdueChargeBusinessEvent", "LoanApprovedBusinessEvent",
+                "LoanBalanceChangedBusinessEvent", 
"LoanChargebackTransactionBusinessEvent", "LoanChargePaymentPostBusinessEvent",
+                "LoanChargePaymentPreBusinessEvent", 
"LoanChargeRefundBusinessEvent", "LoanCloseAsRescheduleBusinessEvent",
+                "LoanCloseBusinessEvent", "LoanCreatedBusinessEvent", 
"LoanCreditBalanceRefundPostBusinessEvent",
+                "LoanCreditBalanceRefundPreBusinessEvent", 
"LoanDeleteChargeBusinessEvent", "LoanDisbursalBusinessEvent",
+                "LoanDisbursalTransactionBusinessEvent", 
"LoanForeClosurePostBusinessEvent", "LoanForeClosurePreBusinessEvent",
+                "LoanInitiateTransferBusinessEvent", 
"LoanInterestRecalculationBusinessEvent", "LoanProductCreateBusinessEvent",
+                "LoanReassignOfficerBusinessEvent", 
"LoanRefundPostBusinessEvent", "LoanRefundPreBusinessEvent",
+                "LoanRejectedBusinessEvent", 
"LoanRejectTransferBusinessEvent", "LoanRemoveOfficerBusinessEvent",
+                "LoanRescheduledDueCalendarChangeBusinessEvent", 
"LoanRescheduledDueHolidayBusinessEvent",
+                "LoanScheduleVariationsAddedBusinessEvent", 
"LoanScheduleVariationsDeletedBusinessEvent", "LoanStatusChangedBusinessEvent",
+                "LoanTransactionGoodwillCreditPostBusinessEvent", 
"LoanTransactionGoodwillCreditPreBusinessEvent",
+                "LoanTransactionMakeRepaymentPostBusinessEvent", 
"LoanTransactionMakeRepaymentPreBusinessEvent",
+                "LoanTransactionMerchantIssuedRefundPostBusinessEvent", 
"LoanTransactionMerchantIssuedRefundPreBusinessEvent",
+                "LoanTransactionPayoutRefundPostBusinessEvent", 
"LoanTransactionPayoutRefundPreBusinessEvent",
+                "LoanTransactionRecoveryPaymentPostBusinessEvent", 
"LoanTransactionRecoveryPaymentPreBusinessEvent",
+                "LoanUndoApprovalBusinessEvent", 
"LoanUndoDisbursalBusinessEvent", "LoanUndoLastDisbursalBusinessEvent",
+                "LoanUndoWrittenOffBusinessEvent", 
"LoanUpdateChargeBusinessEvent", "LoanUpdateDisbursementDataBusinessEvent",
+                "LoanWaiveChargeBusinessEvent", 
"LoanWaiveChargeUndoBusinessEvent", "LoanWaiveInterestBusinessEvent",
+                "LoanWithdrawTransferBusinessEvent", 
"LoanWrittenOffPostBusinessEvent", "LoanWrittenOffPreBusinessEvent",
+                "RecurringDepositAccountCreateBusinessEvent", 
"SavingsActivateBusinessEvent", "SavingsApproveBusinessEvent",
+                "SavingsCloseBusinessEvent", "SavingsCreateBusinessEvent", 
"SavingsDepositBusinessEvent",
+                "SavingsPostInterestBusinessEvent", 
"SavingsRejectBusinessEvent", "SavingsWithdrawalBusinessEvent",
+                "ShareAccountApproveBusinessEvent", 
"ShareAccountCreateBusinessEvent", "ShareProductDividentsCreateBusinessEvent");
+
+        List<FineractPlatformTenant> tenants = Arrays
+                .asList(new FineractPlatformTenant(1L, "default", "Default 
Tenant", "Europe/Budapest", null));
+
+        JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
+        when(tenantDetailsService.findAllTenants()).thenReturn(tenants);
+        when(jdbcTemplateFactory.create(any())).thenReturn(jdbcTemplate);
+        when(jdbcTemplate.queryForList(anyString(), 
eq(String.class))).thenReturn(configurations);
+
+        // when
+        underTest.afterPropertiesSet();
+
+        // then
+        verify(tenantDetailsService).findAllTenants();
+        verify(jdbcTemplateFactory, times(1)).create(any());
+    }
+
+    @Test
+    public void givenNoEventConfigurationWhenValidatedThenThrowException() 
throws Exception {
+        // given
+        List<FineractPlatformTenant> tenants = Arrays
+                .asList(new FineractPlatformTenant(1L, "default", "Default 
Tenant", "Europe/Budapest", null));
+
+        JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
+        when(tenantDetailsService.findAllTenants()).thenReturn(tenants);
+        when(jdbcTemplateFactory.create(any())).thenReturn(jdbcTemplate);
+        when(jdbcTemplate.queryForList(anyString(), 
eq(String.class))).thenReturn(new ArrayList<>());
+
+        // when
+        ExternalEventConfigurationNotFoundException exceptionThrown = 
assertThrows(ExternalEventConfigurationNotFoundException.class,
+                () -> underTest.afterPropertiesSet());
+
+        // then
+        String expectedMessage = "All external events are not configured";
+        String actualMessage = exceptionThrown.getMessage();
+
+        assertTrue(actualMessage.contains(expectedMessage));
+
+    }
+
+    @Test
+    public void 
givenMissingEventConfigurationWhenValidatedThenThrowException() throws 
Exception {
+
+        // given
+        List<String> configurationWithMissingCentersCreateBusinessEvent = 
Arrays.asList("MockBusinessEvent", "ClientActivateBusinessEvent",
+                "ClientCreateBusinessEvent", "ClientRejectBusinessEvent", 
"FixedDepositAccountCreateBusinessEvent",
+                "GroupsCreateBusinessEvent", 
"LoanAcceptTransferBusinessEvent", "LoanAddChargeBusinessEvent",
+                "LoanAdjustTransactionBusinessEvent", 
"LoanApplyOverdueChargeBusinessEvent", "LoanApprovedBusinessEvent",
+                "LoanBalanceChangedBusinessEvent", 
"LoanChargebackTransactionBusinessEvent", "LoanChargePaymentPostBusinessEvent",
+                "LoanChargePaymentPreBusinessEvent", 
"LoanChargeRefundBusinessEvent", "LoanCloseAsRescheduleBusinessEvent",
+                "LoanCloseBusinessEvent", "LoanCreatedBusinessEvent", 
"LoanCreditBalanceRefundPostBusinessEvent",
+                "LoanCreditBalanceRefundPreBusinessEvent", 
"LoanDeleteChargeBusinessEvent", "LoanDisbursalBusinessEvent",
+                "LoanDisbursalTransactionBusinessEvent", 
"LoanForeClosurePostBusinessEvent", "LoanForeClosurePreBusinessEvent",
+                "LoanInitiateTransferBusinessEvent", 
"LoanInterestRecalculationBusinessEvent", "LoanProductCreateBusinessEvent",
+                "LoanReassignOfficerBusinessEvent", 
"LoanRefundPostBusinessEvent", "LoanRefundPreBusinessEvent",
+                "LoanRejectedBusinessEvent", 
"LoanRejectTransferBusinessEvent", "LoanRemoveOfficerBusinessEvent",
+                "LoanRescheduledDueCalendarChangeBusinessEvent", 
"LoanRescheduledDueHolidayBusinessEvent",
+                "LoanScheduleVariationsAddedBusinessEvent", 
"LoanScheduleVariationsDeletedBusinessEvent", "LoanStatusChangedBusinessEvent",
+                "LoanTransactionGoodwillCreditPostBusinessEvent", 
"LoanTransactionGoodwillCreditPreBusinessEvent",
+                "LoanTransactionMakeRepaymentPostBusinessEvent", 
"LoanTransactionMakeRepaymentPreBusinessEvent",
+                "LoanTransactionMerchantIssuedRefundPostBusinessEvent", 
"LoanTransactionMerchantIssuedRefundPreBusinessEvent",
+                "LoanTransactionPayoutRefundPostBusinessEvent", 
"LoanTransactionPayoutRefundPreBusinessEvent",
+                "LoanTransactionRecoveryPaymentPostBusinessEvent", 
"LoanTransactionRecoveryPaymentPreBusinessEvent",
+                "LoanUndoApprovalBusinessEvent", 
"LoanUndoDisbursalBusinessEvent", "LoanUndoLastDisbursalBusinessEvent",
+                "LoanUndoWrittenOffBusinessEvent", 
"LoanUpdateChargeBusinessEvent", "LoanUpdateDisbursementDataBusinessEvent",
+                "LoanWaiveChargeBusinessEvent", 
"LoanWaiveChargeUndoBusinessEvent", "LoanWaiveInterestBusinessEvent",
+                "LoanWithdrawTransferBusinessEvent", 
"LoanWrittenOffPostBusinessEvent", "LoanWrittenOffPreBusinessEvent",
+                "RecurringDepositAccountCreateBusinessEvent", 
"SavingsActivateBusinessEvent", "SavingsApproveBusinessEvent",
+                "SavingsCloseBusinessEvent", "SavingsCreateBusinessEvent", 
"SavingsDepositBusinessEvent",
+                "SavingsPostInterestBusinessEvent", 
"SavingsRejectBusinessEvent", "SavingsWithdrawalBusinessEvent",
+                "ShareAccountApproveBusinessEvent", 
"ShareAccountCreateBusinessEvent", "ShareProductDividentsCreateBusinessEvent");
+        List<FineractPlatformTenant> tenants = Arrays
+                .asList(new FineractPlatformTenant(1L, "default", "Default 
Tenant", "Europe/Budapest", null));
+
+        JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
+        when(tenantDetailsService.findAllTenants()).thenReturn(tenants);
+        when(jdbcTemplateFactory.create(any())).thenReturn(jdbcTemplate);
+        when(jdbcTemplate.queryForList(anyString(), 
eq(String.class))).thenReturn(configurationWithMissingCentersCreateBusinessEvent);
+
+        // when
+        ExternalEventConfigurationNotFoundException exceptionThrown = 
assertThrows(ExternalEventConfigurationNotFoundException.class,
+                () -> underTest.afterPropertiesSet());
+
+        // then
+        String expectedMessage = "Configuration not found for external event 
CentersCreateBusinessEvent";
+        String actualMessage = exceptionThrown.getMessage();
+
+        assertTrue(actualMessage.contains(expectedMessage));
+
+    }
+
+}

Reply via email to