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

aleks 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 47d5a85f1 [FINERACT-1678] configuration validation for COBs
47d5a85f1 is described below

commit 47d5a85f17912d866def938aba1dbc9dacb8af51
Author: taskain7 <[email protected]>
AuthorDate: Wed Aug 3 19:41:52 2022 +0200

    [FINERACT-1678] configuration validation for COBs
---
 fineract-provider/dependencies.gradle              |   1 +
 ...=> ExplicitConfigurationPropertiesFactory.java} |  19 +---
 .../config/FineractModeValidationCondition.java    |   9 +-
 ...eractPartitionJobConfigValidationCondition.java |  59 ++++++++++
 .../core/config/FineractProperties.java            |  21 ++++
 ...g.java => FineractStartupValidationConfig.java} |   9 +-
 .../core/config/FineractValidationCondition.java   |  35 ++++++
 .../src/main/resources/application.properties      |   5 +
 ...tPartitionJobConfigValidationConditionTest.java | 126 +++++++++++++++++++++
 .../src/test/resources/application-test.properties |   5 +
 10 files changed, 270 insertions(+), 19 deletions(-)

diff --git a/fineract-provider/dependencies.gradle 
b/fineract-provider/dependencies.gradle
index 18a5f5264..459a89306 100644
--- a/fineract-provider/dependencies.gradle
+++ b/fineract-provider/dependencies.gradle
@@ -166,5 +166,6 @@ dependencies {
         exclude group: 'javax.activation'
         exclude group: 'org.skyscreamer'
     }
+    testImplementation ('org.mockito:mockito-inline:4.6.1')
 
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationCondition.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/ExplicitConfigurationPropertiesFactory.java
similarity index 50%
copy from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationCondition.java
copy to 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/ExplicitConfigurationPropertiesFactory.java
index aafca6218..98e673890 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationCondition.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/ExplicitConfigurationPropertiesFactory.java
@@ -18,21 +18,14 @@
  */
 package org.apache.fineract.infrastructure.core.config;
 
-import java.util.Optional;
-import org.springframework.context.annotation.Condition;
+import org.springframework.boot.context.properties.bind.Binder;
 import org.springframework.context.annotation.ConditionContext;
-import org.springframework.core.type.AnnotatedTypeMetadata;
 
-public class FineractModeValidationCondition implements Condition {
+public final class ExplicitConfigurationPropertiesFactory {
 
-    @Override
-    public boolean matches(ConditionContext context, AnnotatedTypeMetadata 
metadata) {
-        boolean isReadModeEnabled = 
Optional.ofNullable(context.getEnvironment().getProperty("fineract.mode.read-enabled",
 Boolean.class))
-                .orElse(true);
-        boolean isWriteModeEnabled = 
Optional.ofNullable(context.getEnvironment().getProperty("fineract.mode.write-enabled",
 Boolean.class))
-                .orElse(true);
-        boolean isBatchModeEnabled = 
Optional.ofNullable(context.getEnvironment().getProperty("fineract.mode.batch-enabled",
 Boolean.class))
-                .orElse(true);
-        return !isReadModeEnabled && !isWriteModeEnabled && 
!isBatchModeEnabled;
+    private ExplicitConfigurationPropertiesFactory() {}
+
+    public static <T> T getProperty(ConditionContext context, String 
propertyName, Class<T> type) {
+        return Binder.get(context.getEnvironment()).bind(propertyName, 
type).orElse(null);
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationCondition.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationCondition.java
index aafca6218..aff4865a9 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationCondition.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationCondition.java
@@ -19,10 +19,12 @@
 package org.apache.fineract.infrastructure.core.config;
 
 import java.util.Optional;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Condition;
 import org.springframework.context.annotation.ConditionContext;
 import org.springframework.core.type.AnnotatedTypeMetadata;
 
+@Slf4j
 public class FineractModeValidationCondition implements Condition {
 
     @Override
@@ -33,6 +35,11 @@ public class FineractModeValidationCondition implements 
Condition {
                 .orElse(true);
         boolean isBatchModeEnabled = 
Optional.ofNullable(context.getEnvironment().getProperty("fineract.mode.batch-enabled",
 Boolean.class))
                 .orElse(true);
-        return !isReadModeEnabled && !isWriteModeEnabled && 
!isBatchModeEnabled;
+        boolean isValidationFails = !isReadModeEnabled && !isWriteModeEnabled 
&& !isBatchModeEnabled;
+        if (isValidationFails) {
+            log.error(
+                    "The Fineract instance type is not configured properly. At 
least one of these environment variables should be true: 
FINERACT_MODE_READ_ENABLED, FINERACT_MODE_WRITE_ENABLED, 
FINERACT_MODE_BATCH_ENABLED");
+        }
+        return isValidationFails;
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractPartitionJobConfigValidationCondition.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractPartitionJobConfigValidationCondition.java
new file mode 100644
index 000000000..3cb345e3b
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractPartitionJobConfigValidationCondition.java
@@ -0,0 +1,59 @@
+/**
+ * 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.config;
+
+import java.util.List;
+import java.util.function.Predicate;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+@Slf4j
+public class FineractPartitionJobConfigValidationCondition implements 
Condition {
+
+    @Override
+    public boolean matches(ConditionContext context, AnnotatedTypeMetadata 
metadata) {
+        FineractProperties.FineractPartitionedJob partitionedJobProperties = 
ExplicitConfigurationPropertiesFactory.getProperty(context,
+                "fineract.partitioned-job", 
FineractProperties.FineractPartitionedJob.class);
+        if (partitionedJobProperties != null) {
+            List<FineractProperties.PartitionedJobProperty> invalidConfigs = 
partitionedJobProperties.getPartitionedJobProperties().stream()
+                    
.filter(isAnyConfigBelowOne().or(FineractPartitionJobConfigValidationCondition::isPartitionRatioInvalid)).toList();
+            if (!invalidConfigs.isEmpty()) {
+                for (FineractProperties.PartitionedJobProperty invalidConfig : 
invalidConfigs) {
+                    log.error(
+                            "{} partitioned job is not configured properly. 
The partition size, chunk size and thread count must be more than 0, and 
partition size must be less then chunk size * thread count",
+                            invalidConfig.getJobName());
+                }
+            }
+            return !invalidConfigs.isEmpty();
+        } else {
+            return false;
+        }
+    }
+
+    private static Predicate<FineractProperties.PartitionedJobProperty> 
isAnyConfigBelowOne() {
+        return partitionedJobProperty -> 
!(partitionedJobProperty.getPartitionSize() > 0 && 
partitionedJobProperty.getChunkSize() > 0
+                && partitionedJobProperty.getThreadCount() > 0);
+    }
+
+    private static boolean 
isPartitionRatioInvalid(FineractProperties.PartitionedJobProperty 
partitionedJobProperty) {
+        return partitionedJobProperty.getPartitionSize() < 
partitionedJobProperty.getThreadCount() * partitionedJobProperty.getChunkSize();
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
index fb888cb89..e9ff3258e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
@@ -19,6 +19,7 @@
 
 package org.apache.fineract.infrastructure.core.config;
 
+import java.util.List;
 import lombok.Getter;
 import lombok.Setter;
 import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -36,6 +37,8 @@ public class FineractProperties {
 
     private FineractCorrelationProperties correlation;
 
+    private FineractPartitionedJob partitionedJob;
+
     @Getter
     @Setter
     public static class FineractTenantProperties {
@@ -72,4 +75,22 @@ public class FineractProperties {
         private boolean enabled;
         private String headerName;
     }
+
+    @Getter
+    @Setter
+    public static class FineractPartitionedJob {
+
+        // TODO should be used without wrapper class
+        private List<PartitionedJobProperty> partitionedJobProperties;
+    }
+
+    @Getter
+    @Setter
+    public static class PartitionedJobProperty {
+
+        private String jobName;
+        private Integer chunkSize;
+        private Integer partitionSize;
+        private Integer threadCount;
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationConfig.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractStartupValidationConfig.java
similarity index 78%
rename from 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationConfig.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractStartupValidationConfig.java
index 7fa3bb917..825cf8ff1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractModeValidationConfig.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractStartupValidationConfig.java
@@ -32,8 +32,8 @@ import org.springframework.stereotype.Component;
 @Component
 @Order(Ordered.HIGHEST_PRECEDENCE)
 @RequiredArgsConstructor
-@Conditional(FineractModeValidationCondition.class)
-public class FineractModeValidationConfig implements InitializingBean {
+@Conditional(FineractValidationCondition.class)
+public class FineractStartupValidationConfig implements InitializingBean {
 
     private final ApplicationContext applicationContext;
 
@@ -43,8 +43,7 @@ public class FineractModeValidationConfig implements 
InitializingBean {
     }
 
     private void terminateApplication() {
-        log.error(
-                "The Fineract instance type is not configured properly. At 
least one of these environment variables should be true: 
FINERACT_MODE_READ_ENABLED, FINERACT_MODE_WRITE_ENABLED, 
FINERACT_MODE_BATCH_ENABLED");
-        ((ConfigurableApplicationContext) this.applicationContext).close();
+        log.error("The application startup fails on validations. Please check 
the log above for the details");
+        ((ConfigurableApplicationContext) applicationContext).close();
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractValidationCondition.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractValidationCondition.java
new file mode 100644
index 000000000..f980ec092
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractValidationCondition.java
@@ -0,0 +1,35 @@
+/**
+ * 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.config;
+
+import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
+import org.springframework.context.annotation.Conditional;
+
+public class FineractValidationCondition extends AnyNestedCondition {
+
+    public FineractValidationCondition() {
+        super(ConfigurationPhase.PARSE_CONFIGURATION);
+    }
+
+    @Conditional(FineractModeValidationCondition.class)
+    static class FineractModeValidation {}
+
+    @Conditional(FineractPartitionJobConfigValidationCondition.class)
+    static class FineractPartitionedJobValidation {}
+}
diff --git a/fineract-provider/src/main/resources/application.properties 
b/fineract-provider/src/main/resources/application.properties
index ffdff8dcf..89bf99423 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -43,6 +43,11 @@ 
fineract.mode.batch-manager-enabled=${FINERACT_MODE_BATCH_MANAGER_ENABLED:true}
 
fineract.correlation.enabled=${FINERACT_LOGGING_HTTP_CORRELATION_ID_ENABLED:false}
 
fineract.correlation.header-name=${FINERACT_LOGGING_HTTP_CORRELATION_ID_HEADER_NAME:X-Correlation-ID}
 
+fineract.partitioned-job.partitioned-job-properties[0].job-name=LOAN_COB
+fineract.partitioned-job.partitioned-job-properties[0].chunk-size=${LOAN_COB_CHUNK_SIZE:100}
+fineract.partitioned-job.partitioned-job-properties[0].partition-size=${LOAN_COB_PARTITION_SIZE:100}
+fineract.partitioned-job.partitioned-job-properties[0].thread-count=${LOAN_COB_THREAD_COUNT:1}
+
 # Logging pattern for the console
 logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(%d{yyyy-MM-dd 
HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} 
%clr(%replace([%X{correlationId}]){'\\[\\]', ''}) %clr(---){faint} 
%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} 
%m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}
 
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/config/FineractPartitionJobConfigValidationConditionTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/config/FineractPartitionJobConfigValidationConditionTest.java
new file mode 100644
index 000000000..4e2d4b214
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/config/FineractPartitionJobConfigValidationConditionTest.java
@@ -0,0 +1,126 @@
+/**
+ * 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.config;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+class FineractPartitionJobConfigValidationConditionTest {
+
+    @InjectMocks
+    private FineractPartitionJobConfigValidationCondition testObj;
+
+    @Mock
+    private AnnotatedTypeMetadata metadata;
+
+    private ConditionContext context;
+
+    @BeforeEach
+    void setUp() {
+        context = mock(ConditionContext.class);
+    }
+
+    @Test
+    public void 
testApplicationStartup_ShouldApplicationStartupFails_WhenConfigurationNumbersAreBelowOne()
 {
+        try (MockedStatic<ExplicitConfigurationPropertiesFactory> 
propertyFactory = Mockito
+                .mockStatic(ExplicitConfigurationPropertiesFactory.class)) {
+            propertyFactory.when(() -> 
ExplicitConfigurationPropertiesFactory.getProperty(context, 
"fineract.partitioned-job",
+                    
FineractProperties.FineractPartitionedJob.class)).thenReturn(getBelowOneConfig());
+            assertTrue(testObj.matches(context, metadata));
+        }
+    }
+
+    @Test
+    public void 
testApplicationStartup_ShouldApplicationStartupFails_WhenPartitionSizeInvalid() 
{
+        try (MockedStatic<ExplicitConfigurationPropertiesFactory> 
propertyFactory = Mockito
+                .mockStatic(ExplicitConfigurationPropertiesFactory.class)) {
+            propertyFactory.when(() -> 
ExplicitConfigurationPropertiesFactory.getProperty(context, 
"fineract.partitioned-job",
+                    
FineractProperties.FineractPartitionedJob.class)).thenReturn(getInvalidPartitionSize());
+            assertTrue(testObj.matches(context, metadata));
+        }
+    }
+
+    @Test
+    public void 
testApplicationStartup_ShouldApplicationStart_WhenConfigValid() {
+        try (MockedStatic<ExplicitConfigurationPropertiesFactory> 
propertyFactory = Mockito
+                .mockStatic(ExplicitConfigurationPropertiesFactory.class)) {
+            propertyFactory.when(() -> 
ExplicitConfigurationPropertiesFactory.getProperty(context, 
"fineract.partitioned-job",
+                    
FineractProperties.FineractPartitionedJob.class)).thenReturn(getValidConfig());
+            assertFalse(testObj.matches(context, metadata));
+        }
+    }
+
+    private FineractProperties.FineractPartitionedJob getValidConfig() {
+        FineractProperties.FineractPartitionedJob partitionedJob = new 
FineractProperties.FineractPartitionedJob();
+        List<FineractProperties.PartitionedJobProperty> jobProperties = new 
ArrayList<>();
+        FineractProperties.PartitionedJobProperty partitionedJobProperty = new 
FineractProperties.PartitionedJobProperty();
+        partitionedJobProperty.setJobName("LOAN_COB");
+        partitionedJobProperty.setPartitionSize(100);
+        partitionedJobProperty.setChunkSize(10);
+        partitionedJobProperty.setThreadCount(10);
+        jobProperties.add(partitionedJobProperty);
+        partitionedJob.setPartitionedJobProperties(jobProperties);
+        return partitionedJob;
+    }
+
+    private FineractProperties.FineractPartitionedJob 
getInvalidPartitionSize() {
+        FineractProperties.FineractPartitionedJob partitionedJob = new 
FineractProperties.FineractPartitionedJob();
+        List<FineractProperties.PartitionedJobProperty> jobProperties = new 
ArrayList<>();
+        FineractProperties.PartitionedJobProperty partitionedJobProperty = new 
FineractProperties.PartitionedJobProperty();
+        partitionedJobProperty.setJobName("LOAN_COB");
+        partitionedJobProperty.setPartitionSize(99);
+        partitionedJobProperty.setChunkSize(10);
+        partitionedJobProperty.setThreadCount(10);
+        jobProperties.add(partitionedJobProperty);
+        partitionedJob.setPartitionedJobProperties(jobProperties);
+        return partitionedJob;
+    }
+
+    private FineractProperties.FineractPartitionedJob getBelowOneConfig() {
+        FineractProperties.FineractPartitionedJob partitionedJob = new 
FineractProperties.FineractPartitionedJob();
+        List<FineractProperties.PartitionedJobProperty> jobProperties = new 
ArrayList<>();
+        FineractProperties.PartitionedJobProperty partitionedJobProperty = new 
FineractProperties.PartitionedJobProperty();
+        partitionedJobProperty.setJobName("LOAN_COB");
+        partitionedJobProperty.setPartitionSize(0);
+        partitionedJobProperty.setChunkSize(1);
+        partitionedJobProperty.setThreadCount(1);
+        jobProperties.add(partitionedJobProperty);
+        partitionedJob.setPartitionedJobProperties(jobProperties);
+        return partitionedJob;
+    }
+
+}
diff --git a/fineract-provider/src/test/resources/application-test.properties 
b/fineract-provider/src/test/resources/application-test.properties
index 39b476324..f4fc3d53d 100644
--- a/fineract-provider/src/test/resources/application-test.properties
+++ b/fineract-provider/src/test/resources/application-test.properties
@@ -37,6 +37,11 @@ fineract.mode.read-enabled=true
 fineract.mode.write-enabled=true
 fineract.mode.batch-enabled=true
 
+fineract.partitioned-job.partitioned-job-properties[0].job-name=LOAN_COB
+fineract.partitioned-job.partitioned-job-properties[0].chunk-size=100
+fineract.partitioned-job.partitioned-job-properties[0].partition-size=100
+fineract.partitioned-job.partitioned-job-properties[0].thread-count=1
+
 management.health.jms.enabled=false
 
 # FINERACT 1296

Reply via email to