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