nl.strohalm.cyclos.scheduling.SchedulingHandler.java Source code

Java tutorial

Introduction

Here is the source code for nl.strohalm.cyclos.scheduling.SchedulingHandler.java

Source

/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
    
Cyclos 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 2 of the License, or
(at your option) any later version.
    
Cyclos 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 Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 */
package nl.strohalm.cyclos.scheduling;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;

import nl.strohalm.cyclos.entities.settings.LocalSettings;
import nl.strohalm.cyclos.entities.settings.events.LocalSettingsChangeListener;
import nl.strohalm.cyclos.entities.settings.events.LocalSettingsEvent;
import nl.strohalm.cyclos.scheduling.tasks.ScheduledTask;
import nl.strohalm.cyclos.services.settings.SettingsServiceLocal;
import nl.strohalm.cyclos.utils.logging.LoggingHandler;
import nl.strohalm.cyclos.utils.lucene.IndexHandler;
import nl.strohalm.cyclos.utils.tasks.TaskRunner;

import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * Handles execution of scheduled jobs
 * @author luis
 */
public class SchedulingHandler implements InitializingBean, DisposableBean, LocalSettingsChangeListener {

    /**
     * A {@link TimerTask} that dispatches the execution to a {@link HourlyScheduledTasks} if no other {@link HourlyScheduledTasks} is currently being
     * executed, or enqueues it for later execution
     * @author luis
     */
    private class SchedulingTimerTask extends TimerTask {
        @Override
        public void run() {
            Calendar time = DateUtils.truncate(Calendar.getInstance(), Calendar.HOUR_OF_DAY);
            HourlyScheduledTasks runner = new HourlyScheduledTasks(SchedulingHandler.this, time);
            if (queue.isEmpty()) {
                // Nothing is currently being executed. Execute it right away
                runner.start();
            } else {
                // Tasks of a previous hour are being executed. Enqueue this execution
                queue.offer(runner);
            }
        }
    }

    private Timer timer;
    private SettingsServiceLocal settingsService;
    private LoggingHandler loggingHandler;
    private TransactionTemplate transactionTemplate;
    private IndexHandler indexHandler;
    private TaskRunner taskRunner;
    private Queue<HourlyScheduledTasks> queue;
    private Map<String, ScheduledTask> tasks;
    private Integer lastScheduledMinute;

    @Override
    public void afterPropertiesSet() throws Exception {
        queue = new ConcurrentLinkedQueue<HourlyScheduledTasks>();
        settingsService.addListener(this);
    }

    @Override
    public void destroy() throws Exception {
        shutdown();
        if (queue != null) {
            queue.clear();
            queue = null;
        }
    }

    public IndexHandler getIndexHandler() {
        return indexHandler;
    }

    public LoggingHandler getLoggingHandler() {
        return loggingHandler;
    }

    public SettingsServiceLocal getSettingsServiceLocal() {
        return settingsService;
    }

    public ScheduledTask getTask(final String name) {
        return tasks.get(name);
    }

    public TaskRunner getTaskRunner() {
        return taskRunner;
    }

    public List<ScheduledTask> getTasks() {
        return new ArrayList<ScheduledTask>(tasks.values());
    }

    public TransactionTemplate getTransactionTemplate() {
        return transactionTemplate;
    }

    @Override
    public void onLocalSettingsUpdate(final LocalSettingsEvent event) {
        updateTime();
    }

    public void runNextTasks() {
        HourlyScheduledTasks nextToRun = queue.poll();
        if (nextToRun != null) {
            nextToRun.start();
        }
    }

    public void setIndexHandler(final IndexHandler indexHandler) {
        this.indexHandler = indexHandler;
    }

    public void setLoggingHandler(final LoggingHandler loggingHandler) {
        this.loggingHandler = loggingHandler;
    }

    public void setSettingsServiceLocal(final SettingsServiceLocal settingsService) {
        this.settingsService = settingsService;
    }

    public void setTaskRunner(final TaskRunner taskRunner) {
        this.taskRunner = taskRunner;
    }

    public void setTasks(final List<ScheduledTask> tasks) {
        this.tasks = new LinkedHashMap<String, ScheduledTask>(tasks.size());
        for (ScheduledTask task : tasks) {
            ScheduledTask old = this.tasks.put(task.getName(), task);
            if (old != null) {
                throw new IllegalStateException("Trying to add 2 tasks with the same name '" + task.getName()
                        + "': " + old + " and " + task);
            }
        }
    }

    public void setTransactionTemplate(final TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    /**
     * Starts running scheduled jobs
     */
    public void start() {
        initializeTimer();
    }

    /**
     * Should be called when the time the tasks run should be modified
     */
    public synchronized void updateTime() {
        if (timer == null) {
            return;
        }
        final LocalSettings localSettings = settingsService.getLocalSettings();
        if (lastScheduledMinute == null || lastScheduledMinute != localSettings.getSchedulingMinute()) {
            shutdown();
            initializeTimer();
        }
    }

    private synchronized void initializeTimer() {
        final LocalSettings localSettings = settingsService.getLocalSettings();
        timer = new Timer("Scheduled tasks handler for " + localSettings.getApplicationName());
        timer.scheduleAtFixedRate(new SchedulingTimerTask(), startsTaskAt(), DateUtils.MILLIS_PER_HOUR);
        lastScheduledMinute = localSettings.getSchedulingMinute();
    }

    /**
     * Stops all running tasks
     */
    private synchronized void shutdown() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }

    /**
     * Returns the date where the task will start running. It should be on the next hour, settings the minute to the <code>minute</code> property
     */
    private Date startsTaskAt() {
        final LocalSettings localSettings = settingsService.getLocalSettings();
        final Calendar startAt = Calendar.getInstance();
        startAt.add(Calendar.HOUR_OF_DAY, 1);
        startAt.set(Calendar.MINUTE, localSettings.getSchedulingMinute());
        startAt.set(Calendar.SECOND, 30);
        return startAt.getTime();
    }

}