merging Michael's pull requests around MIFOSX-1184
This commit is contained in:
+12
-9
@@ -19,27 +19,28 @@ import org.springframework.util.ClassUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser to find method which is marked with CronTargetMethod annotation
|
* Parser to find method which is marked with CronTargetMethod annotation
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class CronMethodParser {
|
public class CronMethodParser {
|
||||||
|
|
||||||
|
public static class ClassMethodNamesPair {
|
||||||
|
|
||||||
|
public String className;
|
||||||
|
public String methodName;
|
||||||
|
}
|
||||||
|
|
||||||
private static final String SEARCH_PACKAGE = "org.mifosplatform.";
|
private static final String SEARCH_PACKAGE = "org.mifosplatform.";
|
||||||
|
|
||||||
private static final String CRON_ANNOTATION_ATTRIBUTE_NAME = "jobName";
|
private static final String CRON_ANNOTATION_ATTRIBUTE_NAME = "jobName";
|
||||||
|
|
||||||
private static final String RESOURCE_PATTERN = "**/*.class";
|
private static final String RESOURCE_PATTERN = "**/*.class";
|
||||||
|
|
||||||
private static final Map<String, String[]> targetMethosMap = new HashMap<>();
|
private static final Map<String, ClassMethodNamesPair> targetMethosMap = new HashMap<>();
|
||||||
|
|
||||||
private static final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
private static final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||||
|
|
||||||
private static final MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
private static final MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
||||||
|
|
||||||
public static final int CLASS_INDEX = 0;
|
public static ClassMethodNamesPair findTargetMethodDetails(final String attributeValue) throws IOException {
|
||||||
|
|
||||||
public static final int METHOD_INDEX = 1;
|
|
||||||
|
|
||||||
public static String[] findTargetMethodDetails(final String attributeValue) throws IOException {
|
|
||||||
if (!targetMethosMap.containsKey(attributeValue)) {
|
if (!targetMethosMap.containsKey(attributeValue)) {
|
||||||
findAnnotationMethods(CronTarget.class, CRON_ANNOTATION_ATTRIBUTE_NAME);
|
findAnnotationMethods(CronTarget.class, CRON_ANNOTATION_ATTRIBUTE_NAME);
|
||||||
}
|
}
|
||||||
@@ -66,8 +67,10 @@ public class CronMethodParser {
|
|||||||
final Map<String, Object> attributes = metadata.getAnnotationAttributes(annotationClass.getName());
|
final Map<String, Object> attributes = metadata.getAnnotationAttributes(annotationClass.getName());
|
||||||
final JobName attributeValue = (JobName) attributes.get(attributeName);
|
final JobName attributeValue = (JobName) attributes.get(attributeName);
|
||||||
final String className = metadata.getDeclaringClassName();
|
final String className = metadata.getDeclaringClassName();
|
||||||
final String[] mapVal = { className, metadata.getMethodName() };
|
final ClassMethodNamesPair pair = new ClassMethodNamesPair();
|
||||||
targetMethosMap.put(attributeValue.toString(), mapVal);
|
pair.className = className;
|
||||||
|
pair.methodName = metadata.getMethodName();
|
||||||
|
targetMethosMap.put(attributeValue.toString(), pair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-44
@@ -13,6 +13,7 @@ import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant;
|
|||||||
import org.mifosplatform.infrastructure.core.exception.PlatformInternalServerException;
|
import org.mifosplatform.infrastructure.core.exception.PlatformInternalServerException;
|
||||||
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
import org.mifosplatform.infrastructure.jobs.annotation.CronMethodParser;
|
import org.mifosplatform.infrastructure.jobs.annotation.CronMethodParser;
|
||||||
|
import org.mifosplatform.infrastructure.jobs.annotation.CronMethodParser.ClassMethodNamesPair;
|
||||||
import org.mifosplatform.infrastructure.jobs.domain.ScheduledJobDetail;
|
import org.mifosplatform.infrastructure.jobs.domain.ScheduledJobDetail;
|
||||||
import org.mifosplatform.infrastructure.jobs.domain.SchedulerDetail;
|
import org.mifosplatform.infrastructure.jobs.domain.SchedulerDetail;
|
||||||
import org.mifosplatform.infrastructure.jobs.exception.JobNotFoundException;
|
import org.mifosplatform.infrastructure.jobs.exception.JobNotFoundException;
|
||||||
@@ -38,29 +39,57 @@ import org.springframework.stereotype.Service;
|
|||||||
* Service class to create and load batch jobs to Scheduler using
|
* Service class to create and load batch jobs to Scheduler using
|
||||||
* {@link SchedulerFactoryBean} ,{@link MethodInvokingJobDetailFactoryBean} and
|
* {@link SchedulerFactoryBean} ,{@link MethodInvokingJobDetailFactoryBean} and
|
||||||
* {@link CronTriggerFactoryBean}
|
* {@link CronTriggerFactoryBean}
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class JobRegisterServiceImpl implements JobRegisterService {
|
public class JobRegisterServiceImpl implements JobRegisterService {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(JobRegisterServiceImpl.class);
|
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 ApplicationContext applicationContext;
|
||||||
|
private SchedularWritePlatformService schedularWritePlatformService;
|
||||||
private final TenantDetailsService tenantDetailsService;
|
private TenantDetailsService tenantDetailsService;
|
||||||
|
private SchedulerJobListener schedulerJobListener;
|
||||||
|
private SchedulerStopListener schedulerStopListener;
|
||||||
|
private SchedulerTriggerListener globalSchedulerTriggerListener;
|
||||||
|
|
||||||
private final HashMap<String, Scheduler> schedulers = new HashMap<>(4);
|
private final HashMap<String, Scheduler> schedulers = new HashMap<>(4);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public JobRegisterServiceImpl(final ApplicationContext applicationContext, final SchedularWritePlatformService schedularService,
|
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||||
final TenantDetailsService tenantDetailsService) {
|
|
||||||
this.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;
|
this.tenantDetailsService = tenantDetailsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setSchedulerJobListener(SchedulerJobListener schedulerJobListener) {
|
||||||
|
this.schedulerJobListener = schedulerJobListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setSchedulerStopListener(SchedulerStopListener schedulerStopListener) {
|
||||||
|
this.schedulerStopListener = schedulerStopListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setGlobalTriggerListener(SchedulerTriggerListener globalTriggerListener) {
|
||||||
|
this.globalSchedulerTriggerListener = globalTriggerListener;
|
||||||
|
}
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void loadAllJobs() {
|
public void loadAllJobs() {
|
||||||
final List<MifosPlatformTenant> allTenants = this.tenantDetailsService.findAllTenants();
|
final List<MifosPlatformTenant> allTenants = this.tenantDetailsService.findAllTenants();
|
||||||
@@ -95,10 +124,7 @@ public class JobRegisterServiceImpl implements JobRegisterService {
|
|||||||
if (scheduler == null || !scheduler.checkExists(jobKey)) {
|
if (scheduler == null || !scheduler.checkExists(jobKey)) {
|
||||||
final JobDetail jobDetail = createJobDetail(scheduledJobDetail);
|
final JobDetail jobDetail = createJobDetail(scheduledJobDetail);
|
||||||
final String tempSchedulerName = "temp" + scheduledJobDetail.getId();
|
final String tempSchedulerName = "temp" + scheduledJobDetail.getId();
|
||||||
final List<Class<? extends JobListener>> listenerClasses = new ArrayList<>(2);
|
final Scheduler tempScheduler = createScheduler(tempSchedulerName, 1, schedulerJobListener, schedulerStopListener);
|
||||||
listenerClasses.add(SchedulerJobListener.class);
|
|
||||||
listenerClasses.add(SchedulerStopListener.class);
|
|
||||||
final Scheduler tempScheduler = createScheduler(tempSchedulerName, 1, listenerClasses);
|
|
||||||
tempScheduler.addJob(jobDetail, true);
|
tempScheduler.addJob(jobDetail, true);
|
||||||
jobDataMap.put(SchedulerServiceConstants.SCHEDULER_NAME, tempSchedulerName);
|
jobDataMap.put(SchedulerServiceConstants.SCHEDULER_NAME, tempSchedulerName);
|
||||||
this.schedulers.put(tempSchedulerName, tempScheduler);
|
this.schedulers.put(tempSchedulerName, tempScheduler);
|
||||||
@@ -228,7 +254,7 @@ public class JobRegisterServiceImpl implements JobRegisterService {
|
|||||||
if (scheduledJobDetail.getSchedulerGroup() > 0) {
|
if (scheduledJobDetail.getSchedulerGroup() > 0) {
|
||||||
noOfThreads = SchedulerServiceConstants.GROUP_THREAD_COUNT;
|
noOfThreads = SchedulerServiceConstants.GROUP_THREAD_COUNT;
|
||||||
}
|
}
|
||||||
scheduler = createScheduler(schedulername, noOfThreads, null);
|
scheduler = createScheduler(schedulername, noOfThreads, schedulerJobListener);
|
||||||
this.schedulers.put(schedulername, scheduler);
|
this.schedulers.put(schedulername, scheduler);
|
||||||
}
|
}
|
||||||
return scheduler;
|
return scheduler;
|
||||||
@@ -254,17 +280,11 @@ public class JobRegisterServiceImpl implements JobRegisterService {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Scheduler createScheduler(final String name, final int noOfThreads, List<Class<? extends JobListener>> listenerClasses)
|
private Scheduler createScheduler(final String name, final int noOfThreads, JobListener... jobListeners) throws Exception {
|
||||||
throws Exception {
|
|
||||||
final SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
|
final SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
|
||||||
schedulerFactoryBean.setSchedulerName(name);
|
schedulerFactoryBean.setSchedulerName(name);
|
||||||
if (listenerClasses == null) {
|
schedulerFactoryBean.setGlobalJobListeners(jobListeners);
|
||||||
listenerClasses = new ArrayList<>(1);
|
final TriggerListener[] globalTriggerListeners = { globalSchedulerTriggerListener };
|
||||||
listenerClasses.add(SchedulerJobListener.class);
|
|
||||||
}
|
|
||||||
schedulerFactoryBean.setGlobalJobListeners(getGlobalListener(listenerClasses));
|
|
||||||
final TriggerListener globalTriggerListener = this.applicationContext.getBean("schedulerTriggerListener", TriggerListener.class);
|
|
||||||
final TriggerListener[] globalTriggerListeners = { globalTriggerListener };
|
|
||||||
schedulerFactoryBean.setGlobalTriggerListeners(globalTriggerListeners);
|
schedulerFactoryBean.setGlobalTriggerListeners(globalTriggerListeners);
|
||||||
final Properties quartzProperties = new Properties();
|
final Properties quartzProperties = new Properties();
|
||||||
quartzProperties.put(SchedulerFactoryBean.PROP_THREAD_COUNT, Integer.toString(noOfThreads));
|
quartzProperties.put(SchedulerFactoryBean.PROP_THREAD_COUNT, Integer.toString(noOfThreads));
|
||||||
@@ -274,35 +294,20 @@ public class JobRegisterServiceImpl implements JobRegisterService {
|
|||||||
return schedulerFactoryBean.getScheduler();
|
return schedulerFactoryBean.getScheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JobListener[] getGlobalListener(final List<Class<? extends JobListener>> listenerClasses) throws ClassNotFoundException {
|
|
||||||
final List<JobListener> listeners = new ArrayList<>(listenerClasses.size());
|
|
||||||
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 {
|
private JobDetail createJobDetail(final ScheduledJobDetail scheduledJobDetail) throws Exception {
|
||||||
final MifosPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
|
final MifosPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
|
||||||
final String[] jobDetails = CronMethodParser.findTargetMethodDetails(scheduledJobDetail.getJobName());
|
final ClassMethodNamesPair jobDetails = CronMethodParser.findTargetMethodDetails(scheduledJobDetail.getJobName());
|
||||||
final Object targetObject = getBeanObject(Class.forName(jobDetails[CronMethodParser.CLASS_INDEX]));
|
final Object targetObject = getBeanObject(Class.forName(jobDetails.className));
|
||||||
final MethodInvokingJobDetailFactoryBean jobDetailFactoryBean = new MethodInvokingJobDetailFactoryBean();
|
final MethodInvokingJobDetailFactoryBean jobDetailFactoryBean = new MethodInvokingJobDetailFactoryBean();
|
||||||
jobDetailFactoryBean.setName(scheduledJobDetail.getJobName() + "JobDetail" + tenant.getId());
|
jobDetailFactoryBean.setName(scheduledJobDetail.getJobName() + "JobDetail" + tenant.getId());
|
||||||
jobDetailFactoryBean.setTargetObject(targetObject);
|
jobDetailFactoryBean.setTargetObject(targetObject);
|
||||||
jobDetailFactoryBean.setTargetMethod(jobDetails[CronMethodParser.METHOD_INDEX]);
|
jobDetailFactoryBean.setTargetMethod(jobDetails.methodName);
|
||||||
jobDetailFactoryBean.setGroup(scheduledJobDetail.getGroupName());
|
jobDetailFactoryBean.setGroup(scheduledJobDetail.getGroupName());
|
||||||
jobDetailFactoryBean.setConcurrent(false);
|
jobDetailFactoryBean.setConcurrent(false);
|
||||||
jobDetailFactoryBean.afterPropertiesSet();
|
jobDetailFactoryBean.afterPropertiesSet();
|
||||||
return jobDetailFactoryBean.getObject();
|
return jobDetailFactoryBean.getObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param jobDetails
|
|
||||||
* @return
|
|
||||||
* @throws ClassNotFoundException
|
|
||||||
*/
|
|
||||||
private Object getBeanObject(final Class<?> classType) throws ClassNotFoundException {
|
private Object getBeanObject(final Class<?> classType) throws ClassNotFoundException {
|
||||||
final List<Class<?>> typesList = new ArrayList<>();
|
final List<Class<?>> typesList = new ArrayList<>();
|
||||||
final Class<?>[] interfaceType = classType.getInterfaces();
|
final Class<?>[] interfaceType = classType.getInterfaces();
|
||||||
@@ -332,10 +337,6 @@ public class JobRegisterServiceImpl implements JobRegisterService {
|
|||||||
return targetObject;
|
return targetObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param scheduledJobDetails
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Trigger createTrigger(final ScheduledJobDetail scheduledJobDetails, final JobDetail jobDetail) {
|
private Trigger createTrigger(final ScheduledJobDetail scheduledJobDetails, final JobDetail jobDetail) {
|
||||||
final MifosPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
|
final MifosPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
|
||||||
final CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
|
final CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
|
||||||
|
|||||||
+8
-2
@@ -15,10 +15,16 @@ public class SchedulerStopListener implements JobListener {
|
|||||||
|
|
||||||
private static final String name = "Singlr Trigger Global Listner";
|
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
|
@Autowired
|
||||||
public SchedulerStopListener(final JobRegisterService jobRegisterService) {
|
public void setJobRegisterService(JobRegisterService jobRegisterService) {
|
||||||
this.jobRegisterService = jobRegisterService;
|
this.jobRegisterService = jobRegisterService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user