diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java index 14ee53f70..3bd5b2fc2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobRegisterServiceImpl.java @@ -22,7 +22,6 @@ import com.google.common.base.Splitter; import java.text.ParseException; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Properties; import java.util.TimeZone; import lombok.extern.slf4j.Slf4j; @@ -30,8 +29,6 @@ import org.apache.fineract.infrastructure.core.config.FineractProperties; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.exception.PlatformInternalServerException; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; -import org.apache.fineract.infrastructure.jobs.domain.JobParameter; -import org.apache.fineract.infrastructure.jobs.domain.JobParameterRepository; import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail; import org.apache.fineract.infrastructure.jobs.domain.SchedulerDetail; import org.apache.fineract.infrastructure.jobs.exception.JobNodeIdMismatchingException; @@ -45,11 +42,7 @@ import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerListener; import org.springframework.batch.core.Job; -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.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; @@ -75,12 +68,6 @@ public class JobRegisterServiceImpl implements JobRegisterService, ApplicationLi @Autowired private SchedulerTriggerListener globalSchedulerTriggerListener; - @Autowired - private JobParameterRepository jobParameterRepository; - - @Autowired - private JobExplorer jobExplorer; - private final HashMap schedulers = new HashMap<>(4); // This cannot be injected as Autowired due to circular dependency @@ -89,13 +76,13 @@ public class JobRegisterServiceImpl implements JobRegisterService, ApplicationLi @Autowired private FineractProperties fineractProperties; - @Autowired - private JobLauncher jobLauncher; - @Autowired private JobLocator jobLocator; - private static final String JOB_LAUNCHER_STARTER_METHOD_NAME = "run"; + @Autowired + private JobStarter jobStarter; + + private static final String JOB_STARTER_METHOD_NAME = "run"; public void executeJob(final ScheduledJobDetail scheduledJobDetail, String triggerType) { try { @@ -332,30 +319,16 @@ public class JobRegisterServiceImpl implements JobRegisterService, ApplicationLi final MethodInvokingJobDetailFactoryBean jobDetailFactoryBean = new MethodInvokingJobDetailFactoryBean(); jobDetailFactoryBean.setName(scheduledJobDetail.getJobName() + "JobDetail" + tenant.getId()); - jobDetailFactoryBean.setTargetObject(jobLauncher); - jobDetailFactoryBean.setTargetMethod(JOB_LAUNCHER_STARTER_METHOD_NAME); + jobDetailFactoryBean.setTargetObject(jobStarter); + jobDetailFactoryBean.setTargetMethod(JOB_STARTER_METHOD_NAME); jobDetailFactoryBean.setGroup(scheduledJobDetail.getGroupName()); jobDetailFactoryBean.setConcurrent(false); - Map jobParameterMap = getJobParameter(scheduledJobDetail); - JobParameters jobParameters = new JobParametersBuilder(jobExplorer).getNextJobParameters(job) - .addJobParameters(new JobParameters(jobParameterMap)).toJobParameters(); - - jobDetailFactoryBean.setArguments(job, jobParameters); + jobDetailFactoryBean.setArguments(job, scheduledJobDetail); jobDetailFactoryBean.afterPropertiesSet(); return jobDetailFactoryBean.getObject(); } - public Map getJobParameter(ScheduledJobDetail scheduledJobDetail) { - List jobParameterList = jobParameterRepository.findJobParametersByJobId(scheduledJobDetail.getId()); - Map jobParameterMap = new HashMap<>(); - for (JobParameter jobparameter : jobParameterList) { - jobParameterMap.put(jobparameter.getParameterName(), - new org.springframework.batch.core.JobParameter(jobparameter.getParameterValue())); - } - return jobParameterMap; - } - private Trigger createTrigger(final ScheduledJobDetail scheduledJobDetails, final JobDetail jobDetail) throws ParseException { final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant(); final CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobStarter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobStarter.java new file mode 100644 index 000000000..556e6b4b0 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobStarter.java @@ -0,0 +1,64 @@ +/** + * 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.HashMap; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.jobs.domain.JobParameterRepository; +import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParameter; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.JobParametersInvalidException; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; +import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; +import org.springframework.batch.core.repository.JobRestartException; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class JobStarter { + + private final JobExplorer jobExplorer; + private final JobLauncher jobLauncher; + private final JobParameterRepository jobParameterRepository; + + public void run(Job job, ScheduledJobDetail scheduledJobDetail) throws JobInstanceAlreadyCompleteException, + JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException { + Map jobParameterMap = getJobParameter(scheduledJobDetail); + JobParameters jobParameters = new JobParametersBuilder(jobExplorer).getNextJobParameters(job) + .addJobParameters(new JobParameters(jobParameterMap)).toJobParameters(); + jobLauncher.run(job, jobParameters); + } + + public Map getJobParameter(ScheduledJobDetail scheduledJobDetail) { + List jobParameterList = jobParameterRepository + .findJobParametersByJobId(scheduledJobDetail.getId()); + Map jobParameterMap = new HashMap<>(); + for (org.apache.fineract.infrastructure.jobs.domain.JobParameter jobParameter : jobParameterList) { + jobParameterMap.put(jobParameter.getParameterName(), new JobParameter(jobParameter.getParameterValue())); + } + return jobParameterMap; + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java index 4d13b606d..3d30b193b 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java +++ b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java @@ -38,8 +38,13 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; +import org.springframework.batch.core.configuration.ListableJobLocator; +import org.springframework.batch.core.configuration.annotation.BatchConfigurer; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobRepository; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @@ -93,6 +98,18 @@ public class TestConfiguration { return mock(JobBuilderFactory.class, RETURNS_MOCKS); } + @Primary + @Bean + public JobExplorer jobExplorer() { + return mock(JobExplorer.class, RETURNS_MOCKS); + } + + @Primary + @Bean + public JobLauncher jobLauncher() { + return mock(JobLauncher.class, RETURNS_MOCKS); + } + @Primary @Bean public StepBuilderFactory stepBuilderFactory() { @@ -161,4 +178,22 @@ public class TestConfiguration { public JdbcTemplate jdbcTemplate() { return mock(JdbcTemplate.class); } + + @Primary + @Bean + public BatchConfigurer batchConfigurer() { + return mock(BatchConfigurer.class, RETURNS_MOCKS); + } + + @Primary + @Bean + public ListableJobLocator listableJobLocator() { + return mock(ListableJobLocator.class, RETURNS_MOCKS); + } + + @Primary + @Bean + public JobRepository jobRepository() { + return mock(JobRepository.class, RETURNS_MOCKS); + } }