[FINERACT-1678] Inline COB API
This commit is contained in:
committed by
Arnold Gálovics
parent
22bcccb17b
commit
ebe87433e7
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LoanIdsResponseDTO {
|
||||
|
||||
private List<Long> loanIds;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.exceptions;
|
||||
|
||||
public class LoanAccountLockCannotBeOverruledException extends RuntimeException {
|
||||
|
||||
public LoanAccountLockCannotBeOverruledException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -44,7 +44,7 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class LoanItemListener {
|
||||
public abstract class AbstractLoanItemListener {
|
||||
|
||||
private final LoanAccountLockRepository accountLockRepository;
|
||||
|
||||
@@ -57,8 +57,7 @@ public class LoanItemListener {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(@NotNull TransactionStatus status) {
|
||||
for (Long loanId : loanIds) {
|
||||
Optional<LoanAccountLock> loanAccountLock = accountLockRepository.findByLoanIdAndLockOwner(loanId,
|
||||
LockOwner.LOAN_COB_CHUNK_PROCESSING);
|
||||
Optional<LoanAccountLock> loanAccountLock = accountLockRepository.findByLoanIdAndLockOwner(loanId, getLockOwner());
|
||||
loanAccountLock.ifPresent(
|
||||
accountLock -> accountLock.setError(String.format(msg, loanId), ThrowableSerialization.serialize(e)));
|
||||
}
|
||||
@@ -101,4 +100,7 @@ public class LoanItemListener {
|
||||
public void onSkipInWrite(@NotNull Loan item, @NotNull Exception e) {
|
||||
log.warn("Skipping was triggered during writing of Loan (id={})", item.getId());
|
||||
}
|
||||
|
||||
protected abstract LockOwner getLockOwner();
|
||||
|
||||
}
|
||||
+35
@@ -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.cob.listener;
|
||||
|
||||
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.cob.domain.LockOwner;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
public class ChunkProcessingLoanItemListener extends AbstractLoanItemListener {
|
||||
|
||||
public ChunkProcessingLoanItemListener(LoanAccountLockRepository accountLockRepository, TransactionTemplate transactionTemplate) {
|
||||
super(accountLockRepository, transactionTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LockOwner getLockOwner() {
|
||||
return LockOwner.LOAN_COB_CHUNK_PROCESSING;
|
||||
}
|
||||
}
|
||||
+35
@@ -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.cob.listener;
|
||||
|
||||
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.cob.domain.LockOwner;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
public class InlineCOBLoanItemListener extends AbstractLoanItemListener {
|
||||
|
||||
public InlineCOBLoanItemListener(LoanAccountLockRepository accountLockRepository, TransactionTemplate transactionTemplate) {
|
||||
super(accountLockRepository, transactionTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LockOwner getLockOwner() {
|
||||
return LockOwner.LOAN_INLINE_COB_PROCESSING;
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.TreeMap;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.AfterStep;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public abstract class AbstractLoanItemProcessor implements ItemProcessor<Loan, Loan> {
|
||||
|
||||
private final COBBusinessStepService cobBusinessStepService;
|
||||
|
||||
@Setter(AccessLevel.PROTECTED)
|
||||
private ExecutionContext executionContext;
|
||||
|
||||
@Override
|
||||
public Loan process(@NotNull Loan item) throws Exception {
|
||||
TreeMap<Long, String> businessStepMap = (TreeMap<Long, String>) executionContext.get(LoanCOBConstant.BUSINESS_STEP_MAP);
|
||||
|
||||
return cobBusinessStepService.run(businessStepMap, item);
|
||||
}
|
||||
|
||||
@AfterStep
|
||||
public ExitStatus afterStep(@NotNull StepExecution stepExecution) {
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.exceptions.LoanAccountWasAlreadyLocked;
|
||||
import org.apache.fineract.cob.exceptions.LoanReadException;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.AfterStep;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public abstract class AbstractLoanItemReader implements ItemReader<Loan> {
|
||||
|
||||
private final LoanRepository loanRepository;
|
||||
|
||||
@Setter(AccessLevel.PROTECTED)
|
||||
private List<Long> alreadyLockedAccounts;
|
||||
@Setter(AccessLevel.PROTECTED)
|
||||
private List<Long> remainingData;
|
||||
private Long loanId;
|
||||
|
||||
@Override
|
||||
public Loan read() throws Exception {
|
||||
try {
|
||||
if (remainingData.size() > 0) {
|
||||
loanId = remainingData.remove(0);
|
||||
if (alreadyLockedAccounts != null && alreadyLockedAccounts.remove(loanId)) {
|
||||
throw new LoanAccountWasAlreadyLocked(loanId);
|
||||
}
|
||||
return loanRepository.findById(loanId).orElseThrow(() -> new LoanNotFoundException(loanId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new LoanReadException(loanId, e);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@AfterStep
|
||||
public ExitStatus afterStep(@NotNull StepExecution stepExecution) {
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.cob.domain.LockOwner;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.batch.item.data.RepositoryItemWriter;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public abstract class AbstractLoanItemWriter extends RepositoryItemWriter<Loan> {
|
||||
|
||||
private final LoanAccountLockRepository accountLockRepository;
|
||||
|
||||
@Override
|
||||
public void write(@NotNull List<? extends Loan> items) throws Exception {
|
||||
super.write(items);
|
||||
List<Long> loanIds = items.stream().map(AbstractPersistableCustom::getId).toList();
|
||||
accountLockRepository.deleteByLoanIdInAndLockOwner(loanIds, getLockOwner());
|
||||
}
|
||||
|
||||
protected abstract LockOwner getLockOwner();
|
||||
|
||||
}
|
||||
+35
@@ -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.cob.loan;
|
||||
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.BeforeStep;
|
||||
|
||||
public class InlineCOBLoanItemProcessor extends AbstractLoanItemProcessor {
|
||||
|
||||
public InlineCOBLoanItemProcessor(COBBusinessStepService cobBusinessStepService) {
|
||||
super(cobBusinessStepService);
|
||||
}
|
||||
|
||||
@BeforeStep
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
setExecutionContext(stepExecution.getJobExecution().getExecutionContext());
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.BeforeStep;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
|
||||
public class InlineCOBLoanItemReader extends AbstractLoanItemReader {
|
||||
|
||||
public InlineCOBLoanItemReader(LoanRepository loanRepository) {
|
||||
super(loanRepository);
|
||||
}
|
||||
|
||||
@BeforeStep
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public void beforeStep(@NotNull StepExecution stepExecution) {
|
||||
ExecutionContext executionContext = stepExecution.getJobExecution().getExecutionContext();
|
||||
List<Long> loanIds = (List<Long>) executionContext.get(LoanCOBConstant.LOAN_IDS);
|
||||
setRemainingData(new ArrayList<>(loanIds));
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.cob.domain.LockOwner;
|
||||
|
||||
public class InlineCOBLoanItemWriter extends AbstractLoanItemWriter {
|
||||
|
||||
public InlineCOBLoanItemWriter(LoanAccountLockRepository accountLockRepository) {
|
||||
super(accountLockRepository);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LockOwner getLockOwner() {
|
||||
return LockOwner.LOAN_INLINE_COB_PROCESSING;
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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 com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
|
||||
import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameter;
|
||||
import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameterRepository;
|
||||
import org.apache.fineract.infrastructure.springbatch.SpringBatchJobConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class InlineLoanCOBBuildExecutionContextTasklet implements Tasklet, InitializingBean {
|
||||
|
||||
private final GoogleGsonSerializerHelper gsonFactory;
|
||||
private final COBBusinessStepService cobBusinessStepService;
|
||||
private final CustomJobParameterRepository customJobParameterRepository;
|
||||
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.gson = gsonFactory.createSimpleGson();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
TreeMap<Long, String> cobBusinessStepMap = cobBusinessStepService.getCOBBusinessStepMap(LoanCOBBusinessStep.class,
|
||||
LoanCOBConstant.LOAN_COB_JOB_NAME);
|
||||
contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, getLoanIdsFromJobParameters(chunkContext));
|
||||
contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_STEP_MAP, cobBusinessStepMap);
|
||||
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
private List<Long> getLoanIdsFromJobParameters(ChunkContext chunkContext) {
|
||||
Long customJobParameterId = (Long) chunkContext.getStepContext().getJobParameters()
|
||||
.get(SpringBatchJobConstants.CUSTOM_JOB_PARAMETER_ID_KEY);
|
||||
CustomJobParameter customJobParameter = customJobParameterRepository.findById(customJobParameterId)
|
||||
.orElseThrow(() -> new LoanNotFoundException(customJobParameterId));
|
||||
String parameterJson = customJobParameter.getParameterJson();
|
||||
return gson.fromJson(parameterJson, new TypeToken<ArrayList<Long>>() {}.getType());
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ public final class LoanCOBConstant {
|
||||
public static final String LOAN_COB_WORKER_STEP = "loanCOBWorkerStep";
|
||||
|
||||
public static final String ALREADY_LOCKED_LOAN_IDS = "alreadyLockedLoanIds";
|
||||
public static final String INLINE_LOAN_COB_JOB_NAME = "INLINE_LOAN_COB";
|
||||
|
||||
private LoanCOBConstant() {
|
||||
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@ package org.apache.fineract.cob.loan;
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.apache.fineract.cob.common.InitialisationTasklet;
|
||||
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.cob.listener.LoanItemListener;
|
||||
import org.apache.fineract.cob.listener.ChunkProcessingLoanItemListener;
|
||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.infrastructure.springbatch.PropertyService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
@@ -105,8 +105,8 @@ public class LoanCOBWorkerConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LoanItemListener loanItemListener() {
|
||||
return new LoanItemListener(accountLockRepository, transactionTemplate);
|
||||
public ChunkProcessingLoanItemListener loanItemListener() {
|
||||
return new ChunkProcessingLoanItemListener(accountLockRepository, transactionTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* 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.COBBusinessStepService;
|
||||
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.cob.listener.InlineCOBLoanItemListener;
|
||||
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
|
||||
import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameterRepository;
|
||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.infrastructure.springbatch.PropertyService;
|
||||
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.StepBuilderFactory;
|
||||
import org.springframework.batch.core.launch.support.RunIdIncrementer;
|
||||
import org.springframework.batch.core.listener.ExecutionContextPromotionListener;
|
||||
import org.springframework.batch.integration.config.annotation.EnableBatchIntegration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
@Configuration
|
||||
@EnableBatchIntegration
|
||||
public class LoanInlineCOBConfig {
|
||||
|
||||
@Autowired
|
||||
private JobBuilderFactory jobBuilderFactory;
|
||||
@Autowired
|
||||
private StepBuilderFactory stepBuilderFactory;
|
||||
@Autowired
|
||||
private PropertyService propertyService;
|
||||
@Autowired
|
||||
private LoanRepository loanRepository;
|
||||
@Autowired
|
||||
private COBBusinessStepService cobBusinessStepService;
|
||||
@Autowired
|
||||
private LoanAccountLockRepository accountLockRepository;
|
||||
@Autowired
|
||||
private TransactionTemplate transactionTemplate;
|
||||
@Autowired
|
||||
private CustomJobParameterRepository loanIdListRepository;
|
||||
@Autowired
|
||||
private GoogleGsonSerializerHelper googleGsonSerializerHelper;
|
||||
|
||||
@Bean
|
||||
public InlineLoanCOBBuildExecutionContextTasklet inlineLoanCOBBuildExecutionContextTasklet() {
|
||||
return new InlineLoanCOBBuildExecutionContextTasklet(googleGsonSerializerHelper, cobBusinessStepService, loanIdListRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected Step inlineCOBBuildExecutionContextStep() {
|
||||
return stepBuilderFactory.get("Inline COB build execution context step").tasklet(inlineLoanCOBBuildExecutionContextTasklet())
|
||||
.listener(inlineCobPromotionListener()).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step inlineLoanCOBStep() {
|
||||
return stepBuilderFactory.get("Inline Loan COB Step").<Loan, Loan>chunk(propertyService.getChunkSize(JobName.LOAN_COB.name()))
|
||||
.reader(inlineCobWorkerItemReader()).processor(inlineCobWorkerItemProcessor()).writer(inlineCobWorkerItemWriter())
|
||||
.listener(inlineCobLoanItemListener()).build();
|
||||
}
|
||||
|
||||
@Bean(name = "loanInlineCOBJob")
|
||||
public Job loanInlineCOBJob() {
|
||||
return jobBuilderFactory.get(LoanCOBConstant.INLINE_LOAN_COB_JOB_NAME) //
|
||||
.start(inlineCOBBuildExecutionContextStep()).next(inlineLoanCOBStep()) //
|
||||
.incrementer(new RunIdIncrementer()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InlineCOBLoanItemReader inlineCobWorkerItemReader() {
|
||||
return new InlineCOBLoanItemReader(loanRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InlineCOBLoanItemProcessor inlineCobWorkerItemProcessor() {
|
||||
return new InlineCOBLoanItemProcessor(cobBusinessStepService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InlineCOBLoanItemWriter inlineCobWorkerItemWriter() {
|
||||
InlineCOBLoanItemWriter repositoryItemWriter = new InlineCOBLoanItemWriter(accountLockRepository);
|
||||
repositoryItemWriter.setRepository(loanRepository);
|
||||
return repositoryItemWriter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InlineCOBLoanItemListener inlineCobLoanItemListener() {
|
||||
return new InlineCOBLoanItemListener(accountLockRepository, transactionTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ExecutionContextPromotionListener inlineCobPromotionListener() {
|
||||
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
|
||||
listener.setKeys(new String[] { LoanCOBConstant.LOAN_IDS, LoanCOBConstant.BUSINESS_STEP_MAP });
|
||||
return listener;
|
||||
}
|
||||
}
|
||||
+6
-30
@@ -18,42 +18,18 @@
|
||||
*/
|
||||
package org.apache.fineract.cob.loan;
|
||||
|
||||
import java.util.TreeMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.AfterStep;
|
||||
import org.springframework.batch.core.annotation.BeforeStep;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class LoanItemProcessor implements ItemProcessor<Loan, Loan> {
|
||||
public class LoanItemProcessor extends AbstractLoanItemProcessor {
|
||||
|
||||
private final COBBusinessStepService cobBusinessStepService;
|
||||
private StepExecution stepExecution;
|
||||
public LoanItemProcessor(COBBusinessStepService cobBusinessStepService) {
|
||||
super(cobBusinessStepService);
|
||||
}
|
||||
|
||||
@BeforeStep
|
||||
public void beforeStep(@NotNull StepExecution stepExecution) {
|
||||
this.stepExecution = stepExecution;
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
setExecutionContext(stepExecution.getExecutionContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loan process(@NotNull Loan item) throws Exception {
|
||||
ExecutionContext executionContext = stepExecution.getExecutionContext();
|
||||
TreeMap<Long, String> businessStepMap = (TreeMap<Long, String>) executionContext.get(LoanCOBConstant.BUSINESS_STEP_MAP);
|
||||
|
||||
return cobBusinessStepService.run(businessStepMap, item);
|
||||
}
|
||||
|
||||
@AfterStep
|
||||
public ExitStatus afterStep(@NotNull StepExecution stepExecution) {
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,59 +20,26 @@ package org.apache.fineract.cob.loan;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.exceptions.LoanAccountWasAlreadyLocked;
|
||||
import org.apache.fineract.cob.exceptions.LoanReadException;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.AfterStep;
|
||||
import org.springframework.batch.core.annotation.BeforeStep;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class LoanItemReader implements ItemReader<Loan> {
|
||||
public class LoanItemReader extends AbstractLoanItemReader {
|
||||
|
||||
private final LoanRepository loanRepository;
|
||||
private List<Long> alreadyLockedAccounts;
|
||||
private List<Long> remainingData;
|
||||
private Long loanId;
|
||||
public LoanItemReader(LoanRepository loanRepository) {
|
||||
super(loanRepository);
|
||||
}
|
||||
|
||||
@BeforeStep
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public void beforeStep(@NotNull StepExecution stepExecution) {
|
||||
|
||||
ExecutionContext executionContext = stepExecution.getExecutionContext();
|
||||
ExecutionContext jobExecutionContext = stepExecution.getJobExecution().getExecutionContext();
|
||||
List<Long> loanIds = (List<Long>) executionContext.get(LoanCOBConstant.LOAN_IDS);
|
||||
alreadyLockedAccounts = (List<Long>) jobExecutionContext.get(LoanCOBConstant.ALREADY_LOCKED_LOAN_IDS);
|
||||
remainingData = new ArrayList<>(loanIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loan read() throws Exception {
|
||||
try {
|
||||
if (remainingData.size() > 0) {
|
||||
loanId = remainingData.remove(0);
|
||||
if (alreadyLockedAccounts != null && alreadyLockedAccounts.remove(loanId)) {
|
||||
throw new LoanAccountWasAlreadyLocked(loanId);
|
||||
}
|
||||
|
||||
return loanRepository.findById(loanId).orElseThrow(() -> new LoanNotFoundException(loanId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new LoanReadException(loanId, e);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@AfterStep
|
||||
public ExitStatus afterStep(@NotNull StepExecution stepExecution) {
|
||||
return ExitStatus.COMPLETED;
|
||||
setAlreadyLockedAccounts((List<Long>) jobExecutionContext.get(LoanCOBConstant.ALREADY_LOCKED_LOAN_IDS));
|
||||
setRemainingData(new ArrayList<>(loanIds));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,28 +18,17 @@
|
||||
*/
|
||||
package org.apache.fineract.cob.loan;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.cob.domain.LockOwner;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.batch.item.data.RepositoryItemWriter;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class LoanItemWriter extends RepositoryItemWriter<Loan> {
|
||||
public class LoanItemWriter extends AbstractLoanItemWriter {
|
||||
|
||||
private final LoanAccountLockRepository accountLockRepository;
|
||||
|
||||
@Override
|
||||
public void write(@NotNull List<? extends Loan> items) throws Exception {
|
||||
super.write(items);
|
||||
List<Long> loanIds = items.stream().map(AbstractPersistableCustom::getId).toList();
|
||||
|
||||
accountLockRepository.deleteByLoanIdInAndLockOwner(loanIds, LockOwner.LOAN_COB_CHUNK_PROCESSING);
|
||||
public LoanItemWriter(LoanAccountLockRepository accountLockRepository) {
|
||||
super(accountLockRepository);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LockOwner getLockOwner() {
|
||||
return LockOwner.LOAN_COB_CHUNK_PROCESSING;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-8
@@ -18,8 +18,6 @@
|
||||
*/
|
||||
package org.apache.fineract.cob.service;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.cob.exceptions.BusinessStepException;
|
||||
import org.apache.fineract.cob.exceptions.BusinessStepNotBelongsToJobException;
|
||||
@@ -40,11 +38,6 @@ public class BusinessStepConfigUpdateHandler implements NewCommandSourceHandler
|
||||
@Override
|
||||
@Transactional
|
||||
public CommandProcessingResult processCommand(JsonCommand command) throws BusinessStepNotBelongsToJobException, BusinessStepException {
|
||||
List<String> split = Splitter.on("/").splitToList(command.getUrl());
|
||||
String jobName = split.get(split.size() - 2);
|
||||
if ("null".equals(jobName)) {
|
||||
jobName = null;
|
||||
}
|
||||
return configJobParameterService.updateStepConfigByJobName(command, jobName);
|
||||
return configJobParameterService.updateStepConfigByJobName(command, command.getJobName());
|
||||
}
|
||||
}
|
||||
|
||||
+53
@@ -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.service;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class InlineLoanCOBExecutionDataParser {
|
||||
|
||||
private final FromJsonHelper jsonHelper;
|
||||
|
||||
public List<Long> parseExecution(JsonCommand command) {
|
||||
JsonObject element = extractJsonObject(command);
|
||||
String[] loanArray = jsonHelper.extractArrayNamed("loanIds", element);
|
||||
return Arrays.stream(loanArray).map(Long::parseLong).toList();
|
||||
}
|
||||
|
||||
private JsonObject extractJsonObject(JsonCommand command) {
|
||||
String json = command.json();
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final JsonElement element = jsonHelper.parse(json);
|
||||
return element.getAsJsonObject();
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import static org.springframework.transaction.TransactionDefinition.PROPAGATION_REQUIRES_NEW;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.cob.domain.LoanAccountLock;
|
||||
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.cob.domain.LockOwner;
|
||||
import org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformInternalServerException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
|
||||
import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameter;
|
||||
import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameterRepository;
|
||||
import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
|
||||
import org.apache.fineract.infrastructure.jobs.service.InlineExecutorService;
|
||||
import org.apache.fineract.infrastructure.springbatch.SpringBatchJobConstants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameter;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.configuration.JobLocator;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService, InitializingBean {
|
||||
|
||||
private static final String JOB_EXECUTION_FAILED_MESSAGE = "Job execution failed for job with name: ";
|
||||
|
||||
private final GoogleGsonSerializerHelper gsonFactory;
|
||||
private final LoanAccountLockRepository loanAccountLockRepository;
|
||||
private final InlineLoanCOBExecutionDataParser dataParser;
|
||||
private final JobLauncher jobLauncher;
|
||||
private final JobLocator jobLocator;
|
||||
private final JobExplorer jobExplorer;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
private final CustomJobParameterRepository customJobParameterRepository;
|
||||
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.gson = gsonFactory.createSimpleGson();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public CommandProcessingResult executeInlineJob(JsonCommand command, String jobName) throws LoanAccountLockCannotBeOverruledException {
|
||||
List<Long> loanIds = dataParser.parseExecution(command);
|
||||
lockLoanAccounts(loanIds);
|
||||
execute(loanIds, jobName);
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).build();
|
||||
}
|
||||
|
||||
private List<LoanAccountLock> getLoanAccountLocks(List<Long> loanIds) {
|
||||
List<LoanAccountLock> loanAccountLocks = new ArrayList<>();
|
||||
List<Long> alreadyLockedLoanIds = new ArrayList<>();
|
||||
loanIds.forEach(loanId -> {
|
||||
Optional<LoanAccountLock> loanLockOptional = loanAccountLockRepository.findById(loanId);
|
||||
if (loanLockOptional.isPresent()) {
|
||||
LoanAccountLock loanAccountLock = loanLockOptional.get();
|
||||
if (isLockOverrulable(loanAccountLock)) {
|
||||
loanAccountLocks.add(loanAccountLock);
|
||||
} else {
|
||||
alreadyLockedLoanIds.add(loanId);
|
||||
}
|
||||
} else {
|
||||
loanAccountLocks.add(new LoanAccountLock(loanId, LockOwner.LOAN_INLINE_COB_PROCESSING));
|
||||
}
|
||||
});
|
||||
if (!alreadyLockedLoanIds.isEmpty()) {
|
||||
String message = "There is a hard lock on the loan account without any error, so it can't be overruled.";
|
||||
String loanIdsMessage = " Locked loan IDs: " + alreadyLockedLoanIds;
|
||||
throw new LoanAccountLockCannotBeOverruledException(message + loanIdsMessage);
|
||||
}
|
||||
|
||||
return loanAccountLocks;
|
||||
}
|
||||
|
||||
private void execute(List<Long> loanIds, String jobName) {
|
||||
Job inlineLoanCOBJob;
|
||||
try {
|
||||
inlineLoanCOBJob = jobLocator.getJob(jobName);
|
||||
} catch (NoSuchJobException e) {
|
||||
throw new JobNotFoundException(jobName, e);
|
||||
}
|
||||
JobParameters jobParameters = new JobParametersBuilder(jobExplorer).getNextJobParameters(inlineLoanCOBJob)
|
||||
.addJobParameters(new JobParameters(getJobParametersMap(loanIds))).toJobParameters();
|
||||
JobExecution jobExecution;
|
||||
try {
|
||||
jobExecution = jobLauncher.run(inlineLoanCOBJob, jobParameters);
|
||||
} catch (Exception e) {
|
||||
log.error("{}{}", JOB_EXECUTION_FAILED_MESSAGE, jobName, e);
|
||||
throw new PlatformInternalServerException("error.msg.sheduler.job.execution.failed", JOB_EXECUTION_FAILED_MESSAGE, jobName, e);
|
||||
}
|
||||
if (!BatchStatus.COMPLETED.equals(jobExecution.getStatus())) {
|
||||
log.error("{}{}", JOB_EXECUTION_FAILED_MESSAGE, jobName);
|
||||
throw new PlatformInternalServerException("error.msg.sheduler.job.execution.failed", JOB_EXECUTION_FAILED_MESSAGE, jobName);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, JobParameter> getJobParametersMap(List<Long> loanIds) {
|
||||
// TODO: refactor for a more generic solution
|
||||
String parameterJson = gson.toJson(loanIds);
|
||||
CustomJobParameter customJobParameter = new CustomJobParameter();
|
||||
customJobParameter.setParameterJson(parameterJson);
|
||||
Long customJobParameterId = customJobParameterRepository.saveAndFlush(customJobParameter).getId();
|
||||
Map<String, JobParameter> jobParameterMap = new HashMap<>();
|
||||
jobParameterMap.put(SpringBatchJobConstants.CUSTOM_JOB_PARAMETER_ID_KEY, new JobParameter(customJobParameterId));
|
||||
return jobParameterMap;
|
||||
}
|
||||
|
||||
private void lockLoanAccounts(List<Long> loanIds) {
|
||||
transactionTemplate.setPropagationBehavior(PROPAGATION_REQUIRES_NEW);
|
||||
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(@NotNull TransactionStatus status) {
|
||||
List<LoanAccountLock> loanAccountLocks = getLoanAccountLocks(loanIds);
|
||||
loanAccountLocks.forEach(loanAccountLock -> {
|
||||
loanAccountLock.setNewLockOwner(LockOwner.LOAN_INLINE_COB_PROCESSING);
|
||||
loanAccountLockRepository.save(loanAccountLock);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isLockOverrulable(LoanAccountLock loanAccountLock) {
|
||||
if (LockOwner.LOAN_COB_PARTITIONING.equals(loanAccountLock.getLockOwner())) {
|
||||
return true;
|
||||
} else {
|
||||
return StringUtils.isNotBlank(loanAccountLock.getError());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,6 +104,9 @@ public class CommandSource extends AbstractPersistableCustom {
|
||||
@Column(name = "organisation_creditbureau_id")
|
||||
private Long organisationCreditBureauId;
|
||||
|
||||
@Column(name = "job_name")
|
||||
private String jobName;
|
||||
|
||||
public static CommandSource fullEntryFrom(final CommandWrapper wrapper, final JsonCommand command, final AppUser maker) {
|
||||
return new CommandSource(wrapper.actionName(), wrapper.entityName(), wrapper.getHref(), command.entityId(), command.subentityId(),
|
||||
command.json(), maker);
|
||||
@@ -138,6 +141,10 @@ public class CommandSource extends AbstractPersistableCustom {
|
||||
return this.organisationCreditBureauId;
|
||||
}
|
||||
|
||||
public String getJobName() {
|
||||
return this.jobName;
|
||||
}
|
||||
|
||||
public void setOrganisationCreditBureauId(Long organisationCreditBureauId) {
|
||||
this.organisationCreditBureauId = organisationCreditBureauId;
|
||||
}
|
||||
|
||||
+9
-1
@@ -40,6 +40,7 @@ public class CommandWrapper {
|
||||
private final Long productId;
|
||||
private final Long creditBureauId;
|
||||
private final Long organisationCreditBureauId;
|
||||
private final String jobName;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Long templateId;
|
||||
@@ -80,12 +81,13 @@ public class CommandWrapper {
|
||||
this.productId = productId;
|
||||
this.creditBureauId = null;
|
||||
this.organisationCreditBureauId = null;
|
||||
this.jobName = null;
|
||||
}
|
||||
|
||||
public CommandWrapper(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savingsId,
|
||||
final String actionName, final String entityName, final Long entityId, final Long subentityId, final String href,
|
||||
final String json, final String transactionId, final Long productId, final Long templateId, final Long creditBureauId,
|
||||
final Long organisationCreditBureauId) {
|
||||
final Long organisationCreditBureauId, final String jobName) {
|
||||
|
||||
this.commandId = null;
|
||||
this.officeId = officeId;
|
||||
@@ -105,6 +107,7 @@ public class CommandWrapper {
|
||||
this.templateId = templateId;
|
||||
this.creditBureauId = creditBureauId;
|
||||
this.organisationCreditBureauId = organisationCreditBureauId;
|
||||
this.jobName = jobName;
|
||||
}
|
||||
|
||||
private CommandWrapper(final Long commandId, final String actionName, final String entityName, final Long resourceId,
|
||||
@@ -129,6 +132,7 @@ public class CommandWrapper {
|
||||
this.productId = productId;
|
||||
this.creditBureauId = creditBureauId;
|
||||
this.organisationCreditBureauId = organisationCreditBureauId;
|
||||
this.jobName = null;
|
||||
}
|
||||
|
||||
public Long getCreditBureauId() {
|
||||
@@ -338,4 +342,8 @@ public class CommandWrapper {
|
||||
return this.actionName.equalsIgnoreCase("UPDATE") && this.entityName.equalsIgnoreCase("DISBURSEMENTDETAIL")
|
||||
&& this.entityId == null;
|
||||
}
|
||||
|
||||
public String getJobName() {
|
||||
return jobName;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -44,11 +44,12 @@ public class CommandWrapperBuilder {
|
||||
private Long templateId;
|
||||
private Long creditBureauId;
|
||||
private Long organisationCreditBureauId;
|
||||
private String jobName;
|
||||
|
||||
public CommandWrapper build() {
|
||||
return new CommandWrapper(this.officeId, this.groupId, this.clientId, this.loanId, this.savingsId, this.actionName, this.entityName,
|
||||
this.entityId, this.subentityId, this.href, this.json, this.transactionId, this.productId, this.templateId,
|
||||
this.creditBureauId, this.organisationCreditBureauId);
|
||||
this.creditBureauId, this.organisationCreditBureauId, this.jobName);
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateCreditBureau() {
|
||||
@@ -3562,7 +3563,15 @@ public class CommandWrapperBuilder {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "BATCH_BUSINESS_STEP";
|
||||
this.href = "/jobs/" + jobName + "/steps";
|
||||
this.jobName = jobName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder executeInlineJob(String jobName) {
|
||||
this.actionName = "EXECUTE";
|
||||
this.entityName = "INLINE_JOB";
|
||||
this.href = "/jobs/" + jobName + "/inline";
|
||||
this.jobName = jobName;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
command = JsonCommand.from(json, parsedCommand, this.fromApiJsonHelper, wrapper.getEntityName(), wrapper.getEntityId(),
|
||||
wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(), wrapper.getSavingsId(),
|
||||
wrapper.getTransactionId(), wrapper.getHref(), wrapper.getProductId(), wrapper.getCreditBureauId(),
|
||||
wrapper.getOrganisationCreditBureauId());
|
||||
wrapper.getOrganisationCreditBureauId(), wrapper.getJobName());
|
||||
while (numberOfRetries <= maxNumberOfRetries) {
|
||||
try {
|
||||
result = this.processAndLogCommandService.executeCommand(wrapper, command, isApprovedByChecker);
|
||||
@@ -137,7 +137,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
commandSourceInput.subresourceId(), commandSourceInput.getGroupId(), commandSourceInput.getClientId(),
|
||||
commandSourceInput.getLoanId(), commandSourceInput.getSavingsId(), commandSourceInput.getTransactionId(),
|
||||
commandSourceInput.getResourceGetUrl(), commandSourceInput.getProductId(), commandSourceInput.getCreditBureauId(),
|
||||
commandSourceInput.getOrganisationCreditBureauId());
|
||||
commandSourceInput.getOrganisationCreditBureauId(), commandSourceInput.getJobName());
|
||||
|
||||
final boolean makerCheckerApproval = true;
|
||||
return this.processAndLogCommandService.executeCommand(wrapper, command, makerCheckerApproval);
|
||||
|
||||
+1
-1
@@ -262,7 +262,7 @@ public class CenterImportHandler implements ImportHandler {
|
||||
String payload = gsonBuilder.create().toJson(calendarData);
|
||||
CommandWrapper commandWrapper = new CommandWrapper(result.getOfficeId(), result.getGroupId(), result.getClientId(),
|
||||
result.getLoanId(), result.getSavingsId(), null, null, null, null, null, payload, result.getTransactionId(),
|
||||
result.getProductId(), null, null, null);
|
||||
result.getProductId(), null, null, null, null);
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||
.createCalendar(commandWrapper, TemplatePopulateImportConstants.CENTER_ENTITY_TYPE, result.getGroupId()) //
|
||||
.withJson(payload) //
|
||||
|
||||
+1
-1
@@ -241,7 +241,7 @@ public class GroupImportHandler implements ImportHandler {
|
||||
String payload = gsonBuilder.create().toJson(calendarData);
|
||||
CommandWrapper commandWrapper = new CommandWrapper(result.getOfficeId(), result.getGroupId(), result.getClientId(),
|
||||
result.getLoanId(), result.getSavingsId(), null, null, null, null, null, payload, result.getTransactionId(),
|
||||
result.getProductId(), null, null, null);
|
||||
result.getProductId(), null, null, null, null);
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||
.createCalendar(commandWrapper, TemplatePopulateImportConstants.CENTER_ENTITY_TYPE, result.getGroupId()) //
|
||||
.withJson(payload) //
|
||||
|
||||
+21
-10
@@ -64,29 +64,31 @@ public final class JsonCommand {
|
||||
private final Long productId;
|
||||
private final Long creditBureauId;
|
||||
private final Long organisationCreditBureauId;
|
||||
private final String jobName;
|
||||
|
||||
public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper,
|
||||
final String entityName, final Long resourceId, final Long subresourceId, final Long groupId, final Long clientId,
|
||||
final Long loanId, final Long savingsId, final String transactionId, final String url, final Long productId,
|
||||
final Long creditBureauId, final Long organisationCreditBureauId) {
|
||||
final Long creditBureauId, final Long organisationCreditBureauId, final String jobName) {
|
||||
return new JsonCommand(null, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, groupId,
|
||||
clientId, loanId, savingsId, transactionId, url, productId, creditBureauId, organisationCreditBureauId);
|
||||
clientId, loanId, savingsId, transactionId, url, productId, creditBureauId, organisationCreditBureauId, jobName);
|
||||
|
||||
}
|
||||
|
||||
public static JsonCommand fromExistingCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
|
||||
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
|
||||
final String url, final Long productId, final Long creditBureauId, final Long organisationCreditBureauId) {
|
||||
final String url, final Long productId, final Long creditBureauId, final Long organisationCreditBureauId,
|
||||
final String jobName) {
|
||||
return new JsonCommand(commandId, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, null, null,
|
||||
null, null, null, url, productId, creditBureauId, organisationCreditBureauId);
|
||||
null, null, null, url, productId, creditBureauId, organisationCreditBureauId, jobName);
|
||||
}
|
||||
|
||||
public static JsonCommand fromExistingCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
|
||||
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
|
||||
final Long groupId, final Long clientId, final Long loanId, final Long savingsId, final String transactionId, final String url,
|
||||
final Long productId, Long creditBureauId, final Long organisationCreditBureauId) {
|
||||
final Long productId, Long creditBureauId, final Long organisationCreditBureauId, final String jobName) {
|
||||
return new JsonCommand(commandId, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, groupId,
|
||||
clientId, loanId, savingsId, transactionId, url, productId, creditBureauId, organisationCreditBureauId);
|
||||
clientId, loanId, savingsId, transactionId, url, productId, creditBureauId, organisationCreditBureauId, jobName);
|
||||
|
||||
}
|
||||
|
||||
@@ -94,20 +96,22 @@ public final class JsonCommand {
|
||||
final String jsonCommand = command.fromApiJsonHelper.toJson(parsedCommand);
|
||||
return new JsonCommand(command.commandId, jsonCommand, parsedCommand, command.fromApiJsonHelper, command.entityName,
|
||||
command.resourceId, command.subresourceId, command.groupId, command.clientId, command.loanId, command.savingsId,
|
||||
command.transactionId, command.url, command.productId, command.creditBureauId, command.organisationCreditBureauId);
|
||||
command.transactionId, command.url, command.productId, command.creditBureauId, command.organisationCreditBureauId,
|
||||
command.jobName);
|
||||
}
|
||||
|
||||
public static JsonCommand fromExistingCommand(JsonCommand command, final JsonElement parsedCommand, final Long clientId) {
|
||||
final String jsonCommand = command.fromApiJsonHelper.toJson(parsedCommand);
|
||||
return new JsonCommand(command.commandId, jsonCommand, parsedCommand, command.fromApiJsonHelper, command.entityName,
|
||||
command.resourceId, command.subresourceId, command.groupId, clientId, command.loanId, command.savingsId,
|
||||
command.transactionId, command.url, command.productId, command.creditBureauId, command.organisationCreditBureauId);
|
||||
command.transactionId, command.url, command.productId, command.creditBureauId, command.organisationCreditBureauId,
|
||||
command.jobName);
|
||||
}
|
||||
|
||||
public JsonCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
|
||||
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
|
||||
final Long groupId, final Long clientId, final Long loanId, final Long savingsId, final String transactionId, final String url,
|
||||
final Long productId, final Long creditBureauId, final Long organisationCreditBureauId) {
|
||||
final Long productId, final Long creditBureauId, final Long organisationCreditBureauId, final String jobName) {
|
||||
|
||||
this.commandId = commandId;
|
||||
this.jsonCommand = jsonCommand;
|
||||
@@ -125,6 +129,7 @@ public final class JsonCommand {
|
||||
this.productId = productId;
|
||||
this.creditBureauId = creditBureauId;
|
||||
this.organisationCreditBureauId = organisationCreditBureauId;
|
||||
this.jobName = jobName;
|
||||
}
|
||||
|
||||
public static JsonCommand fromJsonElement(final Long resourceId, final JsonElement parsedCommand) {
|
||||
@@ -153,6 +158,7 @@ public final class JsonCommand {
|
||||
this.productId = null;
|
||||
this.creditBureauId = null;
|
||||
this.organisationCreditBureauId = null;
|
||||
this.jobName = null;
|
||||
}
|
||||
|
||||
public JsonCommand(final Long resourceId, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper) {
|
||||
@@ -172,10 +178,11 @@ public final class JsonCommand {
|
||||
this.productId = null;
|
||||
this.creditBureauId = null;
|
||||
this.organisationCreditBureauId = null;
|
||||
this.jobName = null;
|
||||
}
|
||||
|
||||
public static JsonCommand from(final String jsonCommand) {
|
||||
return new JsonCommand(null, jsonCommand, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
|
||||
return new JsonCommand(null, jsonCommand, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
|
||||
|
||||
}
|
||||
|
||||
@@ -255,6 +262,10 @@ public final class JsonCommand {
|
||||
return this.productId;
|
||||
}
|
||||
|
||||
public String getJobName() {
|
||||
return this.jobName;
|
||||
}
|
||||
|
||||
private boolean differenceExists(final TemporalAccessor baseValue, final TemporalAccessor workingCopyValue) {
|
||||
boolean differenceExists = false;
|
||||
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.exceptionmapper;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Provider
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LoanAccountLockCannotBeOverruledExceptionMapper implements ExceptionMapper<LoanAccountLockCannotBeOverruledException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(LoanAccountLockCannotBeOverruledException exception) {
|
||||
final String globalisationMessageCode = "error.msg.invalid.request.body";
|
||||
final String defaultUserMessage = exception.getMessage();
|
||||
log.warn("Exception: {}, Message: {}", exception.getClass().getName(), defaultUserMessage);
|
||||
|
||||
final ApiParameterError error = ApiParameterError.generalError(globalisationMessageCode, defaultUserMessage);
|
||||
|
||||
return Response.status(Response.Status.CONFLICT).entity(error).type(MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.exceptionmapper;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Provider
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LoanNotFoundExceptionMapper implements ExceptionMapper<LoanNotFoundException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(LoanNotFoundException exception) {
|
||||
final String globalisationMessageCode = "error.msg.invalid.request.body";
|
||||
final String defaultUserMessage = exception.getMessage();
|
||||
log.warn("Exception: {}, Message: {}", exception.getClass().getName(), defaultUserMessage);
|
||||
|
||||
final ApiParameterError error = ApiParameterError.generalError(globalisationMessageCode, defaultUserMessage);
|
||||
|
||||
return Response.status(Response.Status.NOT_FOUND).entity(error).type(MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
}
|
||||
+4
@@ -96,6 +96,10 @@ public final class GoogleGsonSerializerHelper {
|
||||
return serializer.toJson(singleDataObject);
|
||||
}
|
||||
|
||||
public Gson createSimpleGson() {
|
||||
return createGsonBuilder().create();
|
||||
}
|
||||
|
||||
public static GsonBuilder createGsonBuilder() {
|
||||
return createGsonBuilder(false);
|
||||
}
|
||||
|
||||
+1
-1
@@ -450,7 +450,7 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl implemen
|
||||
apicommand = JsonCommand.from(json, parsedCommand, this.fromApiJsonHelper, wrapper.getEntityName(), wrapper.getEntityId(),
|
||||
wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(), wrapper.getSavingsId(),
|
||||
wrapper.getTransactionId(), wrapper.getHref(), wrapper.getProductId(), wrapper.getCreditBureauId(),
|
||||
wrapper.getOrganisationCreditBureauId());
|
||||
wrapper.getOrganisationCreditBureauId(), wrapper.getJobName());
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(apicommand.json());
|
||||
|
||||
|
||||
+69
@@ -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.infrastructure.jobs.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.cob.data.LoanIdsResponseDTO;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/jobs")
|
||||
@Component
|
||||
@Tag(name = "Inline Job", description = "")
|
||||
@RequiredArgsConstructor
|
||||
public class InlineJobResource {
|
||||
|
||||
private final PortfolioCommandSourceWritePlatformService commandWritePlatformService;
|
||||
private final DefaultToApiJsonSerializer<LoanIdsResponseDTO> serializer;
|
||||
|
||||
@POST
|
||||
@Path("{jobName}/inline")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Starts an inline Job", description = "Starts an inline Job")
|
||||
@RequestBody(content = @Content(schema = @Schema(implementation = InlineJobResourceSwagger.InlineJobRequest.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = InlineJobResourceSwagger.InlineJobResponse.class)))) })
|
||||
public String executeInlineJob(@PathParam("jobName") @Parameter(description = "jobName") final String jobName,
|
||||
@Parameter(hidden = true) final String jsonRequestBody) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().executeInlineJob(jobName).withJson(jsonRequestBody).build();
|
||||
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
|
||||
return serializer.serialize(result);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.jobs.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.List;
|
||||
|
||||
final class InlineJobResourceSwagger {
|
||||
|
||||
private InlineJobResourceSwagger() {}
|
||||
|
||||
@Schema(description = "InlineJobRequest")
|
||||
public static final class InlineJobRequest {
|
||||
|
||||
private InlineJobRequest() {}
|
||||
|
||||
public List<Long> loanIds;
|
||||
}
|
||||
|
||||
@Schema(description = "InlineJobResponse")
|
||||
public static final class InlineJobResponse {
|
||||
|
||||
private InlineJobResponse() {}
|
||||
|
||||
public List<Long> loanIds;
|
||||
|
||||
}
|
||||
}
|
||||
+38
@@ -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.infrastructure.jobs.domain;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "batch_custom_job_parameters")
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class CustomJobParameter extends AbstractPersistableCustom {
|
||||
|
||||
@Column(name = "parameter_json", nullable = false)
|
||||
private String parameterJson;
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.jobs.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface CustomJobParameterRepository extends JpaRepository<CustomJobParameter, Long> {}
|
||||
+5
@@ -19,6 +19,7 @@
|
||||
package org.apache.fineract.infrastructure.jobs.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
|
||||
/**
|
||||
@@ -30,6 +31,10 @@ public class JobNotFoundException extends AbstractPlatformResourceNotFoundExcept
|
||||
super("error.msg.sheduler.job.id.invalid", "Job with identifier " + identifier + " does not exist", identifier);
|
||||
}
|
||||
|
||||
public JobNotFoundException(final String identifier, NoSuchJobException e) {
|
||||
super("error.msg.sheduler.job.id.invalid", "Job with identifier " + identifier + " does not exist", identifier, e);
|
||||
}
|
||||
|
||||
public JobNotFoundException(String identifier, EmptyResultDataAccessException e) {
|
||||
super("error.msg.sheduler.job.id.invalid", "Job with identifier " + identifier + " does not exist", identifier, e);
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.jobs.service;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface InlineExecutorService {
|
||||
|
||||
CommandProcessingResult executeInlineJob(JsonCommand command, String jobName);
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.jobs.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@CommandType(entity = "INLINE_JOB", action = "EXECUTE")
|
||||
public class InlineJobExecuteHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(JsonCommand command) {
|
||||
InlineJobType inlineJobType = InlineJobType.getInlineJobType(command.getJobName());
|
||||
InlineExecutorService inlineJobExecutorService = applicationContext.getBean(inlineJobType.getExecutorServiceClass());
|
||||
return inlineJobExecutorService.executeInlineJob(command, inlineJobType.getInlineJobName());
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.jobs.service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.cob.service.InlineLoanCOBExecutorServiceImpl;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum InlineJobType {
|
||||
|
||||
LOAN_COB("LOAN_COB", "INLINE_LOAN_COB", InlineLoanCOBExecutorServiceImpl.class);
|
||||
|
||||
private final String jobName;
|
||||
@Getter
|
||||
private final String inlineJobName;
|
||||
@Getter
|
||||
private final Class<? extends InlineExecutorService> executorServiceClass;
|
||||
|
||||
public static InlineJobType getInlineJobType(String jobName) {
|
||||
Optional<InlineJobType> optionalInlineJobType = Arrays.stream(InlineJobType.values())
|
||||
.filter(inlineCOBType -> jobName.equals(inlineCOBType.jobName)).findAny();
|
||||
return optionalInlineJobType.orElseThrow(() -> new IllegalArgumentException("Inline Job is not found by job name: " + jobName));
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.springbatch;
|
||||
|
||||
public abstract class SpringBatchJobConstants {
|
||||
|
||||
public static final String CUSTOM_JOB_PARAMETER_ID_KEY = "CUSTOM_JOB_PARAMETER_ID";
|
||||
}
|
||||
+1
-1
@@ -37,7 +37,7 @@ public class InteropWrapperBuilder {
|
||||
|
||||
public CommandWrapper build() {
|
||||
return new CommandWrapper(null, null, null, null, null, actionName, entityName, null, null, href, json, null, null, null, null,
|
||||
null);
|
||||
null, null);
|
||||
}
|
||||
|
||||
public InteropWrapperBuilder withJson(final String json) {
|
||||
|
||||
+1
-1
@@ -2857,7 +2857,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(overdueInstallment.toString());
|
||||
final JsonCommand command = JsonCommand.from(overdueInstallment.toString(), parsedCommand, this.fromApiJsonHelper, null, null,
|
||||
null, null, null, loanId, null, null, null, null, null, null);
|
||||
null, null, null, loanId, null, null, null, null, null, null, null);
|
||||
LoanOverdueDTO overdueDTO = applyChargeToOverdueLoanInstallment(loan, overdueInstallment.getChargeId(),
|
||||
overdueInstallment.getPeriodNumber(), command);
|
||||
loan = overdueDTO.getLoan();
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class ShareAccountCommandsServiceImpl implements AccountsCommandsService
|
||||
public Object handleCommand(Long accountId, String command, String jsonBody) {
|
||||
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(jsonBody);
|
||||
final JsonCommand jsonCommand = JsonCommand.from(jsonBody, parsedCommand, this.fromApiJsonHelper, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null);
|
||||
null, null, null, null, null, null, null, null);
|
||||
if (ShareAccountApiConstants.APPROVE_COMMAND.equals(command)) {
|
||||
return approveShareAccount(accountId, jsonCommand);
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ public class ShareProductCommandsServiceImpl implements ProductCommandsService {
|
||||
public Object handleCommand(Long productId, String command, String jsonBody) {
|
||||
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(jsonBody);
|
||||
final JsonCommand jsonCommand = JsonCommand.from(jsonBody, parsedCommand, this.fromApiJsonHelper, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null);
|
||||
null, null, null, null, null, null, null, null);
|
||||
if (ShareProductApiConstants.PREIEW_DIVIDENDS_COMMAND_STRING.equals(command)) {
|
||||
return null;
|
||||
} else if (ShareProductApiConstants.POST_DIVIDENdS_COMMAND_STRING.equals(command)) {
|
||||
|
||||
@@ -77,4 +77,7 @@
|
||||
<include file="parts/0055_add_submitted_on_date_to_loan_charge.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0056_add_external_event_default_configuration.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0057_add_principal_adjustments_to_loan.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0058_add_execute_inline_cob_permission.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0059_add_spring_batch_loan_id_list_table.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0060_add_job_name_to_command_source.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?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 author="fineract" id="1">
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation"/>
|
||||
<column name="code" value="EXECUTE_INLINE_JOB"/>
|
||||
<column name="entity_name" value="INLINE_JOB"/>
|
||||
<column name="action_name" value="EXECUTE"/>
|
||||
<column name="can_maker_checker" valueBoolean="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?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 author="fineract" id="1">
|
||||
<createTable tableName="batch_custom_job_parameters">
|
||||
<column autoIncrement="true" name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true"/>
|
||||
</column>
|
||||
<column name="parameter_json" type="TEXT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?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 author="fineract" id="1">
|
||||
<addColumn tableName="m_portfolio_command_source">
|
||||
<column name="job_name" type="VARCHAR(100)">
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+2
-1
@@ -46,7 +46,8 @@ public class LoanItemListenerStepDefinitions implements En {
|
||||
private LoanAccountLockRepository accountLockRepository = mock(LoanAccountLockRepository.class);
|
||||
private TransactionTemplate transactionTemplate = spy(TransactionTemplate.class);
|
||||
|
||||
private LoanItemListener loanItemListener = new LoanItemListener(accountLockRepository, transactionTemplate);
|
||||
private ChunkProcessingLoanItemListener loanItemListener = new ChunkProcessingLoanItemListener(accountLockRepository,
|
||||
transactionTemplate);
|
||||
|
||||
private Exception exception;
|
||||
|
||||
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class BusinessStepConfigUpdateHandlerTest {
|
||||
|
||||
@InjectMocks
|
||||
private BusinessStepConfigUpdateHandler testObj;
|
||||
|
||||
@Mock
|
||||
private ConfigJobParameterService configJobParameterService;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<String> argumentCaptor;
|
||||
|
||||
@Test
|
||||
void shouldProcessCommandGetsJobName() {
|
||||
JsonCommand command = mock(JsonCommand.class);
|
||||
given(command.getUrl()).willReturn("/jobs/jobName/steps");
|
||||
testObj.processCommand(command);
|
||||
|
||||
verify(configJobParameterService).updateStepConfigByJobName(eq(command), argumentCaptor.capture());
|
||||
assertEquals("jobName", argumentCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldProcessCommandGetsJobNameEmptyString() {
|
||||
JsonCommand command = mock(JsonCommand.class);
|
||||
given(command.getUrl()).willReturn("/jobs//steps");
|
||||
testObj.processCommand(command);
|
||||
|
||||
verify(configJobParameterService).updateStepConfigByJobName(eq(command), argumentCaptor.capture());
|
||||
assertEquals("", argumentCaptor.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldProcessCommandGetsJobNameNull() {
|
||||
JsonCommand command = mock(JsonCommand.class);
|
||||
given(command.getUrl()).willReturn("/jobs/" + null + "/steps");
|
||||
testObj.processCommand(command);
|
||||
|
||||
verify(configJobParameterService).updateStepConfigByJobName(eq(command), argumentCaptor.capture());
|
||||
assertEquals(null, argumentCaptor.getValue());
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class InlineLoanCOBExecutorServiceImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private InlineLoanCOBExecutorServiceImpl testObj;
|
||||
@Mock
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@Mock
|
||||
private InlineLoanCOBExecutionDataParser dataParser;
|
||||
|
||||
@Test
|
||||
void shouldExceptionThrownIfLoanIsAlreadyLocked() {
|
||||
JsonCommand command = mock(JsonCommand.class);
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
|
||||
when(dataParser.parseExecution(any())).thenReturn(List.of(3L));
|
||||
when(transactionTemplate.execute(any())).thenThrow(new LoanAccountLockCannotBeOverruledException(""));
|
||||
assertThrows(LoanAccountLockCannotBeOverruledException.class, () -> testObj.executeInlineJob(command, "INLINE_LOAN_COB"));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class CommandHandlerProviderStepDefinitions implements En {
|
||||
|
||||
When("The user processes the command with ID {long}", (Long id) -> {
|
||||
this.result = commandHandler
|
||||
.processCommand(JsonCommand.fromExistingCommand(id, null, null, null, null, null, null, null, null, null, null));
|
||||
.processCommand(JsonCommand.fromExistingCommand(id, null, null, null, null, null, null, null, null, null, null, null));
|
||||
});
|
||||
|
||||
Then("The command ID matches {long}", (Long id) -> {
|
||||
|
||||
Reference in New Issue
Block a user