All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aspectran.core.scheduler.service.QuartzSchedulerService Maven / Gradle / Ivy

There is a newer version: 8.1.5
Show newest version
/*
 * Copyright (c) 2008-2023 The Aspectran Project
 *
 * Licensed 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 com.aspectran.core.scheduler.service;

import com.aspectran.core.component.schedule.ScheduleRuleRegistry;
import com.aspectran.core.context.ActivityContext;
import com.aspectran.core.context.rule.ScheduleRule;
import com.aspectran.core.context.rule.ScheduledJobRule;
import com.aspectran.core.context.rule.params.TriggerExpressionParameters;
import com.aspectran.core.context.rule.type.TriggerType;
import com.aspectran.core.service.AbstractServiceController;
import com.aspectran.core.service.CoreService;
import com.aspectran.core.util.logging.Logger;
import com.aspectran.core.util.logging.LoggerFactory;
import com.aspectran.core.util.wildcard.PluralWildcardPattern;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobListener;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.matchers.GroupMatcher;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * The Class QuartzSchedulerService.
 */
public class QuartzSchedulerService extends AbstractServiceController implements SchedulerService {

    private static final Logger logger = LoggerFactory.getLogger(QuartzSchedulerService.class);

    static final String SERVICE_DATA_KEY = "SERVICE";

    static final String JOB_RULE_DATA_KEY = "JOB_RULE";

    private final Set schedulerSet = new HashSet<>();

    private final Map schedulerMap = new HashMap<>();

    private final CoreService coreService;

    private int startDelaySeconds = 0;

    private boolean waitOnShutdown = false;

    private PluralWildcardPattern exposableTransletNamesPattern;

    public QuartzSchedulerService(CoreService coreService) {
        super(false);
        this.coreService = coreService;
    }

    @Override
    public int getStartDelaySeconds() {
        return startDelaySeconds;
    }

    public void setStartDelaySeconds(int startDelaySeconds) {
        this.startDelaySeconds = startDelaySeconds;
    }

    @Override
    public boolean isWaitOnShutdown() {
        return waitOnShutdown;
    }

    public void setWaitOnShutdown(boolean waitOnShutdown) {
        this.waitOnShutdown = waitOnShutdown;
    }

    public void setExposals(String[] includePatterns, String[] excludePatterns) {
        if ((includePatterns != null && includePatterns.length > 0) ||
                excludePatterns != null && excludePatterns.length > 0) {
            exposableTransletNamesPattern = new PluralWildcardPattern(includePatterns, excludePatterns,
                    ActivityContext.NAME_SEPARATOR_CHAR);
        }
    }

    private boolean isExposable(String transletName) {
        return (exposableTransletNamesPattern == null || exposableTransletNamesPattern.matches(transletName));
    }

    @Override
    public boolean isDerived() {
        return false;
    }

    @Override
    protected void doStart() throws Exception {
        startSchedulerService();
    }

    @Override
    protected void doPause() throws Exception {
        try {
            for (Scheduler scheduler : schedulerSet) {
                scheduler.pauseAll();
            }
        } catch (Exception e) {
            throw new SchedulerServiceException("Could not pause all schedulers", e);
        }
    }

    @Override
    protected void doPause(long timeout) throws Exception {
        logger.warn(getServiceName() + " does not support pausing for a certain period of time");
    }

    @Override
    protected void doResume() throws Exception {
        try {
            for (Scheduler scheduler : schedulerSet) {
                scheduler.resumeAll();
            }
        } catch (Exception e) {
            throw new SchedulerServiceException("Could not resume all schedulers", e);
        }
    }

    @Override
    protected void doStop() throws Exception {
        stopSchedulerService();
    }

    @Override
    public ActivityContext getActivityContext() {
        return coreService.getActivityContext();
    }

    private void startSchedulerService() throws SchedulerServiceException {
        ScheduleRuleRegistry scheduleRuleRegistry = getActivityContext().getScheduleRuleRegistry();
        if (scheduleRuleRegistry == null) {
            return;
        }

        Collection scheduleRules = scheduleRuleRegistry.getScheduleRules();
        if (scheduleRules == null || scheduleRules.isEmpty()) {
            return;
        }

        logger.info("Now try to starting QuartzSchedulerService");

        try {
            for (ScheduleRule scheduleRule : scheduleRules) {
                Scheduler scheduler = buildScheduler((scheduleRule));
                schedulerSet.add(scheduler);
                schedulerMap.put(scheduleRule.getId(), scheduler);
            }

            for (Scheduler scheduler : schedulerSet) {
                logger.info("Starting scheduler '" + scheduler.getSchedulerName() + "'");

                // Listener attached to jobKey
                JobListener defaultJobListener = new QuartzJobListener();
                scheduler.getListenerManager().addJobListener(defaultJobListener);

                if (startDelaySeconds > 0) {
                    scheduler.startDelayed(startDelaySeconds);
                } else {
                    scheduler.start();
                }
            }
        } catch (Exception e) {
            throw new SchedulerServiceException("Could not start QuartzSchedulerService", e);
        }
    }

    private void stopSchedulerService() throws SchedulerServiceException {
        logger.info("Now try to shutting down QuartzSchedulerService");

        try {
            for (Scheduler scheduler : schedulerSet) {
                if (!scheduler.isShutdown()) {
                    logger.info("Shutting down the scheduler '" + scheduler.getSchedulerName() +
                            "' with waitForJobsToComplete=" + waitOnShutdown);
                    scheduler.shutdown(waitOnShutdown);
                }
            }
            schedulerSet.clear();
            schedulerMap.clear();
        } catch (Exception e) {
            throw new SchedulerServiceException("Could not shutdown QuartzSchedulerService", e);
        }
    }

    public void pause(String scheduleId) throws SchedulerServiceException {
        synchronized (getLock()) {
            try {
                Scheduler scheduler = getScheduler(scheduleId);
                if (scheduler != null && scheduler.isStarted()) {
                    scheduler.pauseJobs(GroupMatcher.jobGroupEquals(scheduleId));
                }
            } catch (Exception e) {
                throw new SchedulerServiceException("Could not pause scheduler '" + scheduleId + "'", e);
            }
        }
    }

    public synchronized void resume(String scheduleId) throws SchedulerServiceException {
        synchronized (getLock()) {
            try {
                Scheduler scheduler = getScheduler(scheduleId);
                if (scheduler != null && scheduler.isStarted()) {
                    scheduler.resumeJobs(GroupMatcher.jobGroupEquals(scheduleId));
                }
            } catch (Exception e) {
                throw new SchedulerServiceException("Could not resume scheduler '" + scheduleId + "'", e);
            }
        }
    }

    private Scheduler getScheduler(String scheduleId) {
        return schedulerMap.get(scheduleId);
    }

    private Scheduler buildScheduler(ScheduleRule scheduleRule) throws SchedulerException {
        Scheduler scheduler = null;
        if (scheduleRule.getSchedulerBeanClass() != null) {
            scheduler = (Scheduler)getActivityContext().getBeanRegistry().getBean(scheduleRule.getSchedulerBeanClass());
        } else if (scheduleRule.getSchedulerBeanId() != null) {
            scheduler = getActivityContext().getBeanRegistry().getBean(scheduleRule.getSchedulerBeanId());
        }
        if (scheduler == null) {
            throw new SchedulerServiceException("No such scheduler bean; Invalid ScheduleRule " + scheduleRule);
        }

        List jobRuleList = scheduleRule.getScheduledJobRuleList();
        for (ScheduledJobRule jobRule : jobRuleList) {
            if (isExposable(jobRule.getTransletName())) {
                JobDetail jobDetail = buildJobDetail(jobRule);
                if (jobDetail != null) {
                    String triggerName = jobDetail.getKey().getName();
                    String triggerGroup = scheduleRule.getId();
                    Trigger trigger = buildTrigger(triggerName, triggerGroup, scheduleRule);
                    scheduler.scheduleJob(jobDetail, trigger);
                }
            } else {
                logger.warn("Unavailable translet [" + jobRule.getTransletName() + "] in ScheduleRule " + scheduleRule);
            }
        }

        return scheduler;
    }

    private JobDetail buildJobDetail(ScheduledJobRule jobRule) {
        String jobName = jobRule.getTransletName();
        String jobGroup = jobRule.getScheduleRule().getId();

        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put(SERVICE_DATA_KEY, this);
        jobDataMap.put(JOB_RULE_DATA_KEY, jobRule);

        return JobBuilder.newJob(ActivityLauncherJob.class)
                .withIdentity(jobName, jobGroup)
                .setJobData(jobDataMap)
                .build();
    }

    private Trigger buildTrigger(String name, String group, ScheduleRule scheduleRule) {
        TriggerExpressionParameters expressionParameters = scheduleRule.getTriggerExpressionParameters();
        int startDelaySeconds = this.startDelaySeconds;
        if (expressionParameters.getStartDelaySeconds() != null) {
            startDelaySeconds += expressionParameters.getStartDelaySeconds();
        }

        Date firstFireTime;
        if (startDelaySeconds > 0) {
            firstFireTime = new Date(System.currentTimeMillis() + (startDelaySeconds * 1000L));
        } else {
            firstFireTime = new Date();
        }

        if (scheduleRule.getTriggerType() == TriggerType.SIMPLE) {
            Long intervalInMilliseconds = expressionParameters.getIntervalInMilliseconds();
            Integer intervalInSeconds = expressionParameters.getIntervalInSeconds();
            Integer intervalInMinutes = expressionParameters.getIntervalInMinutes();
            Integer intervalInHours = expressionParameters.getIntervalInHours();
            Integer repeatCount = expressionParameters.getRepeatCount();
            Boolean repeatForever = expressionParameters.getRepeatForever();

            SimpleScheduleBuilder builder = SimpleScheduleBuilder.simpleSchedule();
            if (intervalInMilliseconds != null) {
                builder.withIntervalInMilliseconds(intervalInMilliseconds);
            }
            if (intervalInSeconds != null) {
                builder.withIntervalInSeconds(intervalInSeconds);
            }
            if (intervalInMinutes != null) {
                builder.withIntervalInMinutes(intervalInMinutes);
            }
            if (intervalInHours != null) {
                builder.withIntervalInHours(intervalInHours);
            }
            if (repeatCount != null) {
                builder.withRepeatCount(repeatCount);
            }
            if (Boolean.TRUE.equals(repeatForever)) {
                builder.repeatForever();
            }

            return TriggerBuilder.newTrigger()
                    .withIdentity(name, group)
                    .startAt(firstFireTime)
                    .withSchedule(builder)
                    .build();
        } else {
            String expression = expressionParameters.getExpression();
            CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(expression);

            return TriggerBuilder.newTrigger()
                    .withIdentity(name, group)
                    .startAt(firstFireTime)
                    .withSchedule(cronSchedule)
                    .build();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy