net.audumla.scheduler.quartz.QuartzScheduledExecutorService.java Source code

Java tutorial

Introduction

Here is the source code for net.audumla.scheduler.quartz.QuartzScheduledExecutorService.java

Source

package net.audumla.scheduler.quartz;

/*
 * *********************************************************************
 *  ORGANIZATION : audumla.net
 *  More information about this project can be found at the following locations:
 *  http://www.audumla.net/
 *  http://audumla.googlecode.com/
 * *********************************************************************
 *  Copyright (C) 2012 - 2013 Audumla.net
 *  Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.
 *  You may not use this file except in compliance with the License located at http://creativecommons.org/licenses/by-nc-nd/3.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.
 */

import org.apache.commons.lang.time.DateUtils;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

public class QuartzScheduledExecutorService extends AbstractExecutorService implements ScheduledExecutorService {
    private static final Logger logger = LoggerFactory.getLogger(QuartzScheduledExecutorService.class);
    private static long jobCount = 0;
    private Scheduler scheduler;

    public QuartzScheduledExecutorService(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    public QuartzScheduledExecutorService() {
    }

    public void setScheduler(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    public Scheduler getScheduler() {
        if (scheduler == null) {
            try {
                scheduler = StdSchedulerFactory.getDefaultScheduler();
                scheduler.start();
            } catch (SchedulerException e) {
                logger.error("Instantiation error", e);
            }
        }
        return scheduler;

    }

    @Override
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new QuartzRunnableFuture<T>(runnable, value, this.scheduler, generateName());
    }

    @Override
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new QuartzRunnableFuture<T>(callable, this.scheduler, generateName());
    }

    @Override
    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
        QuartzRunnableFuture<Object> rf = new QuartzRunnableFuture<Object>(command, null, this.scheduler, delay,
                unit, generateName());
        rf.run();
        return rf;
    }

    @Override
    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
        RunnableScheduledFuture<V> rf = new QuartzRunnableFuture<V>(callable, this.scheduler, delay, unit,
                generateName());
        rf.run();
        return rf;
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
        RunnableScheduledFuture<Object> rf = new QuartzRunnableFuture<Object>(command, null, this.scheduler,
                initialDelay, unit, generateName());
        rf.run();
        return rf;
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,
            TimeUnit unit) {
        RunnableScheduledFuture<Object> rf = new QuartzRunnableFuture<Object>(command, null, this.scheduler, delay,
                unit, generateName());
        rf.run();
        return rf;
    }

    @Override
    public void shutdown() {
        try {
            scheduler.shutdown(true);
        } catch (SchedulerException e) {
            logger.error("Error shutting down", e);
        }
    }

    @Override
    public List<Runnable> shutdownNow() {
        try {
            scheduler.shutdown(false);
        } catch (SchedulerException e) {
            logger.error("Error shutting down", e);
        }
        return null;
    }

    @Override
    public boolean isShutdown() {
        try {
            return scheduler.isShutdown();
        } catch (SchedulerException e) {
            logger.error("Error determining shutting state", e);
        }
        return true;
    }

    @Override
    public boolean isTerminated() {
        return isShutdown();
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void execute(Runnable command) {
        command.run();
    }

    protected String generateName() {
        return "job" + (jobCount++);

    }

    private static class QuartzRunnableFuture<V> implements RunnableScheduledFuture<V> {
        private static final Logger logger = LoggerFactory.getLogger(QuartzRunnableFuture.class);
        private final Callable<V> callable;
        private final Scheduler scheduler;
        private final Trigger trigger;
        private final String name;
        private V result;
        private long delay;

        /**
         * Creates a {@code FutureTask} that will, upon running, execute the
         * given {@code Callable}.
         *
         * @param callable the callable task
         * @throws NullPointerException if the callable is null
         */
        public QuartzRunnableFuture(Callable<V> callable, Scheduler scheduler, String name) {
            if (callable == null)
                throw new NullPointerException();
            this.name = name;
            this.callable = callable;
            this.scheduler = scheduler;
            this.trigger = createTrigger(callable, 0, TimeUnit.MILLISECONDS);
        }

        /**
         * Creates a {@code FutureTask} that will, upon running, execute the
         * given {@code Runnable}, and arrange that {@code get} will return the
         * given result on successful completion.
         *
         * @param runnable the runnable task
         * @param result   the result to return on successful completion. If
         *                 you don't need a particular result, consider using
         *                 constructions of the form:
         *                 {@code Future<?> f = new FutureTask<Void>(runnable, null)}
         * @throws NullPointerException if the runnable is null
         */
        public QuartzRunnableFuture(Runnable runnable, V result, Scheduler scheduler, String name) {
            this.name = name;
            this.callable = Executors.callable(runnable, result);
            this.trigger = createTrigger(callable, 0, TimeUnit.MILLISECONDS);
            this.scheduler = scheduler;
        }

        /**
         * Creates a {@code FutureTask} that will, upon running, execute the
         * given {@code Callable}.
         *
         * @param callable the callable task
         * @throws NullPointerException if the callable is null
         */
        public QuartzRunnableFuture(Callable<V> callable, Scheduler scheduler, long delay, TimeUnit timeUnit,
                String name) {
            if (callable == null)
                throw new NullPointerException();
            this.name = name;
            this.callable = callable;
            this.trigger = createTrigger(callable, delay, timeUnit);
            this.scheduler = scheduler;
        }

        /**
         * Creates a {@code FutureTask} that will, upon running, execute the
         * given {@code Runnable}, and arrange that {@code get} will return the
         * given result on successful completion.
         *
         * @param runnable the runnable task
         * @param result   the result to return on successful completion. If
         *                 you don't need a particular result, consider using
         *                 constructions of the form:
         *                 {@code Future<?> f = new FutureTask<Void>(runnable, null)}
         * @throws NullPointerException if the runnable is null
         */
        public QuartzRunnableFuture(Runnable runnable, V result, Scheduler scheduler, long delay, TimeUnit timeUnit,
                String name) {
            this.name = name;
            this.callable = Executors.callable(runnable, result);
            this.trigger = createTrigger(callable, delay, timeUnit);
            this.scheduler = scheduler;
        }

        protected Trigger createTrigger(Callable<V> callable, long delay, TimeUnit timeUnit) {
            try {
                this.delay = timeUnit.toSeconds(delay);
                Date start = DateUtils.addSeconds(new Date(), (int) this.delay);
                ScheduleBuilder<SimpleTrigger> sbuilder = SimpleScheduleBuilder.repeatSecondlyForTotalCount(1)
                        .withMisfireHandlingInstructionFireNow();
                TriggerBuilder<SimpleTrigger> tbuilder = TriggerBuilder.newTrigger()
                        .withIdentity(getName(), "Group:" + getName()).startAt(start).withSchedule(sbuilder);
                return tbuilder.build();
            } catch (Exception e) {
                logger.error("Cannot create Trigger", e);
                return null;
            }
        }

        @Override
        public void run() {
            try {
                JobDetail job = JobBuilder.newJob(RunnableJob.class)
                        .withIdentity(trigger.getKey().getName(), trigger.getKey().getGroup()).storeDurably(false)
                        .build();
                job.getJobDataMap().put(RunnableJob.RUNNABLE_PROPERTY, callable);
                job.getJobDataMap().put(RunnableJob.RESULT_PROPERTY, this);
                scheduler.scheduleJob(job, trigger);
            } catch (SchedulerException e) {
                logger.error("Error executing job {}", trigger.getKey(), e);
            }
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            try {
                return scheduler.unscheduleJob(trigger.getKey());
            } catch (SchedulerException e) {
                logger.warn("Unable to cancel job {}", trigger.getKey(), e);
            }
            return false;
        }

        public boolean isCancelled() {
            try {
                return scheduler.getTriggerState(trigger.getKey()).equals(Trigger.TriggerState.NONE);
            } catch (SchedulerException e) {
                logger.error("Cannot find trigger - {}", trigger.getKey());
            }
            return false;
        }

        public boolean isDone() {
            try {
                return scheduler.getTriggerState(trigger.getKey()).equals(Trigger.TriggerState.COMPLETE);
            } catch (SchedulerException e) {
                // if the trigger does not exist then we can assumer that it has been removed from the scheduler
                return true;
            }
        }

        @Override
        public V get() throws InterruptedException, ExecutionException {
            return result;
        }

        @Override
        public V get(long timeout, TimeUnit unit)
                throws InterruptedException, ExecutionException, TimeoutException {
            return result;
        }

        public String getName() {
            return name;
        }

        public Trigger getTrigger() {
            return trigger;
        }

        public Scheduler getScheduler() {
            return scheduler;
        }

        public Callable<V> getCallable() {
            return callable;
        }

        public void setResult(V result) {
            this.result = result;
        }

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

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(delay, TimeUnit.SECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            return 0;
        }

        public static class RunnableJob implements Job {

            public static String RUNNABLE_PROPERTY = "runnable";
            public static String RESULT_PROPERTY = "result";

            public RunnableJob() {
            }

            @Override
            public void execute(JobExecutionContext context) throws JobExecutionException {
                Callable<?> rf = (Callable<?>) context.getMergedJobDataMap().get(RUNNABLE_PROPERTY);
                try {
                    Object result = rf.call();
                    QuartzRunnableFuture<Object> qrf = (QuartzRunnableFuture<Object>) context.getMergedJobDataMap()
                            .get(RESULT_PROPERTY);
                    qrf.setResult(result);

                } catch (Exception e) {
                    throw new JobExecutionException(e);
                }
            }
        }

    }
}