com.aionlightning.commons.services.CronService.java Source code

Java tutorial

Introduction

Here is the source code for com.aionlightning.commons.services.CronService.java

Source

/**
 * This file is part of aion-lightning <aion-lightning.org>.
 * 
 * aion-lightning is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * aion-lightning is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with aion-lightning.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionlightning.commons.services;

import com.aionlightning.commons.services.cron.CronServiceException;
import com.aionlightning.commons.services.cron.RunnableRunner;
import com.aionlightning.commons.utils.GenericValidator;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;

/**
 * @author SoulKeeper
 */
public final class CronService {

    private static final Logger log = LoggerFactory.getLogger(CronService.class);

    /**
     * We really should use some dependency injection (Spring?)<br>
     * Current code is bloated, should be much cleaner
     */
    private static CronService instance;

    private Scheduler scheduler;

    private Class<? extends RunnableRunner> runnableRunner;

    public static CronService getInstance() {
        return instance;
    }

    public static synchronized void initSingleton(Class<? extends RunnableRunner> runableRunner) {
        if (instance != null) {
            throw new CronServiceException("CronService is already initialized");
        }

        CronService cs = new CronService();
        cs.init(runableRunner);
        instance = cs;
    }

    /**
     * Empty private constructor to prevent initialization.<br>
     * Can be instantiated using reflection (for tests), but no real use for application please!
     */
    private CronService() {

    }

    public synchronized void init(Class<? extends RunnableRunner> runnableRunner) {

        if (scheduler != null) {
            return;
        }

        if (runnableRunner == null) {
            throw new CronServiceException("RunnableRunner class must be defined");
        }

        this.runnableRunner = runnableRunner;

        Properties properties = new Properties();
        properties.setProperty("org.quartz.threadPool.threadCount", "1");

        try {
            scheduler = new StdSchedulerFactory(properties).getScheduler();
            scheduler.start();
        } catch (SchedulerException e) {
            throw new CronServiceException("Failed to initialize CronService", e);
        }
    }

    public void shutdown() {

        Scheduler localScheduler;
        synchronized (this) {
            if (scheduler == null) {
                return;
            }

            localScheduler = scheduler;
            scheduler = null;
            runnableRunner = null;
        }

        try {
            localScheduler.shutdown(false);
        } catch (SchedulerException e) {
            log.error("Failed to shutdown CronService correctly", e);
        }
    }

    public void schedule(Runnable r, String cronExpression) {
        schedule(r, cronExpression, false);
    }

    public void schedule(Runnable r, String cronExpression, boolean longRunning) {
        try {
            JobDataMap jdm = new JobDataMap();
            jdm.put(RunnableRunner.KEY_RUNNABLE_OBJECT, r);
            jdm.put(RunnableRunner.KEY_PROPERTY_IS_LONGRUNNING_TASK, longRunning);
            jdm.put(RunnableRunner.KEY_CRON_EXPRESSION, cronExpression);

            String jobId = "Started at ms" + System.currentTimeMillis() + "; ns" + System.nanoTime();
            JobKey jobKey = new JobKey("JobKey:" + jobId);
            JobDetail jobDetail = JobBuilder.newJob(runnableRunner).usingJobData(jdm).withIdentity(jobKey).build();

            CronScheduleBuilder csb = CronScheduleBuilder.cronSchedule(cronExpression);
            CronTrigger trigger = TriggerBuilder.newTrigger().withSchedule(csb).build();

            scheduler.scheduleJob(jobDetail, trigger);
        } catch (Exception e) {
            throw new CronServiceException("Failed to start job", e);
        }
    }

    public void cancel(Runnable r) {
        Map<Runnable, JobDetail> map = getRunnables();
        JobDetail jd = map.get(r);
        cancel(jd);
    }

    public void cancel(JobDetail jd) {

        if (jd == null) {
            return;
        }

        if (jd.getKey() == null) {
            throw new CronServiceException("JobDetail should have JobKey");
        }

        try {
            scheduler.deleteJob(jd.getKey());
        } catch (SchedulerException e) {
            throw new CronServiceException("Failed to delete Job", e);
        }
    }

    protected Collection<JobDetail> getJobDetails() {
        if (scheduler == null) {
            return Collections.emptySet();
        }

        try {
            Set<JobKey> keys = scheduler.getJobKeys(null);

            if (GenericValidator.isBlankOrNull(keys)) {
                return Collections.emptySet();
            }

            Set<JobDetail> result = Sets.newHashSetWithExpectedSize(keys.size());
            for (JobKey jk : keys) {
                result.add(scheduler.getJobDetail(jk));
            }

            return result;
        } catch (Exception e) {
            throw new CronServiceException("Can't get all active job details", e);
        }
    }

    public Map<Runnable, JobDetail> getRunnables() {
        Collection<JobDetail> jobDetails = getJobDetails();
        if (GenericValidator.isBlankOrNull(jobDetails)) {
            return Collections.emptyMap();
        }

        Map<Runnable, JobDetail> result = Maps.newHashMap();
        for (JobDetail jd : jobDetails) {
            if (GenericValidator.isBlankOrNull(jd.getJobDataMap())) {
                continue;
            }

            if (jd.getJobDataMap().containsKey(RunnableRunner.KEY_RUNNABLE_OBJECT)) {
                result.put((Runnable) jd.getJobDataMap().get(RunnableRunner.KEY_RUNNABLE_OBJECT), jd);
            }
        }

        return Collections.unmodifiableMap(result);
    }

    public List<? extends Trigger> getJobTriggers(JobDetail jd) {
        return getJobTriggers(jd.getKey());
    }

    public List<? extends Trigger> getJobTriggers(JobKey jk) {
        if (scheduler == null) {
            return Collections.emptyList();
        }

        try {
            return scheduler.getTriggersOfJob(jk);
        } catch (SchedulerException e) {
            throw new CronServiceException("Can't get triggers for JobKey " + jk, e);
        }
    }
}