001/*
002 * HA-JDBC: High-Availability JDBC
003 * Copyright (c) 2004-2007 Paul Ferraro
004 * 
005 * This library is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Lesser General Public License as published by the 
007 * Free Software Foundation; either version 2.1 of the License, or (at your 
008 * option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful, but WITHOUT
011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 
013 * for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this library; if not, write to the Free Software Foundation, 
017 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018 * 
019 * Contact: ferraro@users.sourceforge.net
020 */
021package net.sf.hajdbc.util.concurrent;
022
023import java.util.Date;
024import java.util.concurrent.CancellationException;
025import java.util.concurrent.RejectedExecutionException;
026import java.util.concurrent.RejectedExecutionHandler;
027import java.util.concurrent.ScheduledThreadPoolExecutor;
028import java.util.concurrent.TimeUnit;
029
030import org.quartz.CronExpression;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034/**
035 * Scheduled thread-pool executor implementation that leverages a Quartz CronExpression to calculate future execution times for scheduled tasks.
036 *
037 * @author  Paul Ferraro
038 * @since   1.1
039 */
040public class CronThreadPoolExecutor extends ScheduledThreadPoolExecutor implements CronExecutorService
041{
042        protected static Logger logger = LoggerFactory.getLogger(CronThreadPoolExecutor.class);
043        
044        /**
045         * Constructs a new CronThreadPoolExecutor.
046         * @param corePoolSize
047         * @param handler
048         */
049        public CronThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler)
050        {
051                super(corePoolSize, DaemonThreadFactory.getInstance(), handler);
052        }
053
054        /**
055         * Constructs a new CronThreadPoolExecutor.
056         * @param corePoolSize
057         */
058        public CronThreadPoolExecutor(int corePoolSize)
059        {
060                super(corePoolSize, DaemonThreadFactory.getInstance());
061        }
062        
063        /**
064         * @see net.sf.hajdbc.util.concurrent.CronExecutorService#schedule(java.lang.Runnable, org.quartz.CronExpression)
065         */
066        @Override
067        public void schedule(final Runnable task, final CronExpression expression)
068        {
069                if (task == null) throw new NullPointerException();
070                
071                this.setCorePoolSize(this.getCorePoolSize() + 1);
072                
073                Runnable scheduleTask = new Runnable()
074                {
075                        /**
076                         * @see java.lang.Runnable#run()
077                         */
078                        public void run()
079                        {
080                                Date now = new Date();
081                                Date time = expression.getNextValidTimeAfter(now);
082                        
083                                try
084                                {
085                                        while (time != null)
086                                        {
087                                                CronThreadPoolExecutor.this.schedule(task, time.getTime() - now.getTime(), TimeUnit.MILLISECONDS);
088                                                
089                                                while (now.before(time))
090                                                {
091                                                        Thread.sleep(time.getTime() - now.getTime());
092                                                        
093                                                        now = new Date();
094                                                }
095                                                
096                                                time = expression.getNextValidTimeAfter(now);
097                                        }
098                                }
099                                catch (RejectedExecutionException e)
100                                {
101                                        // Occurs if executor was already shutdown when schedule() is called
102                                }
103                                catch (CancellationException e)
104                                {
105                                        // Occurs when scheduled, but not yet executed tasks are canceled during shutdown
106                                }
107                                catch (InterruptedException e)
108                                {
109                                        // Occurs when executing tasks are interrupted during shutdownNow()
110                                }
111                        }
112                };
113                
114                this.execute(scheduleTask);
115        }
116}