From e76adfbe564ce6d712e325f8af20646b07e332f1 Mon Sep 17 00:00:00 2001 From: Adam Saghy Date: Thu, 27 Oct 2022 14:13:38 +0200 Subject: [PATCH] FINERACT-1787: Fineract using wrong business date due to lack of resetting the ActionContext --- .../cob/COBBusinessStepServiceImpl.java | 1 + .../cob/common/InitialisationTasklet.java | 3 ++ .../cob/common/ResetContextTasklet.java | 40 +++++++++++++++++++ ...neLoanCOBBuildExecutionContextTasklet.java | 3 ++ .../cob/loan/LoanCOBWorkerConfiguration.java | 14 ++++++- .../cob/loan/LoanInlineCOBConfig.java | 13 +++++- .../core/service/ThreadLocalContextUtil.java | 8 ++++ .../jobs/service/JobSchedulerServiceImpl.java | 2 + .../jobs/service/SchedulerJobListener.java | 2 + .../service/SchedulerTriggerListener.java | 2 + .../TenantAwareBasicAuthenticationFilter.java | 3 +- .../TenantAwareTenantIdentifierFilter.java | 3 +- 12 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/cob/common/ResetContextTasklet.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/COBBusinessStepServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/cob/COBBusinessStepServiceImpl.java index 33361c4cc..e716c1ac3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/COBBusinessStepServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/COBBusinessStepServiceImpl.java @@ -54,6 +54,7 @@ public class COBBusinessStepServiceImpl implements COBBusinessStepService { businessEventNotifierService.startExternalEventRecording(); for (String businessStep : executionMap.values()) { try { + ThreadLocalContextUtil.setActionContext(ActionContext.COB); COBBusinessStep businessStepBean = (COBBusinessStep) applicationContext.getBean(businessStep); item = businessStepBean.execute(item); } catch (Exception e) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java index 20be30778..160eee62f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java @@ -20,6 +20,8 @@ package org.apache.fineract.cob.common; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.infrastructure.core.domain.ActionContext; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; import org.jetbrains.annotations.NotNull; @@ -43,6 +45,7 @@ public class InitialisationTasklet implements Tasklet { UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, user.getPassword(), new NullAuthoritiesMapper().mapAuthorities(user.getAuthorities())); SecurityContextHolder.getContext().setAuthentication(auth); + ThreadLocalContextUtil.setActionContext(ActionContext.COB); return RepeatStatus.FINISHED; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/common/ResetContextTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/common/ResetContextTasklet.java new file mode 100644 index 000000000..60f51f2ea --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/common/ResetContextTasklet.java @@ -0,0 +1,40 @@ +/** + * 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.common; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.infrastructure.core.domain.ActionContext; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.jetbrains.annotations.NotNull; +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; + +@Slf4j +@RequiredArgsConstructor +public class ResetContextTasklet implements Tasklet { + + @Override + public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull ChunkContext chunkContext) throws Exception { + ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); + return RepeatStatus.FINISHED; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java index 37bf40e51..e3856fd05 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java @@ -26,7 +26,9 @@ import java.util.TreeMap; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.cob.COBBusinessStepService; +import org.apache.fineract.infrastructure.core.domain.ActionContext; import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameter; import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameterRepository; import org.apache.fineract.infrastructure.springbatch.SpringBatchJobConstants; @@ -54,6 +56,7 @@ public class InlineLoanCOBBuildExecutionContextTasklet implements Tasklet, Initi @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { + ThreadLocalContextUtil.setActionContext(ActionContext.COB); TreeMap cobBusinessStepMap = cobBusinessStepService.getCOBBusinessStepMap(LoanCOBBusinessStep.class, LoanCOBConstant.LOAN_COB_JOB_NAME); contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, getLoanIdsFromJobParameters(chunkContext)); diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java index 0a3bd5a33..823675a31 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java @@ -20,6 +20,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.common.ResetContextTasklet; import org.apache.fineract.cob.domain.LoanAccountLockRepository; import org.apache.fineract.cob.listener.ChunkProcessingLoanItemListener; import org.apache.fineract.infrastructure.jobs.service.JobName; @@ -74,7 +75,7 @@ public class LoanCOBWorkerConfiguration { @Bean public Flow flow() { return new FlowBuilder("cobFlow").start(initialisationStep(null)).next(applyLockStep(null)).next(loanBusinessStep(null)) - .build(); + .next(resetContextStep(null)).build(); } @Bean @@ -99,6 +100,12 @@ public class LoanCOBWorkerConfiguration { return localStepBuilderFactory.get("Apply lock - Step:" + partitionName).tasklet(applyLock()).listener(promotionListener()).build(); } + @Bean + @StepScope + public Step resetContextStep(@Value("#{stepExecutionContext['partition']}") String partitionName) { + return localStepBuilderFactory.get("Reset context - Step:" + partitionName).tasklet(resetContext()).build(); + } + @Bean public InitialisationTasklet initialiseContext() { return new InitialisationTasklet(userRepository); @@ -114,6 +121,11 @@ public class LoanCOBWorkerConfiguration { return new ApplyLoanLockTasklet(accountLockRepository); } + @Bean + public ResetContextTasklet resetContext() { + return new ResetContextTasklet(); + } + @Bean @StepScope public LoanItemReader cobWorkerItemReader() { diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java index cbaa5bc0d..71bf56714 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java @@ -19,6 +19,7 @@ package org.apache.fineract.cob.loan; import org.apache.fineract.cob.COBBusinessStepService; +import org.apache.fineract.cob.common.ResetContextTasklet; import org.apache.fineract.cob.domain.LoanAccountLockRepository; import org.apache.fineract.cob.listener.InlineCOBLoanItemListener; import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; @@ -83,7 +84,7 @@ public class LoanInlineCOBConfig { @Bean(name = "loanInlineCOBJob") public Job loanInlineCOBJob() { return jobBuilderFactory.get(LoanCOBConstant.INLINE_LOAN_COB_JOB_NAME) // - .start(inlineCOBBuildExecutionContextStep()).next(inlineLoanCOBStep()) // + .start(inlineCOBBuildExecutionContextStep()).next(inlineLoanCOBStep()).next(inlineCOBResetContextStep()) // .incrementer(new RunIdIncrementer()) // .build(); } @@ -98,6 +99,11 @@ public class LoanInlineCOBConfig { return new InlineCOBLoanItemProcessor(cobBusinessStepService); } + @Bean + public Step inlineCOBResetContextStep() { + return stepBuilderFactory.get("Reset context - Step").tasklet(inlineCOBResetContext()).build(); + } + @Bean public InlineCOBLoanItemWriter inlineCobWorkerItemWriter() { InlineCOBLoanItemWriter repositoryItemWriter = new InlineCOBLoanItemWriter(accountLockRepository); @@ -110,6 +116,11 @@ public class LoanInlineCOBConfig { return new InlineCOBLoanItemListener(accountLockRepository, transactionTemplate); } + @Bean + public ResetContextTasklet inlineCOBResetContext() { + return new ResetContextTasklet(); + } + @Bean public ExecutionContextPromotionListener inlineCobPromotionListener() { ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/ThreadLocalContextUtil.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/ThreadLocalContextUtil.java index fad559f15..fe3f10d54 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/ThreadLocalContextUtil.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/ThreadLocalContextUtil.java @@ -116,4 +116,12 @@ public final class ThreadLocalContextUtil { setBusinessDates(fineractContext.getBusinessDateContext()); setActionContext(fineractContext.getActionContext()); } + + public static void reset() { + contextHolder.remove(); + tenantContext.remove(); + authTokenContext.remove(); + businessDateContext.remove(); + actionContext.remove(); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobSchedulerServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobSchedulerServiceImpl.java index 654efc063..54bdcd437 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobSchedulerServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobSchedulerServiceImpl.java @@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService; import org.apache.fineract.infrastructure.core.config.FineractProperties; +import org.apache.fineract.infrastructure.core.domain.ActionContext; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail; @@ -57,6 +58,7 @@ public class JobSchedulerServiceImpl implements ApplicationListener businessDates = businessDateReadPlatformService.getBusinessDates(); + ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); ThreadLocalContextUtil.setBusinessDates(businessDates); final List scheduledJobDetails = schedularWritePlatformService .retrieveAllJobs(fineractProperties.getNodeId()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobListener.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobListener.java index 8fa314ac1..6f1e412cf 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobListener.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobListener.java @@ -24,6 +24,7 @@ import java.util.HashMap; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService; +import org.apache.fineract.infrastructure.core.domain.ActionContext; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail; import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobRunHistory; @@ -67,6 +68,7 @@ public class SchedulerJobListener implements JobListener { authoritiesMapper.mapAuthorities(user.getAuthorities())); SecurityContextHolder.getContext().setAuthentication(auth); HashMap businessDates = businessDateReadPlatformService.getBusinessDates(); + ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); ThreadLocalContextUtil.setBusinessDates(businessDates); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerTriggerListener.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerTriggerListener.java index 5952f5503..a48910de9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerTriggerListener.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerTriggerListener.java @@ -25,6 +25,7 @@ import java.util.HashMap; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService; +import org.apache.fineract.infrastructure.core.domain.ActionContext; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.security.service.TenantDetailsService; @@ -69,6 +70,7 @@ public class SchedulerTriggerListener implements TriggerListener { final String tenantIdentifier = trigger.getJobDataMap().getString(SchedulerServiceConstants.TENANT_IDENTIFIER); final FineractPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantIdentifier); ThreadLocalContextUtil.setTenant(tenant); + ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); HashMap businessDates = businessDateReadPlatformService.getBusinessDates(); ThreadLocalContextUtil.setBusinessDates(businessDates); final JobKey key = trigger.getJobKey(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java index 4a8c0d494..d9a43c437 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java @@ -103,7 +103,7 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil task.start(); try { - + ThreadLocalContextUtil.reset(); if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { // ignore to allow 'preflight' requests from AJAX applications // in different origin (domain name) @@ -157,6 +157,7 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil response.addHeader("WWW-Authenticate", "Basic realm=\"" + "Fineract Platform API" + "\""); response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); } finally { + ThreadLocalContextUtil.reset(); task.stop(); final PlatformRequestLog log = PlatformRequestLog.from(task, request); LOG.debug("{}", this.toApiJsonSerializer.serialize(log)); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareTenantIdentifierFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareTenantIdentifierFilter.java index 82f6abab8..193538773 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareTenantIdentifierFilter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareTenantIdentifierFilter.java @@ -88,7 +88,7 @@ public class TenantAwareTenantIdentifierFilter extends GenericFilterBean { task.start(); try { - + ThreadLocalContextUtil.reset(); // allows for Cross-Origin // Requests (CORs) to be performed against the platform API. response.setHeader("Access-Control-Allow-Origin", "*"); // NOSONAR @@ -148,6 +148,7 @@ public class TenantAwareTenantIdentifierFilter extends GenericFilterBean { response.addHeader("WWW-Authenticate", "Basic realm=\"" + "Fineract Platform API" + "\""); response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); } finally { + ThreadLocalContextUtil.reset(); task.stop(); final PlatformRequestLog logRequest = PlatformRequestLog.from(task, request); log.debug("{}", this.toApiJsonSerializer.serialize(logRequest));