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

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

There is a newer version: 8.1.5
Show newest version
/*
 * Copyright (c) 2008-2025 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.config.AcceptableConfig;
import com.aspectran.core.context.config.SchedulerConfig;
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.AbstractServiceLifeCycle;
import com.aspectran.core.service.CoreService;
import com.aspectran.core.service.RequestAcceptor;
import com.aspectran.utils.Assert;
import com.aspectran.utils.annotation.jsr305.NonNull;
import com.aspectran.utils.logging.Logger;
import com.aspectran.utils.logging.LoggerFactory;
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 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 AbstractSchedulerService.
 */
public abstract class AbstractSchedulerService extends AbstractServiceLifeCycle implements SchedulerService {

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

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

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

    private int startDelaySeconds = 0;

    private boolean waitOnShutdown = false;

    private RequestAcceptor requestAcceptor;

    AbstractSchedulerService(CoreService parentService) {
        super(parentService);
        Assert.notNull(parentService, "parentService must not be null");
    }

    @Override
    public ActivityContext getActivityContext() {
        Assert.state(getParentService().getActivityContext() != null,
                "No ActivityContext configured yet");
        return getParentService().getActivityContext();
    }

    @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;
    }

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

    public boolean isAcceptable(String requestName) {
        return (requestAcceptor == null || requestAcceptor.isAcceptable(requestName));
    }

    protected void setRequestAcceptor(RequestAcceptor requestAcceptor) {
        this.requestAcceptor = requestAcceptor;
    }

    protected Set getSchedulers() {
        return schedulers;
    }

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

    private void addScheduler(String scheduleId, Scheduler scheduler) {
        Assert.notNull(scheduler, "scheduler must not be null");
        schedulers.add(scheduler);
        schedulerMap.put(scheduleId, scheduler);
    }

    private void clearSchedulers() {
        schedulers.clear();
        schedulerMap.clear();
    }

    @Override
    protected void doStart() throws Exception {
        try {
            buildSchedulers();
            for (Scheduler scheduler : getSchedulers()) {
                logger.info("Starting scheduler '" + scheduler.getSchedulerName() + "'");

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

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

    @Override
    protected void doStop() throws Exception {
        try {
            for (Scheduler scheduler : getSchedulers()) {
                if (!scheduler.isShutdown()) {
                    logger.info("Shutting down the scheduler '" + scheduler.getSchedulerName() +
                            "' with waitForJobsToComplete=" + isWaitOnShutdown());
                    scheduler.shutdown(isWaitOnShutdown());
                }
            }
            clearSchedulers();
        } catch (Exception e) {
            throw new SchedulerServiceException("Could not shutdown DefaultSchedulerService", e);
        }
    }

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

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

        try {
            for (ScheduleRule scheduleRule : scheduleRules) {
                Scheduler scheduler = createScheduler(scheduleRule);
                addScheduler(scheduleRule.getId(), scheduler);
            }
        } catch (Exception e) {
            throw new SchedulerServiceException("Could not start DefaultSchedulerService", e);
        }
    }

    @NonNull
    private Scheduler createScheduler(@NonNull 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 (isAcceptable(jobRule.getTransletName())) {
                JobDetail jobDetail = createJobDetail(jobRule);
                if (jobDetail != null) {
                    String triggerName = jobDetail.getKey().getName();
                    String triggerGroup = scheduleRule.getId();
                    Trigger trigger = createTrigger(triggerName, triggerGroup, scheduleRule, getStartDelaySeconds());
                    scheduler.scheduleJob(jobDetail, trigger);
                }
            } else {
                logger.warn("Unexposed translet [" + jobRule.getTransletName() + "] in ScheduleRule " + scheduleRule);
            }
        }

        return scheduler;
    }

    private JobDetail createJobDetail(@NonNull 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 createTrigger(String name, String group, @NonNull ScheduleRule scheduleRule, final int startDelaySeconds) {
        TriggerExpressionParameters expressionParameters = scheduleRule.getTriggerExpressionParameters();
        int startDelaySecondsToUse = startDelaySeconds;
        if (expressionParameters.getStartDelaySeconds() != null) {
            startDelaySecondsToUse += expressionParameters.getStartDelaySeconds();
        }

        Date firstFireTime;
        if (startDelaySecondsToUse > 0) {
            firstFireTime = new Date(System.currentTimeMillis() + (startDelaySecondsToUse * 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();
        }
    }

    protected void configure(@NonNull SchedulerConfig schedulerConfig) {
        int startDelaySeconds = schedulerConfig.getStartDelaySeconds();
        if (startDelaySeconds == -1) {
            startDelaySeconds = 3;
            if (logger.isDebugEnabled()) {
                logger.debug("Scheduler option 'startDelaySeconds' is not specified, defaulting to 3 seconds");
            }
        }

        boolean waitOnShutdown = schedulerConfig.isWaitOnShutdown();
        if (waitOnShutdown) {
            setWaitOnShutdown(true);
        }
        setStartDelaySeconds(startDelaySeconds);

        AcceptableConfig acceptableConfig = schedulerConfig.getAcceptableConfig();
        if (acceptableConfig != null) {
            setRequestAcceptor(new RequestAcceptor(acceptableConfig));
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy