rewrite MultiException to actually contain all causes (FINERACT-858) (#855)
This commit is contained in:
+64
-8
@@ -18,6 +18,14 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.core.exception;
|
||||
|
||||
import com.google.common.io.CharStreams;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Exception with multiple root causes.
|
||||
*
|
||||
@@ -25,21 +33,69 @@ package org.apache.fineract.infrastructure.core.exception;
|
||||
* each of which could fail, but where we don't want to fail immediately but continue, and
|
||||
* then fail at end.
|
||||
*
|
||||
* <p>The failures MUST each be logged within the loop, as they occur; this exception is
|
||||
* only thrown to propagate the failure, but will not contain and re-log the details.
|
||||
* <p>The failures should typically also each be logged within the loop, as they occur; this exception is
|
||||
* only thrown to propagate the failure, and the caller may or may not log this with the details.
|
||||
*
|
||||
* <p>Originally inspired by org.junit.runners.model.MultipleFailureException</p>.
|
||||
*
|
||||
* @author Michael Vorburger.ch <mike@vorburger.ch>
|
||||
*/
|
||||
public class MultiException extends Exception {
|
||||
|
||||
private final int n;
|
||||
private final List<Throwable> throwables;
|
||||
|
||||
public MultiException(int n) {
|
||||
super(n + "x failures occured here (details have been previously logged");
|
||||
this.n = n;
|
||||
public MultiException(List<Throwable> problems) {
|
||||
super("MultiException with " + problems.size() + " contained causes (details available)");
|
||||
if (problems.isEmpty()) { throw new IllegalArgumentException("List of Throwables must not be empty"); }
|
||||
this.throwables = new ArrayList<>(problems);
|
||||
}
|
||||
|
||||
public int getCausesSize() {
|
||||
return n;
|
||||
public List<Throwable> getCauses() {
|
||||
return Collections.unmodifiableList(throwables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
int i = 0;
|
||||
StringBuilder sb = new StringBuilder(super.getMessage());
|
||||
for (Throwable e : throwables) {
|
||||
sb.append("\n ");
|
||||
sb.append(++i);
|
||||
sb.append(". ");
|
||||
Writer w = CharStreams.asWriter(sb);
|
||||
e.printStackTrace(new PrintWriter(w, true));
|
||||
}
|
||||
sb.append("\n which was itself thrown..");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace() {
|
||||
System.err.println(super.getMessage());
|
||||
int i = 0;
|
||||
for (Throwable e : throwables) {
|
||||
System.err.print(++i + ".");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(PrintStream s) {
|
||||
s.println(super.getMessage());
|
||||
int i = 0;
|
||||
for (Throwable e : throwables) {
|
||||
s.print(++i + ".");
|
||||
e.printStackTrace(s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(PrintWriter s) {
|
||||
s.println(super.getMessage());
|
||||
int i = 0;
|
||||
for (Throwable e : throwables) {
|
||||
s.print(++i + ".");
|
||||
e.printStackTrace(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -18,11 +18,16 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.jobs.exception;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.exception.MultiException;
|
||||
|
||||
public class JobExecutionException extends MultiException {
|
||||
|
||||
public JobExecutionException(int n) {
|
||||
super(n);
|
||||
public JobExecutionException(List<Throwable> problems) {
|
||||
super(problems);
|
||||
}
|
||||
|
||||
public JobExecutionException(MultiException multiException) {
|
||||
super(multiException.getCauses());
|
||||
}
|
||||
}
|
||||
|
||||
+14
-20
@@ -24,8 +24,10 @@ import static org.apache.fineract.portfolio.account.AccountDetailConstants.toAcc
|
||||
import static org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.statusParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
@@ -193,7 +195,7 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
|
||||
public void executeStandingInstructions() throws JobExecutionException {
|
||||
Collection<StandingInstructionData> instructionDatas = this.standingInstructionReadPlatformService
|
||||
.retrieveAll(StandingInstructionStatus.ACTIVE.getValue());
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
for (StandingInstructionData data : instructionDatas) {
|
||||
boolean isDueForTransfer = false;
|
||||
AccountTransferRecurrenceType recurrenceType = data.recurrenceType();
|
||||
@@ -240,7 +242,7 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
|
||||
+ " Standing instruction trasfer ", null, null, null, null, data.toTransferType(), null, null, data
|
||||
.transferType().getValue(), null, null, null, null, null, fromSavingsAccount,
|
||||
isRegularTransaction, isExceptionForBalanceCheck);
|
||||
final boolean transferCompleted = transferAmount(sb, accountTransferDTO, data.getId());
|
||||
final boolean transferCompleted = transferAmount(errors, accountTransferDTO, data.getId());
|
||||
|
||||
if(transferCompleted){
|
||||
final String updateQuery = "UPDATE m_account_transfer_standing_instructions SET last_run_date = ? where id = ?";
|
||||
@@ -249,14 +251,10 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
|
||||
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
logger.error("executeStandingInstructions (transferAmount) encountered failure/s: {}", sb.toString());
|
||||
// This is a bit of a hack (related to https://issues.apache.org/jira/browse/FINERACT-858) and could be improved..
|
||||
throw new JobExecutionException(123456789);
|
||||
}
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
|
||||
private boolean transferAmount(final StringBuilder sb, final AccountTransferDTO accountTransferDTO, final Long instructionId) {
|
||||
private boolean transferAmount(final List<Throwable> errors, final AccountTransferDTO accountTransferDTO, final Long instructionId) {
|
||||
boolean transferCompleted = true;
|
||||
StringBuilder errorLog = new StringBuilder();
|
||||
StringBuilder updateQuery = new StringBuilder(
|
||||
@@ -264,24 +262,20 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
|
||||
try {
|
||||
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
|
||||
} catch (final PlatformApiDataValidationException e) {
|
||||
sb.append("Validation exception while trasfering funds for standing Instruction id").append(instructionId).append(" from ")
|
||||
.append(accountTransferDTO.getFromAccountId()).append(" to ").append(accountTransferDTO.getToAccountId())
|
||||
.append("--------");
|
||||
errors.add(new Exception("Validation exception while transfering funds for standing Instruction id" + instructionId + " from "
|
||||
+ accountTransferDTO.getFromAccountId() + " to " + accountTransferDTO.getToAccountId(), e));
|
||||
errorLog.append("Validation exception while trasfering funds " + e.getDefaultUserMessage());
|
||||
} catch (final InsufficientAccountBalanceException e) {
|
||||
sb.append("InsufficientAccountBalance Exception while trasfering funds for standing Instruction id").append(instructionId)
|
||||
.append(" from ").append(accountTransferDTO.getFromAccountId()).append(" to ")
|
||||
.append(accountTransferDTO.getToAccountId()).append("--------");
|
||||
errors.add(new Exception("InsufficientAccountBalance Exception while trasfering funds for standing Instruction id"
|
||||
+ instructionId + " from " + accountTransferDTO.getFromAccountId() + " to " + accountTransferDTO.getToAccountId(), e));
|
||||
errorLog.append("InsufficientAccountBalance Exception ");
|
||||
} catch (final AbstractPlatformServiceUnavailableException e) {
|
||||
sb.append("Platform exception while trasfering funds for standing Instruction id").append(instructionId).append(" from ")
|
||||
.append(accountTransferDTO.getFromAccountId()).append(" to ").append(accountTransferDTO.getToAccountId())
|
||||
.append("--------");
|
||||
errors.add(new Exception("Platform exception while trasfering funds for standing Instruction id" + instructionId + " from "
|
||||
+ accountTransferDTO.getFromAccountId() + " to " + accountTransferDTO.getToAccountId(), e));
|
||||
errorLog.append("Platform exception while trasfering funds " + e.getDefaultUserMessage());
|
||||
} catch (Exception e) {
|
||||
sb.append("Exception while trasfering funds for standing Instruction id").append(instructionId).append(" from ")
|
||||
.append(accountTransferDTO.getFromAccountId()).append(" to ").append(accountTransferDTO.getToAccountId())
|
||||
.append("--------");
|
||||
errors.add(new Exception("Unhandled System Exception while trasfering funds for standing Instruction id" + instructionId
|
||||
+ " from " + accountTransferDTO.getFromAccountId() + " to " + accountTransferDTO.getToAccountId(), e));
|
||||
errorLog.append("Exception while trasfering funds " + e.getMessage());
|
||||
|
||||
}
|
||||
|
||||
+13
-12
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.service;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.core.exception.MultiException;
|
||||
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
|
||||
@@ -63,16 +64,16 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
|
||||
}
|
||||
}
|
||||
|
||||
int errors = 0;
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
for (Map.Entry<Long, Collection<LoanScheduleAccrualData>> mapEntry : loanDataMap.entrySet()) {
|
||||
try {
|
||||
this.loanAccrualWritePlatformService.addAccrualAccounting(mapEntry.getKey(), mapEntry.getValue());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to add accural transaction for loan {}", mapEntry.getKey(), e);
|
||||
++errors;
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
if (errors > 0) { throw new JobExecutionException(errors); }
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,18 +82,18 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
|
||||
try {
|
||||
addPeriodicAccruals(LocalDate.now());
|
||||
} catch (MultiException e) {
|
||||
throw new JobExecutionException(e.getCausesSize());
|
||||
throw new JobExecutionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPeriodicAccruals(final LocalDate tilldate) throws MultiException {
|
||||
public void addPeriodicAccruals(final LocalDate tilldate) throws JobExecutionException {
|
||||
Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = this.loanReadPlatformService.retrivePeriodicAccrualData(tilldate);
|
||||
addPeriodicAccruals(tilldate, loanScheduleAccrualDatas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPeriodicAccruals(final LocalDate tilldate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas) throws MultiException {
|
||||
public void addPeriodicAccruals(final LocalDate tilldate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas) throws JobExecutionException {
|
||||
Map<Long, Collection<LoanScheduleAccrualData>> loanDataMap = new HashMap<>();
|
||||
for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) {
|
||||
if (loanDataMap.containsKey(accrualData.getLoanId())) {
|
||||
@@ -104,16 +105,16 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
|
||||
}
|
||||
}
|
||||
|
||||
int errors = 0;
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
for (Map.Entry<Long, Collection<LoanScheduleAccrualData>> mapEntry : loanDataMap.entrySet()) {
|
||||
try {
|
||||
this.loanAccrualWritePlatformService.addPeriodicAccruals(tilldate, mapEntry.getKey(), mapEntry.getValue());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to add accural transaction for loan {}", mapEntry.getKey(), e);
|
||||
++errors;
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
if (errors > 0) { throw new MultiException(errors); }
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -121,16 +122,16 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
|
||||
public void addPeriodicAccrualsForLoansWithIncomePostedAsTransactions() throws JobExecutionException {
|
||||
Collection<Long> loanIds = this.loanReadPlatformService.retrieveLoanIdsWithPendingIncomePostingTransactions();
|
||||
if(loanIds != null && loanIds.size() > 0){
|
||||
int errors = 0;
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
for (Long loanId : loanIds) {
|
||||
try {
|
||||
this.loanAccrualWritePlatformService.addIncomeAndAccrualTransactions(loanId);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to add income and accrual transaction for loan {}", loanId, e);
|
||||
++errors;
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
if (errors > 0) { throw new JobExecutionException(errors); }
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -95,7 +95,7 @@ public class LoanSchedularServiceImpl implements LoanSchedularService {
|
||||
}
|
||||
}
|
||||
|
||||
int numberOfErrors = 0;
|
||||
List<Throwable> exceptions = new ArrayList<>();
|
||||
for (final Long loanId : overdueScheduleData.keySet()) {
|
||||
try {
|
||||
this.loanWritePlatformService.applyOverdueChargesForLoan(loanId, overdueScheduleData.get(loanId));
|
||||
@@ -104,17 +104,17 @@ public class LoanSchedularServiceImpl implements LoanSchedularService {
|
||||
final List<ApiParameterError> errors = e.getErrors();
|
||||
for (final ApiParameterError error : errors) {
|
||||
logger.error("Apply Charges due for overdue loans failed for account {} with message: {}", loanId, error.getDeveloperMessage(), e);
|
||||
++numberOfErrors;
|
||||
}
|
||||
exceptions.add(e);
|
||||
} catch (final AbstractPlatformDomainRuleException e) {
|
||||
logger.error("Apply Charges due for overdue loans failed for account {} with message: {}", loanId, e.getDefaultUserMessage(), e);
|
||||
++numberOfErrors;
|
||||
exceptions.add(e);
|
||||
} catch (Exception e) {
|
||||
logger.error("Apply Charges due for overdue loans failed for account {}", loanId, e);
|
||||
++numberOfErrors;
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
if (numberOfErrors > 0) { throw new JobExecutionException(numberOfErrors); }
|
||||
if (!exceptions.isEmpty()) { throw new JobExecutionException(exceptions); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class LoanSchedularServiceImpl implements LoanSchedularService {
|
||||
.fetchLoansForInterestRecalculation();
|
||||
int i = 0;
|
||||
if (!loanIds.isEmpty()) {
|
||||
int errors = 0;
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
for (Long loanId : loanIds) {
|
||||
logger.info("recalculateInterest: Loan ID = {}", loanId);
|
||||
Integer numberOfRetries = 0;
|
||||
@@ -143,7 +143,7 @@ public class LoanSchedularServiceImpl implements LoanSchedularService {
|
||||
// Fail if the transaction has been retried for maxNumberOfRetries
|
||||
if (numberOfRetries >= maxNumberOfRetries) {
|
||||
logger.error("Recalulate interest job has been retried for the max allowed attempts of {} and will be rolled back", numberOfRetries);
|
||||
++errors;
|
||||
errors.add(exception);
|
||||
break;
|
||||
}
|
||||
// Else sleep for a random time (between 1 to 10 seconds) and continue
|
||||
@@ -154,19 +154,19 @@ public class LoanSchedularServiceImpl implements LoanSchedularService {
|
||||
numberOfRetries = numberOfRetries + 1;
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Interest recalculation for loans retry failed due to InterruptedException", e) ;
|
||||
++errors;
|
||||
errors.add(e);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Interest recalculation for loans failed for account {}", loanId, e);
|
||||
numberOfRetries = maxNumberOfRetries + 1;
|
||||
++errors;
|
||||
errors.add(e);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
logger.info("recalculateInterest: Loans count {}", i);
|
||||
}
|
||||
if (errors > 0) { throw new JobExecutionException(errors); }
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+69
-78
@@ -181,7 +181,6 @@ import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.exception.InsufficientAccountBalanceException;
|
||||
import org.apache.fineract.portfolio.transfer.api.TransferApiConstants;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -325,27 +324,27 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult disburseGLIMLoan(final Long loanId, final JsonCommand command)
|
||||
{
|
||||
final Long parentLoanId=loanId;
|
||||
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
|
||||
List<Loan> childLoans=this.loanRepository.findByGlimId(loanId);
|
||||
CommandProcessingResult result=null;
|
||||
int count=0;
|
||||
for(Loan loan:childLoans)
|
||||
{
|
||||
result=disburseLoan(loan.getId(),command,false);
|
||||
if(result.getLoanId()!=null)
|
||||
{
|
||||
count++;
|
||||
// if all the child loans are approved, mark the parent loan as approved
|
||||
if(count==parentLoan.getChildAccountsCount())
|
||||
{
|
||||
parentLoan.setLoanStatus(LoanStatus.ACTIVE.getValue());
|
||||
glimRepository.save(parentLoan);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
{
|
||||
final Long parentLoanId=loanId;
|
||||
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
|
||||
List<Loan> childLoans=this.loanRepository.findByGlimId(loanId);
|
||||
CommandProcessingResult result=null;
|
||||
int count=0;
|
||||
for(Loan loan:childLoans)
|
||||
{
|
||||
result=disburseLoan(loan.getId(),command,false);
|
||||
if(result.getLoanId()!=null)
|
||||
{
|
||||
count++;
|
||||
// if all the child loans are approved, mark the parent loan as approved
|
||||
if(count==parentLoan.getChildAccountsCount())
|
||||
{
|
||||
parentLoan.setLoanStatus(LoanStatus.ACTIVE.getValue());
|
||||
glimRepository.save(parentLoan);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -772,27 +771,27 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
@Override
|
||||
public CommandProcessingResult undoGLIMLoanDisbursal(final Long loanId, final JsonCommand command)
|
||||
{
|
||||
//GroupLoanIndividualMonitoringAccount glimAccount=glimRepository.findOne(loanId);
|
||||
final Long parentLoanId=loanId;
|
||||
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
|
||||
List<Loan> childLoans=this.loanRepository.findByGlimId(loanId);
|
||||
CommandProcessingResult result=null;
|
||||
int count=0;
|
||||
for(Loan loan:childLoans)
|
||||
{
|
||||
result=undoLoanDisbursal(loan.getId(),command);
|
||||
if(result.getLoanId()!=null)
|
||||
{
|
||||
count++;
|
||||
// if all the child loans are approved, mark the parent loan as approved
|
||||
if(count==parentLoan.getChildAccountsCount())
|
||||
{
|
||||
parentLoan.setLoanStatus(LoanStatus.APPROVED.getValue());
|
||||
glimRepository.save(parentLoan);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
//GroupLoanIndividualMonitoringAccount glimAccount=glimRepository.findOne(loanId);
|
||||
final Long parentLoanId=loanId;
|
||||
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
|
||||
List<Loan> childLoans=this.loanRepository.findByGlimId(loanId);
|
||||
CommandProcessingResult result=null;
|
||||
int count=0;
|
||||
for(Loan loan:childLoans)
|
||||
{
|
||||
result=undoLoanDisbursal(loan.getId(),command);
|
||||
if(result.getLoanId()!=null)
|
||||
{
|
||||
count++;
|
||||
// if all the child loans are approved, mark the parent loan as approved
|
||||
if(count==parentLoan.getChildAccountsCount())
|
||||
{
|
||||
parentLoan.setLoanStatus(LoanStatus.APPROVED.getValue());
|
||||
glimRepository.save(parentLoan);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -854,28 +853,28 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
public CommandProcessingResult makeGLIMLoanRepayment(final Long loanId, final JsonCommand command)
|
||||
{
|
||||
|
||||
final Long parentLoanId=loanId;
|
||||
final Long parentLoanId=loanId;
|
||||
|
||||
GroupLoanIndividualMonitoringAccount parentLoan=glimRepository.findById(parentLoanId).get();
|
||||
glimRepository.findById(parentLoanId).get();
|
||||
|
||||
JsonArray repayments= command.arrayOfParameterNamed("formDataArray");
|
||||
JsonCommand childCommand=null;
|
||||
CommandProcessingResult result=null;
|
||||
JsonObject jsonObject=null;
|
||||
JsonArray repayments= command.arrayOfParameterNamed("formDataArray");
|
||||
JsonCommand childCommand=null;
|
||||
CommandProcessingResult result=null;
|
||||
JsonObject jsonObject=null;
|
||||
|
||||
Long[] childLoanId=new Long[repayments.size()];
|
||||
for (int i = 0; i < repayments.size(); i++) {
|
||||
jsonObject=repayments.get(i).getAsJsonObject();
|
||||
LOG.info("{}",jsonObject.toString());
|
||||
childLoanId[i]=jsonObject.get("loanId").getAsLong();
|
||||
}
|
||||
int j=0;
|
||||
for(JsonElement element:repayments )
|
||||
{
|
||||
childCommand=JsonCommand.fromExistingCommand(command,element);
|
||||
result=makeLoanRepayment(childLoanId[j++],childCommand,false);
|
||||
}
|
||||
return result;
|
||||
Long[] childLoanId=new Long[repayments.size()];
|
||||
for (int i = 0; i < repayments.size(); i++) {
|
||||
jsonObject=repayments.get(i).getAsJsonObject();
|
||||
LOG.info("{}",jsonObject.toString());
|
||||
childLoanId[i]=jsonObject.get("loanId").getAsLong();
|
||||
}
|
||||
int j=0;
|
||||
for(JsonElement element:repayments )
|
||||
{
|
||||
childCommand=JsonCommand.fromExistingCommand(command,element);
|
||||
result=makeLoanRepayment(childLoanId[j++],childCommand,false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -1868,7 +1867,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Collection<LoanChargeData> chargeDatas = this.loanChargeReadPlatformService.retrieveLoanChargesForFeePayment(
|
||||
ChargePaymentMode.ACCOUNT_TRANSFER.getValue(), LoanStatus.ACTIVE.getValue());
|
||||
final boolean isRegularTransaction = true;
|
||||
int errors = 0;
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
if (chargeDatas != null) {
|
||||
for (final LoanChargeData chargeData : chargeDatas) {
|
||||
if (chargeData.isInstallmentFee()) {
|
||||
@@ -1889,9 +1888,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
null, LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId(),
|
||||
installmentChargeData.getInstallmentNumber(), AccountTransferType.CHARGE_PAYMENT.getValue(), null,
|
||||
null, null, null, null, fromSavingsAccount, isRegularTransaction, isExceptionForBalanceCheck);
|
||||
if (!transferFeeCharge(accountTransferDTO)) {
|
||||
++errors;
|
||||
}
|
||||
transferFeeCharge(accountTransferDTO, errors);
|
||||
}
|
||||
}
|
||||
} else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(DateUtils.getLocalDateOfTenant())) {
|
||||
@@ -1905,25 +1902,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId(), null,
|
||||
AccountTransferType.CHARGE_PAYMENT.getValue(), null, null, null, null, null, fromSavingsAccount,
|
||||
isRegularTransaction, isExceptionForBalanceCheck);
|
||||
if (!transferFeeCharge(accountTransferDTO)) {
|
||||
++errors;
|
||||
}
|
||||
transferFeeCharge(accountTransferDTO, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors > 0) { throw new JobExecutionException(errors); }
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
|
||||
private boolean transferFeeCharge(final AccountTransferDTO accountTransferDTO) {
|
||||
private void transferFeeCharge(final AccountTransferDTO accountTransferDTO, List<Throwable> errors) {
|
||||
try {
|
||||
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
|
||||
return true;
|
||||
} catch (final PlatformApiDataValidationException e) {
|
||||
LOG.error("Validation exception while paying charge {} for loan id {}", accountTransferDTO.getChargeId(), accountTransferDTO.getToAccountId(), e);
|
||||
return false;
|
||||
} catch (final InsufficientAccountBalanceException e) {
|
||||
LOG.error("InsufficientAccountBalanceException while paying charge {} for loan id {}", accountTransferDTO.getChargeId(), accountTransferDTO.getToAccountId(), e);
|
||||
return false;
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error("Exception while paying charge {} for loan id {}", accountTransferDTO.getChargeId(), accountTransferDTO.getToAccountId(), e);
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -18,7 +18,9 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
@@ -56,7 +58,7 @@ public class RecalculateInterestPoster implements Callable<Void> {
|
||||
|
||||
int i = 0;
|
||||
if (!loanIds.isEmpty()) {
|
||||
int errors = 0;
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
for (Long loanId : loanIds) {
|
||||
logger.info("Loan ID {}", loanId);
|
||||
Integer numberOfRetries = 0;
|
||||
@@ -70,7 +72,7 @@ public class RecalculateInterestPoster implements Callable<Void> {
|
||||
// Fail if the transaction has been retired for maxNumberOfRetries
|
||||
if (numberOfRetries >= maxNumberOfRetries) {
|
||||
logger.error("Recalulate interest job has been retried for the max allowed attempts of {} and will be rolled back", numberOfRetries);
|
||||
++errors;
|
||||
errors.add(exception);
|
||||
break;
|
||||
}
|
||||
// Else sleep for a random time (between 1 to 10 seconds) and continue
|
||||
@@ -81,19 +83,19 @@ public class RecalculateInterestPoster implements Callable<Void> {
|
||||
numberOfRetries = numberOfRetries + 1;
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Interest recalculation for loans retry failed due to InterruptedException", e) ;
|
||||
++errors;
|
||||
errors.add(e);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Interest recalculation for loans failed for account {}", loanId, e);
|
||||
numberOfRetries = maxNumberOfRetries + 1;
|
||||
++errors;
|
||||
errors.add(e);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
logger.info("Loans count {}", i);
|
||||
}
|
||||
if (errors > 0) { throw new JobExecutionException(errors); }
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+4
-4
@@ -575,20 +575,20 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.TRANSFER_INTEREST_TO_SAVINGS)
|
||||
public void transferInterestToSavings() throws JobExecutionException {
|
||||
int errors = 0;
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
Collection<AccountTransferDTO> accountTrasferData = this.depositAccountReadPlatformService.retrieveDataForInterestTransfer();
|
||||
for (AccountTransferDTO accountTransferDTO : accountTrasferData) {
|
||||
try {
|
||||
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
|
||||
} catch (final PlatformApiDataValidationException e) {
|
||||
LOG.error("Validation exception while trasfering Interest from {} to {}", accountTransferDTO.getFromAccountId(), accountTransferDTO.getToAccountId(), e);
|
||||
++errors;
|
||||
errors.add(e);
|
||||
} catch (final InsufficientAccountBalanceException e) {
|
||||
LOG.error("InsufficientAccountBalanceException while trasfering Interest from {} to {} ", accountTransferDTO.getFromAccountId(), accountTransferDTO.getToAccountId(), e);
|
||||
++errors;
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
if (errors > 0) { throw new JobExecutionException(errors); }
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-3
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.savings.service;
|
||||
|
||||
import static org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType.ACTIVE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
|
||||
@@ -62,7 +63,7 @@ public class SavingsSchedularServiceImpl implements SavingsSchedularService {
|
||||
int page = 0;
|
||||
Integer initialSize = 500;
|
||||
Integer totalPageSize = 0;
|
||||
int errors = 0;
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
do {
|
||||
PageRequest pageRequest = PageRequest.of(page, initialSize);
|
||||
Page<SavingsAccount> savingsAccounts = this.savingsAccountRepository.findByStatus(ACTIVE.getValue(), pageRequest);
|
||||
@@ -74,14 +75,14 @@ public class SavingsSchedularServiceImpl implements SavingsSchedularService {
|
||||
this.savingsAccountWritePlatformService.postInterest(savingsAccount, postInterestAsOn, transactionDate);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to post interest for Savings with id {}", savingsAccount.getId(), e);
|
||||
++errors;
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
page++;
|
||||
totalPageSize = savingsAccounts.getTotalPages();
|
||||
} while (page < totalPageSize);
|
||||
|
||||
if (errors > 0) { throw new JobExecutionException(errors); }
|
||||
if (!errors.isEmpty()) { throw new JobExecutionException(errors); }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+11
-9
@@ -21,6 +21,7 @@ package org.apache.fineract.scheduledjobs.service;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -239,20 +240,20 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
@CronTarget(jobName = JobName.PAY_DUE_SAVINGS_CHARGES)
|
||||
public void applyDueChargesForSavings() throws JobExecutionException {
|
||||
final Collection<SavingsAccountAnnualFeeData> chargesDueData = this.savingsAccountChargeReadPlatformService.retrieveChargesWithDue();
|
||||
int numberOfErrors = 0;
|
||||
List<Throwable> exceptions = new ArrayList<>();
|
||||
for (final SavingsAccountAnnualFeeData savingsAccountReference : chargesDueData) {
|
||||
try {
|
||||
this.savingsAccountWritePlatformService.applyChargeDue(savingsAccountReference.getId(), savingsAccountReference.getAccountId());
|
||||
} catch (final PlatformApiDataValidationException e) {
|
||||
exceptions.add(e);
|
||||
final List<ApiParameterError> errors = e.getErrors();
|
||||
for (final ApiParameterError error : errors) {
|
||||
logger.error("Apply Charges due for savings failed for account {} with message: {}", savingsAccountReference.getAccountNo(), error.getDeveloperMessage(), e);
|
||||
++numberOfErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info("{}: Savings accounts affected by update: {}", ThreadLocalContextUtil.getTenant().getName(), chargesDueData.size());
|
||||
if (numberOfErrors > 0) { throw new JobExecutionException(numberOfErrors); }
|
||||
if (!exceptions.isEmpty()) { throw new JobExecutionException(exceptions); }
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -372,7 +373,7 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.POST_DIVIDENTS_FOR_SHARES)
|
||||
public void postDividends() throws JobExecutionException {
|
||||
int numberOfErrors = 0;
|
||||
List<Throwable> exceptions = new ArrayList<>();
|
||||
List<Map<String, Object>> dividendDetails = this.shareAccountDividendReadPlatformService.retriveDividendDetailsForPostDividents();
|
||||
for (Map<String, Object> dividendMap : dividendDetails) {
|
||||
Long id = null ;
|
||||
@@ -388,19 +389,20 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
try {
|
||||
this.shareAccountSchedularService.postDividend(id, savingsId);
|
||||
} catch (final PlatformApiDataValidationException e) {
|
||||
exceptions.add(e);
|
||||
final List<ApiParameterError> errors = e.getErrors();
|
||||
for (final ApiParameterError error : errors) {
|
||||
logger.error("Post Dividends to savings failed due to ApiParameterError for Divident detail Id: {} and savings Id: {} with message: {}",
|
||||
new Object[] { id, savingsId, error.getDeveloperMessage(), e });
|
||||
++numberOfErrors;
|
||||
logger.error(
|
||||
"Post Dividends to savings failed due to ApiParameterError for Divident detail Id: {} and savings Id: {} with message: {}",
|
||||
id, savingsId, error.getDeveloperMessage(), e);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
logger.error("Post Dividends to savings failed for Divident detail Id: {} and savings Id: {}", id, savingsId, e);
|
||||
++numberOfErrors;
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (numberOfErrors > 0) { throw new JobExecutionException(numberOfErrors); }
|
||||
if (!exceptions.isEmpty()) { throw new JobExecutionException(exceptions); }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+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.infrastructure.core.exception;
|
||||
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
class MultiExceptionTest {
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(MultiExceptionTest.class);
|
||||
|
||||
@Test()
|
||||
void testEmpty() throws MultiException {
|
||||
assertThrows(IllegalArgumentException.class, () -> { throw new MultiException(Collections.emptyList()); });
|
||||
}
|
||||
|
||||
@Test()
|
||||
void test() throws MultiException {
|
||||
List<Throwable> causes = List.of(new IllegalArgumentException(), new IllegalStateException());
|
||||
MultiException e = new MultiException(causes);
|
||||
logger.warn("Biep, bieb", e);
|
||||
// Uncomment to see JUnit UI:
|
||||
// throw e;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user