From 226439bef1399eb99d2b7c5ee3b1ca3741acdfec Mon Sep 17 00:00:00 2001 From: Michael Vorburger Date: Sun, 11 May 2014 01:48:49 +0200 Subject: [PATCH] MIFOSX-1184 FIXED JobRegisterServiceImpl <-> SchedulerStopListener circular bean dependency --- .../jobs/service/JobRegisterServiceImpl.java | 60 +++++++++++-------- .../jobs/service/SchedulerStopListener.java | 10 +++- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/jobs/service/JobRegisterServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/jobs/service/JobRegisterServiceImpl.java index c71a58247..10a40d49d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/jobs/service/JobRegisterServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/jobs/service/JobRegisterServiceImpl.java @@ -38,29 +38,50 @@ import org.springframework.stereotype.Service; * Service class to create and load batch jobs to Scheduler using * {@link SchedulerFactoryBean} ,{@link MethodInvokingJobDetailFactoryBean} and * {@link CronTriggerFactoryBean} - * */ @Service public class JobRegisterServiceImpl implements JobRegisterService { - private final static Logger logger = LoggerFactory.getLogger(JobRegisterServiceImpl.class); - private final ApplicationContext applicationContext; + // MIFOSX-1184: This class cannot use constructor injection, because one of + // its dependencies (SchedulerStopListener) has a circular dependency to + // itself. So, slightly differently from how it's done elsewhere in this + // code base, the following fields are not final, and there is no + // constructor, but setters. - private final SchedularWritePlatformService schedularWritePlatformService; - - private final TenantDetailsService tenantDetailsService; + private ApplicationContext applicationContext; + private SchedularWritePlatformService schedularWritePlatformService; + private TenantDetailsService tenantDetailsService; + private SchedulerJobListener schedulerJobListener; + private SchedulerStopListener schedulerStopListener; private final HashMap schedulers = new HashMap(4); @Autowired - public JobRegisterServiceImpl(final ApplicationContext applicationContext, final SchedularWritePlatformService schedularService, - final TenantDetailsService tenantDetailsService) { + public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; - this.schedularWritePlatformService = schedularService; + } + + @Autowired + public void setSchedularWritePlatformService(SchedularWritePlatformService schedularWritePlatformService) { + this.schedularWritePlatformService = schedularWritePlatformService; + } + + @Autowired + public void setTenantDetailsService(TenantDetailsService tenantDetailsService) { this.tenantDetailsService = tenantDetailsService; } + @Autowired + public void setSchedulerJobListener(SchedulerJobListener schedulerJobListener) { + this.schedulerJobListener = schedulerJobListener; + } + + @Autowired + public void setSchedulerStopListener(SchedulerStopListener schedulerStopListener) { + this.schedulerStopListener = schedulerStopListener; + } + @PostConstruct public void loadAllJobs() { final List allTenants = this.tenantDetailsService.findAllTenants(); @@ -95,9 +116,7 @@ public class JobRegisterServiceImpl implements JobRegisterService { if (scheduler == null || !scheduler.checkExists(jobKey)) { final JobDetail jobDetail = createJobDetail(scheduledJobDetail); final String tempSchedulerName = "temp" + scheduledJobDetail.getId(); - @SuppressWarnings("unchecked") - final Scheduler tempScheduler = createScheduler(tempSchedulerName, 1, SchedulerJobListener.class, - SchedulerStopListener.class); + final Scheduler tempScheduler = createScheduler(tempSchedulerName, 1, schedulerJobListener, schedulerStopListener); tempScheduler.addJob(jobDetail, true); jobDataMap.put(SchedulerServiceConstants.SCHEDULER_NAME, tempSchedulerName); this.schedulers.put(tempSchedulerName, tempScheduler); @@ -219,7 +238,6 @@ public class JobRegisterServiceImpl implements JobRegisterService { scheduledJobDetails.updateCurrentlyRunningStatus(false); } - @SuppressWarnings("unchecked") private Scheduler getScheduler(final ScheduledJobDetail scheduledJobDetail) throws Exception { final String schedulername = getSchedulerName(scheduledJobDetail); Scheduler scheduler = this.schedulers.get(schedulername); @@ -228,7 +246,7 @@ public class JobRegisterServiceImpl implements JobRegisterService { if (scheduledJobDetail.getSchedulerGroup() > 0) { noOfThreads = SchedulerServiceConstants.GROUP_THREAD_COUNT; } - scheduler = createScheduler(schedulername, noOfThreads, SchedulerJobListener.class); + scheduler = createScheduler(schedulername, noOfThreads, schedulerJobListener); this.schedulers.put(schedulername, scheduler); } return scheduler; @@ -254,11 +272,11 @@ public class JobRegisterServiceImpl implements JobRegisterService { return sb.toString(); } - private Scheduler createScheduler(final String name, final int noOfThreads, Class... listenerClasses) + private Scheduler createScheduler(final String name, final int noOfThreads, JobListener... jobListeners) throws Exception { final SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setSchedulerName(name); - schedulerFactoryBean.setGlobalJobListeners(getGlobalListeners(listenerClasses)); + schedulerFactoryBean.setGlobalJobListeners(jobListeners); final TriggerListener globalTriggerListener = this.applicationContext.getBean("schedulerTriggerListener", TriggerListener.class); final TriggerListener[] globalTriggerListeners = { globalTriggerListener }; schedulerFactoryBean.setGlobalTriggerListeners(globalTriggerListeners); @@ -270,16 +288,6 @@ public class JobRegisterServiceImpl implements JobRegisterService { return schedulerFactoryBean.getScheduler(); } - private JobListener[] getGlobalListeners(final Class[] listenerClasses) throws ClassNotFoundException { - final List listeners = new ArrayList(listenerClasses.length); - for (final Class listenerClass : listenerClasses) { - final JobListener listener = (JobListener) getBeanObject(listenerClass); - listeners.add(listener); - } - final JobListener[] listenerArray = new JobListener[listeners.size()]; - return listeners.toArray(listenerArray); - } - private JobDetail createJobDetail(final ScheduledJobDetail scheduledJobDetail) throws Exception { final MifosPlatformTenant tenant = ThreadLocalContextUtil.getTenant(); final String[] jobDetails = CronMethodParser.findTargetMethodDetails(scheduledJobDetail.getJobName()); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/jobs/service/SchedulerStopListener.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/jobs/service/SchedulerStopListener.java index 1b3a80135..881c917d7 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/jobs/service/SchedulerStopListener.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/jobs/service/SchedulerStopListener.java @@ -15,10 +15,16 @@ public class SchedulerStopListener implements JobListener { private static final String name = "Singlr Trigger Global Listner"; - private final JobRegisterService jobRegisterService; + // MIFOSX-1184: This class cannot use constructor injection, because one of + // its dependencies (SchedulerStopListener) has a circular dependency to + // itself. So, slightly differently from how it's done elsewhere in this + // code base, the following fields are not final, and there is no + // constructor, but setters. + + private JobRegisterService jobRegisterService; @Autowired - public SchedulerStopListener(final JobRegisterService jobRegisterService) { + public void setJobRegisterService(JobRegisterService jobRegisterService) { this.jobRegisterService = jobRegisterService; }