org.geowebcache.seed.JobMonitorTask.java Source code

Java tutorial

Introduction

Here is the source code for org.geowebcache.seed.JobMonitorTask.java

Source

/**
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program 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 Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @author Arne Kepp / The Open Planning Project 2008 
 */
package org.geowebcache.seed;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geowebcache.GeoWebCacheException;
import org.geowebcache.job.JobScheduler;
import org.geowebcache.storage.JobLogObject;
import org.geowebcache.storage.JobObject;
import org.geowebcache.storage.JobStore;
import org.geowebcache.storage.StorageException;

public class JobMonitorTask extends GWCTask {
    private static Log log = LogFactory.getLog(JobMonitorTask.class);

    private final JobStore jobStore;
    private final TileBreeder seeder;
    private final long updateFrequency;
    private final String purgeJobTaskSchedule;
    private final ConcurrentLinkedQueue<GWCTask> finishedTasks;

    public JobMonitorTask(JobStore js, TileBreeder seeder, long updateFrequency, String purgeJobTaskSchedule) {
        this.jobStore = js;
        this.seeder = seeder;
        this.updateFrequency = updateFrequency;
        this.purgeJobTaskSchedule = purgeJobTaskSchedule;
        this.finishedTasks = new ConcurrentLinkedQueue<GWCTask>();

        super.taskType = GWCTask.TYPE.JOB_MONITOR;
    }

    /**
     * Infrequently wake up and go through the list of running tasks to update the jobs (task groups).
     * @see org.geowebcache.seed.GWCTask#doActionInternal()
     */
    @Override
    protected void doActionInternal() throws GeoWebCacheException, InterruptedException {
        super.state = GWCTask.STATE.RUNNING;

        Thread.currentThread().setPriority(PRIORITY.LOW.getThreadPriority());

        int consecutiveFailures = 0;

        initCron4J();

        scheduleOldJobPurgeTask();

        restartInterruptedTasks();

        while ((!Thread.interrupted()) && super.state != GWCTask.STATE.INTERRUPTED) {
            try {
                Iterator<Entry<Long, GWCTask>> tasks = seeder.getRunningTasksIterator();

                List<Long> jobIds = new ArrayList<Long>();
                while (tasks.hasNext()) {
                    GWCTask task = tasks.next().getValue();

                    if (!(task instanceof JobMonitorTask)) {
                        if (!jobIds.contains(task.getJobId())) {
                            jobIds.add(task.getJobId());

                            JobObject job = new JobObject();
                            job.setJobId(task.getJobId());
                            if (jobStore.get(job)) {
                                job.update(seeder);
                                jobStore.put(job);
                            }
                        }
                    }
                }

                // clear out completed tasks
                jobIds = new ArrayList<Long>();
                while (!finishedTasks.isEmpty()) {
                    GWCTask task;
                    synchronized (finishedTasks) {
                        task = finishedTasks.poll();
                    }
                    if (!(task instanceof JobMonitorTask)) {
                        if (!jobIds.contains(task.getJobId())) {
                            jobIds.add(task.getJobId());

                            JobObject job = new JobObject();
                            job.setJobId(task.getJobId());
                            if (jobStore.get(job)) {
                                job.update(task);
                                jobStore.put(job);
                            }
                        }
                    }
                }

                consecutiveFailures = 0;
            } catch (Exception e) {
                log.error("During job monitor task: " + e.getClass().getName() + ": " + e.getMessage());

                consecutiveFailures++;

                if (consecutiveFailures > 5) {
                    log.error("5 consecutive failures in a row, job monitoring will be shut down.");
                    super.state = GWCTask.STATE.DEAD;
                }
            }

            Thread.sleep(updateFrequency);
        }

        if (super.state != GWCTask.STATE.DEAD) {
            super.state = GWCTask.STATE.DONE;
            log.debug("Completed job monitoring.");
        }
    }

    /**
     * The job monitor doesn't do anything on abnormal exit - assumes that things are so unstable at
     * this point that trying to save off the latest state of the tasks isn't worth attempting.
     */
    protected void doAbnormalExit(Throwable t) {
        ;
    }

    /**
     * Ensures all ready jobs in the system are scheduled using Cron4J
     * Called when this task begins.  
     */
    private void initCron4J() {
        Iterator<JobObject> iter;
        try {
            iter = jobStore.getPendingScheduledJobs().iterator();
            while (iter.hasNext()) {
                JobObject job = iter.next();
                JobScheduler.scheduleJob(job, seeder, jobStore);
            }
        } catch (StorageException e) {
            log.error("Job Monitor couldn't initialise Cron4J due to a storage exception.", e);
        }
    }

    /**
     * Schedules a task to daily check for old jobs and delete them.
     */
    private void scheduleOldJobPurgeTask() {
        OldJobPurgeTask ojct = new OldJobPurgeTask(jobStore);
        JobScheduler.getSchedulerInstance().schedule(purgeJobTaskSchedule, ojct);
    }

    /**
     * Checks for interrupted tasks or tasks that the store thought was running 
     * and starts them.
     * Called when this task begins.  
     */
    private void restartInterruptedTasks() {
        try {
            Iterator<JobObject> iter = jobStore.getInterruptedJobs().iterator();

            while (iter.hasNext()) {
                JobObject job = iter.next();
                try {
                    job.setState(STATE.INTERRUPTED);
                    job.addLog(JobLogObject.createWarnLog(job.getJobId(), "Job Interruption Detected",
                            "This job was running last time GeoWebCache was running. Changing state to interrupted."));
                    seeder.executeJob(job);
                } catch (GeoWebCacheException e) {
                    log.error("Couldn't restart interrupted job: " + e.getMessage(), e);
                }
            }
        } catch (StorageException e) {
            log.error("Job Monitor couldn't restart interrupted jobs due to a storage exception.", e);
        }
    }

    @Override
    protected void dispose() {
        // do nothing
    }

    public void addFinishedTask(GWCTask task) {
        synchronized (finishedTasks) {
            finishedTasks.add(task);
        }
    }
}