FINERACT-1787: Fineract using wrong business date due to lack of resetting the ActionContext

This commit is contained in:
Adam Saghy
2022-10-27 15:39:23 +02:00
committed by Arnold Gálovics
parent a293dee55c
commit e76adfbe56
12 changed files with 90 additions and 4 deletions
@@ -54,6 +54,7 @@ public class COBBusinessStepServiceImpl implements COBBusinessStepService {
businessEventNotifierService.startExternalEventRecording();
for (String businessStep : executionMap.values()) {
try {
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
COBBusinessStep<S> businessStepBean = (COBBusinessStep<S>) applicationContext.getBean(businessStep);
item = businessStepBean.execute(item);
} catch (Exception e) {
@@ -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;
}
}
@@ -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;
}
}
@@ -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<Long, String> cobBusinessStepMap = cobBusinessStepService.getCOBBusinessStepMap(LoanCOBBusinessStep.class,
LoanCOBConstant.LOAN_COB_JOB_NAME);
contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, getLoanIdsFromJobParameters(chunkContext));
@@ -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<Flow>("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() {
@@ -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();
@@ -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();
}
}
@@ -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<ContextRefre
for (final FineractPlatformTenant tenant : allTenants) {
ThreadLocalContextUtil.setTenant(tenant);
HashMap<BusinessDateType, LocalDate> businessDates = businessDateReadPlatformService.getBusinessDates();
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
ThreadLocalContextUtil.setBusinessDates(businessDates);
final List<ScheduledJobDetail> scheduledJobDetails = schedularWritePlatformService
.retrieveAllJobs(fineractProperties.getNodeId());
@@ -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<BusinessDateType, LocalDate> businessDates = businessDateReadPlatformService.getBusinessDates();
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
ThreadLocalContextUtil.setBusinessDates(businessDates);
}
@@ -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<BusinessDateType, LocalDate> businessDates = businessDateReadPlatformService.getBusinessDates();
ThreadLocalContextUtil.setBusinessDates(businessDates);
final JobKey key = trigger.getJobKey();
@@ -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));
@@ -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));