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 8a1f13488 [FINERACT-1678] Loan COB job skeleton
8a1f13488 is described below
commit 8a1f1348812bc1b7faae32d814b827be6569a994
Author: taskain7 <[email protected]>
AuthorDate: Wed Aug 3 19:41:52 2022 +0200
[FINERACT-1678] Loan COB job skeleton
---
fineract-provider/dependencies.gradle | 7 +-
.../fineract/cob/COBInputChannelInterceptor.java | 36 +++++++++
.../org/apache/fineract/cob/COBManagerConfig.java | 55 +++++++++++++
.../COBMessage.java} | 22 +++--
.../fineract/cob/COBOutputChannelInterceptor.java | 38 +++++++++
.../COBPropertyService.java} | 17 +---
.../fineract/cob/COBPropertyServiceImpl.java | 53 ++++++++++++
.../org/apache/fineract/cob/COBWorkerConfig.java | 60 ++++++++++++++
.../cob/loan/LoanCOBManagerConfiguration.java | 69 ++++++++++++++++
.../fineract/cob/loan/LoanCOBPartitioner.java | 59 ++++++++++++++
.../cob/loan/LoanCOBWorkerConfiguration.java | 94 ++++++++++++++++++++++
.../config/FineractModeValidationCondition.java | 8 +-
.../core/config/FineractProperties.java | 16 ++++
.../FineractRemoteJobMessageHandlerCondition.java | 51 ++++++++++++
.../core/config/FineractValidationCondition.java | 3 +
.../infrastructure/jobs/service/JobName.java | 3 +-
.../jobs/service/JobRegisterServiceImpl.java | 2 +-
.../jobs/service/JobSchedulerServiceImpl.java | 7 ++
.../infrastructure/jobs/service/JobStarter.java | 8 +-
.../service/SchedulerJobRunnerReadServiceImpl.java | 2 +
.../loanaccount/domain/LoanRepository.java | 5 ++
.../src/main/resources/application.properties | 2 +
.../db/changelog/tenant/changelog-tenant.xml | 1 +
.../tenant/parts/0037_add_loan_cob_job_data.xml | 45 +++++++++++
24 files changed, 627 insertions(+), 36 deletions(-)
diff --git a/fineract-provider/dependencies.gradle
b/fineract-provider/dependencies.gradle
index 459a89306..ca0992ef3 100644
--- a/fineract-provider/dependencies.gradle
+++ b/fineract-provider/dependencies.gradle
@@ -32,6 +32,10 @@ dependencies {
'org.springframework.boot:spring-boot-starter-cache',
'org.springframework.boot:spring-boot-starter-oauth2-resource-server',
'org.springframework.boot:spring-boot-starter-actuator',
+ 'org.springframework.boot:spring-boot-starter-batch',
+ 'org.springframework.batch:spring-batch-integration',
+ 'org.springframework.boot:spring-boot-starter-integration',
+ 'org.springframework.integration:spring-integration-event',
'org.glassfish.jersey.media:jersey-media-multipart:2.36',
@@ -129,9 +133,6 @@ dependencies {
exclude group: 'xml-apis'
}
- implementation ('org.springframework.boot:spring-boot-starter-batch') {
- }
-
runtimeOnly('org.glassfish.jaxb:jaxb-runtime') {
exclude group: 'com.sun.activation'
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/COBInputChannelInterceptor.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBInputChannelInterceptor.java
new file mode 100644
index 000000000..05626e77b
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBInputChannelInterceptor.java
@@ -0,0 +1,36 @@
+/**
+ * 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.cob;
+
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.MessageHandler;
+import org.springframework.messaging.support.ExecutorChannelInterceptor;
+import org.springframework.messaging.support.GenericMessage;
+
+public class COBInputChannelInterceptor implements ExecutorChannelInterceptor {
+
+ @Override
+ public Message<?> beforeHandle(Message<?> message, MessageChannel channel,
MessageHandler handler) {
+ COBMessage castedMessage = COBMessage.class.cast(message.getPayload());
+ ThreadLocalContextUtil.init(castedMessage.getContext());
+ return new GenericMessage<>(castedMessage.getStepExecutionRequest());
+ }
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/COBManagerConfig.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBManagerConfig.java
new file mode 100644
index 000000000..9796cc37e
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBManagerConfig.java
@@ -0,0 +1,55 @@
+/**
+ * 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.cob;
+
+import
org.springframework.batch.integration.config.annotation.EnableBatchIntegration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.dsl.IntegrationFlow;
+import org.springframework.integration.dsl.IntegrationFlows;
+import
org.springframework.integration.event.outbound.ApplicationEventPublishingMessageHandler;
+import org.springframework.integration.handler.LoggingHandler;
+
+@Configuration
+@EnableBatchIntegration
+@ConditionalOnProperty(value = "fineract.mode.batch-manager-enabled",
havingValue = "true")
+public class COBManagerConfig {
+
+ @Bean
+ public IntegrationFlow outboundFlow() {
+ ApplicationEventPublishingMessageHandler handler = new
ApplicationEventPublishingMessageHandler();
+ return IntegrationFlows.from(outboundRequests()) //
+ .intercept(outputInterceptor()) //
+ .log(LoggingHandler.Level.DEBUG) //
+ .handle(handler) //
+ .get(); //
+ }
+
+ @Bean
+ public DirectChannel outboundRequests() {
+ return new DirectChannel();
+ }
+
+ @Bean
+ public COBOutputChannelInterceptor outputInterceptor() {
+ return new COBOutputChannelInterceptor();
+ }
+}
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/cob/COBMessage.java
similarity index 57%
copy from
fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractValidationCondition.java
copy to fineract-provider/src/main/java/org/apache/fineract/cob/COBMessage.java
index f980ec092..f7b04ea7f 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractValidationCondition.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/COBMessage.java
@@ -16,20 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.infrastructure.core.config;
+package org.apache.fineract.cob;
-import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
-import org.springframework.context.annotation.Conditional;
+import java.io.Serializable;
+import lombok.Data;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.springframework.batch.integration.partition.StepExecutionRequest;
-public class FineractValidationCondition extends AnyNestedCondition {
+@Data
+public class COBMessage implements Serializable {
- public FineractValidationCondition() {
- super(ConfigurationPhase.PARSE_CONFIGURATION);
- }
-
- @Conditional(FineractModeValidationCondition.class)
- static class FineractModeValidation {}
-
- @Conditional(FineractPartitionJobConfigValidationCondition.class)
- static class FineractPartitionedJobValidation {}
+ private StepExecutionRequest stepExecutionRequest;
+ private FineractContext context;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/COBOutputChannelInterceptor.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBOutputChannelInterceptor.java
new file mode 100644
index 000000000..5c06c4d94
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBOutputChannelInterceptor.java
@@ -0,0 +1,38 @@
+/**
+ * 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.cob;
+
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.springframework.batch.integration.async.StepExecutionInterceptor;
+import org.springframework.batch.integration.partition.StepExecutionRequest;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.support.GenericMessage;
+
+public class COBOutputChannelInterceptor extends StepExecutionInterceptor {
+
+ @Override
+ public Message<?> preSend(Message<?> message, MessageChannel channel) {
+ StepExecutionRequest stepExecutionRequest =
StepExecutionRequest.class.cast(message.getPayload());
+ COBMessage cobMessage = new COBMessage();
+ cobMessage.setStepExecutionRequest(stepExecutionRequest);
+ cobMessage.setContext(ThreadLocalContextUtil.getContext());
+ return new GenericMessage<>(cobMessage);
+ }
+}
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/cob/COBPropertyService.java
similarity index 57%
copy from
fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractValidationCondition.java
copy to
fineract-provider/src/main/java/org/apache/fineract/cob/COBPropertyService.java
index f980ec092..58c6d534c 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractValidationCondition.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBPropertyService.java
@@ -16,20 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.infrastructure.core.config;
+package org.apache.fineract.cob;
-import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
-import org.springframework.context.annotation.Conditional;
+public interface COBPropertyService {
-public class FineractValidationCondition extends AnyNestedCondition {
+ Integer getPartitionSize(String jobName);
- public FineractValidationCondition() {
- super(ConfigurationPhase.PARSE_CONFIGURATION);
- }
-
- @Conditional(FineractModeValidationCondition.class)
- static class FineractModeValidation {}
-
- @Conditional(FineractPartitionJobConfigValidationCondition.class)
- static class FineractPartitionedJobValidation {}
+ Integer getChunkSize(String jobName);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/COBPropertyServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBPropertyServiceImpl.java
new file mode 100644
index 000000000..27f3d5a8e
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBPropertyServiceImpl.java
@@ -0,0 +1,53 @@
+/**
+ * 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.cob;
+
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.config.FineractProperties;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class COBPropertyServiceImpl implements COBPropertyService {
+
+ private final FineractProperties fineractProperties;
+
+ @Override
+ public Integer getPartitionSize(String jobName) {
+ List<FineractProperties.PartitionedJobProperty> jobProperties =
fineractProperties.getPartitionedJob()
+ .getPartitionedJobProperties();
+ return jobProperties.stream() //
+ .filter(jobProperty ->
jobName.equals(jobProperty.getJobName())) //
+ .findFirst() //
+
.map(FineractProperties.PartitionedJobProperty::getPartitionSize) //
+ .orElse(0);
+ }
+
+ @Override
+ public Integer getChunkSize(String jobName) {
+ List<FineractProperties.PartitionedJobProperty> jobProperties =
fineractProperties.getPartitionedJob()
+ .getPartitionedJobProperties();
+ return jobProperties.stream() //
+ .filter(jobProperty ->
jobName.equals(jobProperty.getJobName())) //
+ .findFirst() //
+ .map(FineractProperties.PartitionedJobProperty::getChunkSize)
//
+ .orElse(0);
+ }
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/COBWorkerConfig.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBWorkerConfig.java
new file mode 100644
index 000000000..bd8e00043
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/COBWorkerConfig.java
@@ -0,0 +1,60 @@
+/**
+ * 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.cob;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.integration.dsl.IntegrationFlow;
+import org.springframework.integration.dsl.IntegrationFlows;
+import org.springframework.integration.event.core.MessagingEvent;
+import
org.springframework.integration.event.inbound.ApplicationEventListeningMessageProducer;
+import org.springframework.integration.handler.LoggingHandler;
+
+@Configuration
+@ConditionalOnProperty(value = "fineract.mode.batch-worker-enabled",
havingValue = "true")
+public class COBWorkerConfig {
+
+ @Bean
+ public IntegrationFlow inboundFlow() {
+ return IntegrationFlows.from(eventListener()) //
+ .log(LoggingHandler.Level.DEBUG) //
+ .channel(inboundRequests()) //
+ .intercept(inputInterceptor()) //
+ .get(); //
+ }
+
+ @Bean
+ public ApplicationEventListeningMessageProducer eventListener() {
+ ApplicationEventListeningMessageProducer producer = new
ApplicationEventListeningMessageProducer();
+ producer.setEventTypes(MessagingEvent.class);
+ return producer;
+ }
+
+ @Bean
+ public QueueChannel inboundRequests() {
+ return new QueueChannel();
+ }
+
+ @Bean
+ public COBInputChannelInterceptor inputInterceptor() {
+ return new COBInputChannelInterceptor();
+ }
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
new file mode 100644
index 000000000..077602c74
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
@@ -0,0 +1,69 @@
+/**
+ * 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.cob.loan;
+
+import org.apache.fineract.cob.COBPropertyService;
+import org.apache.fineract.infrastructure.jobs.service.JobName;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.Step;
+import
org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.launch.support.RunIdIncrementer;
+import
org.springframework.batch.integration.config.annotation.EnableBatchIntegration;
+import
org.springframework.batch.integration.partition.RemotePartitioningManagerStepBuilderFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.channel.DirectChannel;
+
+@Configuration
+@EnableBatchIntegration
+@ConditionalOnProperty(value = "fineract.mode.batch-manager-enabled",
havingValue = "true")
+public class LoanCOBManagerConfiguration {
+
+ @Autowired
+ private JobBuilderFactory jobBuilderFactory;
+ @Autowired
+ private RemotePartitioningManagerStepBuilderFactory stepBuilderFactory;
+
+ @Autowired
+ private LoanRepository loanRepository;
+ @Autowired
+ private COBPropertyService cobPropertyService;
+ @Autowired
+ private DirectChannel outboundRequests;
+
+ @Bean
+ public LoanCOBPartitioner partitioner() {
+ return new LoanCOBPartitioner(loanRepository, cobPropertyService);
+ }
+
+ @Bean
+ public Step loanCOBStep() {
+ return
stepBuilderFactory.get(JobName.LOAN_COB.name()).partitioner("Loan COB worker",
partitioner()).outputChannel(outboundRequests)
+ .build();
+ }
+
+ @Bean(name = "loanCOBJob")
+ public Job loanCOBJob() {
+ return
jobBuilderFactory.get(JobName.LOAN_COB.name()).start(loanCOBStep()).incrementer(new
RunIdIncrementer()).build();
+ }
+
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBPartitioner.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBPartitioner.java
new file mode 100644
index 000000000..49ed65d0b
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBPartitioner.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.cob.loan;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.COBPropertyService;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.partition.support.Partitioner;
+import org.springframework.batch.item.ExecutionContext;
+
+@RequiredArgsConstructor
+public class LoanCOBPartitioner implements Partitioner {
+
+ private final LoanRepository loanRepository;
+ private final COBPropertyService cobPropertyService;
+
+ private static final String PARTITION_PREFIX = "partition";
+ private static final String JOB_NAME = "LOAN_COB";
+
+ @Override
+ public Map<String, ExecutionContext> partition(int gridSize) {
+ int partitionCount = cobPropertyService.getPartitionSize(JOB_NAME);
+ Map<String, ExecutionContext> partitions = new HashMap<>();
+ for (int i = 0; i < partitionCount; i++) {
+ ExecutionContext executionContext = new ExecutionContext();
+ executionContext.put("loanIds", new ArrayList<Integer>());
+ partitions.put(PARTITION_PREFIX + i, executionContext);
+ }
+
+ List<Integer> allNonClosedLoanIds =
loanRepository.findAllNonClosedLoanIds();
+ for (int i = 0; i < allNonClosedLoanIds.size(); i++) {
+ String key = PARTITION_PREFIX + (i % partitionCount);
+ ExecutionContext executionContext = partitions.get(key);
+ List<Integer> data = (List<Integer>)
executionContext.get("loanIds");
+ data.add(allNonClosedLoanIds.get(i));
+ }
+ return partitions;
+ }
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java
new file mode 100644
index 000000000..18527eb63
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java
@@ -0,0 +1,94 @@
+/**
+ * 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.cob.loan;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.fineract.cob.COBPropertyService;
+import org.apache.fineract.infrastructure.jobs.service.JobName;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.Step;
+import
org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
+import org.springframework.batch.core.configuration.annotation.StepScope;
+import org.springframework.batch.core.launch.support.RunIdIncrementer;
+import
org.springframework.batch.integration.partition.RemotePartitioningWorkerStepBuilderFactory;
+import org.springframework.batch.item.ItemProcessor;
+import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.data.RepositoryItemWriter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.channel.QueueChannel;
+
+@Configuration
+@ConditionalOnProperty(value = "fineract.mode.batch-worker-enabled",
havingValue = "true")
+public class LoanCOBWorkerConfiguration {
+
+ @Autowired
+ private JobBuilderFactory jobBuilderFactory;
+ @Autowired
+ private RemotePartitioningWorkerStepBuilderFactory stepBuilderFactory;
+ @Autowired
+ private COBPropertyService cobPropertyService;
+ @Autowired
+ private LoanRepository loanRepository;
+ @Autowired
+ private QueueChannel inboundRequests;
+
+ @Bean(name = "Loan COB worker")
+ public Step loanCOBWorkerStep() {
+ return stepBuilderFactory.get("Loan COB
worker").inputChannel(inboundRequests)
+ .<Loan,
Loan>chunk(cobPropertyService.getChunkSize(JobName.LOAN_COB.name())).reader(itemReader(null))
+ .processor(itemProcessor()).writer(itemWriter()).build();
+ }
+
+ @Bean
+ public Job loanCOBWorkerJob() {
+ return jobBuilderFactory.get("Loan COB
worker").start(loanCOBWorkerStep()).incrementer(new RunIdIncrementer()).build();
+ }
+
+ @Bean
+ @StepScope
+ public ItemReader<Loan>
itemReader(@Value("#{stepExecutionContext['loanIds']}") List<Integer> data) {
+ List<Integer> remainingData = new ArrayList<>(data);
+ return () -> {
+ if (remainingData.size() > 0) {
+ return
loanRepository.findById(remainingData.remove(0).longValue()).orElse(null);
+ }
+ return null;
+ };
+ }
+
+ @Bean
+ public ItemProcessor<Loan, Loan> itemProcessor() {
+ return null;
+ }
+
+ @Bean
+ public RepositoryItemWriter<Loan> itemWriter() {
+ RepositoryItemWriter<Loan> writer = new RepositoryItemWriter<>();
+ writer.setRepository(loanRepository);
+ writer.setMethodName("save");
+ return writer;
+ }
+}
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 aff4865a9..13ed4e0ce 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
@@ -33,9 +33,11 @@ public class FineractModeValidationCondition implements
Condition {
.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);
- boolean isValidationFails = !isReadModeEnabled && !isWriteModeEnabled
&& !isBatchModeEnabled;
+ boolean isBatchManagerModeEnabled = Optional
+
.ofNullable(context.getEnvironment().getProperty("fineract.mode.batch-manager-enabled",
Boolean.class)).orElse(true);
+ boolean isBatchWorkerModeEnabled = Optional
+
.ofNullable(context.getEnvironment().getProperty("fineract.mode.batch-worker-enabled",
Boolean.class)).orElse(true);
+ boolean isValidationFails = !isReadModeEnabled && !isWriteModeEnabled
&& !isBatchManagerModeEnabled && !isBatchWorkerModeEnabled;
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");
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 e9ff3258e..e90d44dfa 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
@@ -39,6 +39,8 @@ public class FineractProperties {
private FineractPartitionedJob partitionedJob;
+ private FineractRemoteJobMessageHandlerProperties remoteJobMessageHandler;
+
@Getter
@Setter
public static class FineractTenantProperties {
@@ -93,4 +95,18 @@ public class FineractProperties {
private Integer partitionSize;
private Integer threadCount;
}
+
+ @Getter
+ @Setter
+ public static class FineractRemoteJobMessageHandlerProperties {
+
+ private FineractRemoteJobMessageHandlerSpringEventsProperties
springEvents;
+ }
+
+ @Getter
+ @Setter
+ public static class FineractRemoteJobMessageHandlerSpringEventsProperties {
+
+ private boolean enabled;
+ }
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractRemoteJobMessageHandlerCondition.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractRemoteJobMessageHandlerCondition.java
new file mode 100644
index 000000000..bf57190c0
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractRemoteJobMessageHandlerCondition.java
@@ -0,0 +1,51 @@
+/**
+ * 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.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 FineractRemoteJobMessageHandlerCondition implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata
metadata) {
+ boolean isSpringEventsEnabled = Optional
+ .ofNullable(
+
context.getEnvironment().getProperty("fineract.remote-job-message-handler.spring-events.enabled",
Boolean.class))
+ .orElse(true);
+ boolean isBatchManagerModeEnabled = Optional
+
.ofNullable(context.getEnvironment().getProperty("fineract.mode.batch-manager-enabled",
Boolean.class)).orElse(true);
+ boolean isBatchWorkerModeEnabled = Optional
+
.ofNullable(context.getEnvironment().getProperty("fineract.mode.batch-worker-enabled",
Boolean.class)).orElse(true);
+ // TODO extend this expression with other message handlers in the
future
+ boolean isMessageHandlerCountFails = !isSpringEventsEnabled;
+ boolean isSpringEventValidationFails = !(isSpringEventsEnabled &&
isBatchManagerModeEnabled && isBatchWorkerModeEnabled);
+ if (isMessageHandlerCountFails) {
+ log.error("For remote partitioning jobs exactly one Message
Handler must be enabled.");
+ }
+ if (isSpringEventValidationFails) {
+ log.error("If Spring Event Message Handler is enabled, the
instance must be Batch Manager and Batch Worker too.");
+ }
+ return isMessageHandlerCountFails || isSpringEventValidationFails;
+ }
+}
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
index f980ec092..6b8dd5eef 100644
---
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
@@ -32,4 +32,7 @@ public class FineractValidationCondition extends
AnyNestedCondition {
@Conditional(FineractPartitionJobConfigValidationCondition.class)
static class FineractPartitionedJobValidation {}
+
+ @Conditional(FineractRemoteJobMessageHandlerCondition.class)
+ static class FineractRemoteJobMessageHandlerValidation {}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java
index 58e719786..021bbafbe 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java
@@ -54,7 +54,8 @@ public enum JobName {
UPDATE_TRIAL_BALANCE_DETAILS("Update Trial Balance Details"), //
EXECUTE_DIRTY_JOBS("Execute All Dirty Jobs"), //
INCREASE_BUSINESS_DATE_BY_1_DAY("Increase Business Date by 1 day"), //
- INCREASE_COB_DATE_BY_1_DAY("Increase COB Date by 1 day");
+ INCREASE_COB_DATE_BY_1_DAY("Increase COB Date by 1 day"), //
+ LOAN_COB("Loan COB");
private final String name;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java
index fb9e1d8a1..779632ee4 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java
@@ -325,7 +325,7 @@ public class JobRegisterServiceImpl implements
JobRegisterService, ApplicationLi
jobDetailFactoryBean.setGroup(scheduledJobDetail.getGroupName());
jobDetailFactoryBean.setConcurrent(false);
- jobDetailFactoryBean.setArguments(job, scheduledJobDetail);
+ jobDetailFactoryBean.setArguments(job, scheduledJobDetail,
ThreadLocalContextUtil.getContext());
jobDetailFactoryBean.afterPropertiesSet();
return jobDetailFactoryBean.getObject();
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobSchedulerServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobSchedulerServiceImpl.java
index 74f13f37d..fa140e7d6 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobSchedulerServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobSchedulerServiceImpl.java
@@ -18,9 +18,13 @@
*/
package org.apache.fineract.infrastructure.jobs.service;
+import java.time.LocalDate;
+import java.util.HashMap;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import
org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
@@ -40,6 +44,7 @@ public class JobSchedulerServiceImpl implements
ApplicationListener<ContextRefre
private final SchedularWritePlatformService schedularWritePlatformService;
private final TenantDetailsService tenantDetailsService;
private final JobRegisterService jobRegisterService;
+ private final BusinessDateReadPlatformService
businessDateReadPlatformService;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
@@ -51,6 +56,8 @@ public class JobSchedulerServiceImpl implements
ApplicationListener<ContextRefre
final List<FineractPlatformTenant> allTenants =
tenantDetailsService.findAllTenants();
for (final FineractPlatformTenant tenant : allTenants) {
ThreadLocalContextUtil.setTenant(tenant);
+ HashMap<BusinessDateType, LocalDate> businessDates =
businessDateReadPlatformService.getBusinessDates();
+ ThreadLocalContextUtil.setBusinessDates(businessDates);
final List<ScheduledJobDetail> scheduledJobDetails =
schedularWritePlatformService
.retrieveAllJobs(fineractProperties.getNodeId());
for (final ScheduledJobDetail jobDetails : scheduledJobDetails) {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobStarter.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobStarter.java
index 556e6b4b0..9e72cd54b 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobStarter.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobStarter.java
@@ -22,6 +22,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.jobs.domain.JobParameterRepository;
import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
import org.springframework.batch.core.Job;
@@ -44,8 +46,10 @@ public class JobStarter {
private final JobLauncher jobLauncher;
private final JobParameterRepository jobParameterRepository;
- public void run(Job job, ScheduledJobDetail scheduledJobDetail) throws
JobInstanceAlreadyCompleteException,
- JobExecutionAlreadyRunningException,
JobParametersInvalidException, JobRestartException {
+ public void run(Job job, ScheduledJobDetail scheduledJobDetail,
FineractContext fineractContext)
+ throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException, JobParametersInvalidException,
+ JobRestartException {
+ ThreadLocalContextUtil.init(fineractContext);
Map<String, JobParameter> jobParameterMap =
getJobParameter(scheduledJobDetail);
JobParameters jobParameters = new
JobParametersBuilder(jobExplorer).getNextJobParameters(job)
.addJobParameters(new
JobParameters(jobParameterMap)).toJobParameters();
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobRunnerReadServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobRunnerReadServiceImpl.java
index c778f5914..b915521a5 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobRunnerReadServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobRunnerReadServiceImpl.java
@@ -22,6 +22,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
+import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
@@ -39,6 +40,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
+@Slf4j
@Transactional(readOnly = true)
public class SchedulerJobRunnerReadServiceImpl implements
SchedulerJobRunnerReadService {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
index 3ec053973..f75996e70 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
@@ -69,6 +69,8 @@ public interface LoanRepository extends JpaRepository<Loan,
Long>, JpaSpecificat
String FIND_NON_CLOSED_BY_ACCOUNT_NUMBER = "select loan from Loan loan
where loan.accountNumber = :accountNumber and loan.loanStatus in
(100,200,300,303,304)";
+ String FIND_ALL_NON_CLOSED = "select loan.id from Loan loan where
loan.loanStatus in (100,200,300,303,304)";
+
String FIND_NON_CLOSED_LOAN_THAT_BELONGS_TO_CLIENT = "select loan from
Loan loan where loan.id = :loanId and loan.loanStatus = 300 and loan.client.id
= :clientId";
String FIND_BY_ACCOUNT_NUMBER = "select loan from Loan loan where
loan.accountNumber = :accountNumber";
@@ -163,4 +165,7 @@ public interface LoanRepository extends JpaRepository<Loan,
Long>, JpaSpecificat
boolean existsByExternalId(@Param("externalId") String externalId);
+ @Query(FIND_ALL_NON_CLOSED)
+ List<Integer> findAllNonClosedLoanIds();
+
}
diff --git a/fineract-provider/src/main/resources/application.properties
b/fineract-provider/src/main/resources/application.properties
index 89bf99423..f2b4db126 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -48,6 +48,8 @@
fineract.partitioned-job.partitioned-job-properties[0].chunk-size=${LOAN_COB_CHU
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}
+fineract.remote-job-message-handler.spring-events.enabled=${FINERACT_REMOTE_JOB_MESSAGE_HANDLER_SPRING_EVENTS_ENABLED:true}
+
# 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/main/resources/db/changelog/tenant/changelog-tenant.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index 65cf79c76..501a7aafc 100644
---
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -56,4 +56,5 @@
<include file="parts/0034_add_audit_entries_to_note.xml"
relativeToChangelogFile="true"/>
<include file="parts/0035_add_audit_entries_to_calendar.xml"
relativeToChangelogFile="true"/>
<include
file="parts/0036_add_audit_entries_and_rework_command_source_datetime_fields.xml"
relativeToChangelogFile="true"/>
+ <include file="parts/0037_add_loan_cob_job_data.xml"
relativeToChangelogFile="true"/>
</databaseChangeLog>
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0037_add_loan_cob_job_data.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0037_add_loan_cob_job_data.xml
new file mode 100644
index 000000000..0b25642bb
--- /dev/null
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0037_add_loan_cob_job_data.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
+ <changeSet id="1" author="fineract">
+ <insert tableName="job">
+ <column name="name" value="Loan COB"/>
+ <column name="display_name" value="Loan COB"/>
+ <column name="cron_expression" value="0 0 0 * * ?"/>
+ <column name="create_time" valueDate="${current_datetime}"/>
+ <column name="task_priority" valueNumeric="5"/>
+ <column name="group_name"/>
+ <column name="previous_run_start_time"/>
+ <column name="job_key" value="Loan COB dayJobDetail1 _ DEFAULT"/>
+ <column name="initializing_errorlog"/>
+ <column name="is_active" valueBoolean="false"/>
+ <column name="currently_running" valueBoolean="false"/>
+ <column name="updates_allowed" valueBoolean="true"/>
+ <column name="scheduler_group" valueNumeric="0"/>
+ <column name="is_misfired" valueBoolean="false"/>
+ <column name="node_id" valueNumeric="1"/>
+ <column name="is_mismatched_job" valueBoolean="false"/>
+ </insert>
+ </changeSet>
+</databaseChangeLog>