001    /**
002     * Jetrix TetriNET Server
003     * Copyright (C) 2001-2004  Emmanuel Bourg
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License
007     * as published by the Free Software Foundation; either version 2
008     * of the License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
018     */
019    
020    package net.jetrix.services;
021    
022    import java.util.Calendar;
023    import java.util.Date;
024    import java.util.Timer;
025    import java.util.TimerTask;
026    import java.util.logging.Level;
027    
028    import org.jcrontab.data.CalendarBuilder;
029    import org.jcrontab.data.CrontabEntryBean;
030    import org.jcrontab.data.CrontabEntryException;
031    import org.jcrontab.data.CrontabParser;
032    
033    /**
034     * A service running a task at a fixed date. Services extending this service
035     * expect a <tt>pattern</tt> parameter setting the execution time, this pattern
036     * uses the cron format of Unix systems extended with a 6th field for the year
037     * (see http://www.nncron.ru/nncronlt/help/EN/working/cron-format.htm).
038     *
039     * @author Emmanuel Bourg
040     * @version $Revision: 794 $, $Date: 2009-02-17 20:08:39 +0100 (Tue, 17 Feb 2009) $
041     * @since 0.2
042     */
043    public abstract class CronService extends AbstractService
044    {
045        protected String pattern;
046        private Timer timer;
047        private CrontabEntryBean cron;
048    
049        public void setPattern(String pattern)
050        {
051            this.pattern = pattern;
052        }
053    
054        /**
055         * Initialization performed before the timer is started.
056         */
057        protected void init() { }
058    
059        public void start()
060        {
061            if (!isRunning())
062            {
063                init();
064    
065                // parse the cron pattern
066                CrontabParser parser = new CrontabParser();
067                try
068                {
069                    cron = parser.marshall(pattern);
070                    cron.setBSeconds(new boolean[60]);
071                }
072                catch (CrontabEntryException e)
073                {
074                    log.log(Level.SEVERE, "Unable to start the service", e);
075                    return;
076                }
077    
078                // start the timer
079                timer = new Timer();
080                scheduleNext();
081            }
082        }
083    
084        public synchronized void stop()
085        {
086            // stop the timer
087            if (isRunning())
088            {
089                timer.cancel();
090                timer = null;
091            }
092        }
093    
094        public boolean isRunning()
095        {
096            return timer != null;
097        }
098    
099        /**
100         * Do the task
101         */
102        protected abstract void run();
103    
104        /**
105         * Schedule the next execution of the task.
106         */
107        private synchronized void scheduleNext()
108        {
109            if (timer != null)
110            {
111                timer.cancel();
112            }
113            else
114            {
115                return;
116            }
117    
118            TimerTask task = new TimerTask()
119            {
120                public void run()
121                {
122                    CronService.this.run();
123                    scheduleNext();
124                }
125            };
126    
127            timer = new Timer();
128            timer.schedule(task, getNextExecutionDate());
129        }
130    
131        /**
132         * Return the next time the task has to be executed.
133         */
134        private Date getNextExecutionDate()
135        {
136            Calendar calendar = Calendar.getInstance();
137            calendar.add(Calendar.SECOND, 1);
138            Date date = new CalendarBuilder().buildCalendar(cron, calendar.getTime());
139    
140            log.fine("Next execution of '" + getName() + "' on " + date);
141    
142            return date;
143        }
144    }