    001package org.apache.turbine.services.schedule;
    002
    003/*
    004 * Licensed to the Apache Software Foundation (ASF) under one
    005 * or more contributor license agreements.  See the NOTICE file
    006 * distributed with this work for additional information
    007 * regarding copyright ownership.  The ASF licenses this file
    008 * to you under the Apache License, Version 2.0 (the
    009 * "License"); you may not use this file except in compliance
    010 * with the License.  You may obtain a copy of the License at
    011 *
    012 *   http://www.apache.org/licenses/LICENSE-2.0
    013 *
    014 * Unless required by applicable law or agreed to in writing,
    015 * software distributed under the License is distributed on an
    016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    017 * KIND, either express or implied.  See the License for the
    018 * specific language governing permissions and limitations
    019 * under the License.
    020 */
    021
    022import java.util.Calendar;
    023import java.util.Date;
    024
    025import org.apache.commons.lang.StringUtils;
    026import org.apache.commons.logging.Log;
    027import org.apache.commons.logging.LogFactory;
    028import org.apache.turbine.util.TurbineException;
    029
    030/**
    031 * This class provides the basic implementation of common features for a scheduled job entry.
    032 *
    033 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
    034 */
    035public abstract class AbstractJobEntry implements JobEntry
    036{
    037    /** Logging */
    038    protected static Log log = LogFactory.getLog(ScheduleService.LOGGER_NAME);
    039
    040    /** indicates if job is currently running */
    041    private boolean jobIsActive = false;
    042
    043    /** Next runtime. **/
    044    private long runtime = 0;
    045
    046    /** schedule types **/
    047    protected enum ScheduleType {
    048        SECOND,
    049        MINUTE,
    050        WEEK_DAY,
    051        DAY_OF_MONTH,
    052        DAILY
    053    }
    054
    055    /**
    056     * Default constructor
    057     */
    058    public AbstractJobEntry()
    059    {
    060        super();
    061    }
    062
    063    /**
    064     * Constructor.
    065     *
    066     * Schedule a job to run on a certain point of time.<br>
    067     *
    068     * Example 1: Run the DefaultScheduledJob at 8:00am every 15th of
    069     * the month - <br>
    070     *
    071     * JobEntry je = new JobEntry(0,0,8,-1,15,"DefaultScheduledJob");<br>
    072     *
    073     * Example 2: Run the DefaultScheduledJob at 8:00am every day -
    074     * <br>
    075     *
    076     * JobEntry je = new JobEntry(0,0,8,-1,-1,"DefaultScheduledJob");<br>
    077     *
    078     * Example 3: Run the DefaultScheduledJob every 2 hours. - <br>
    079     *
    080     * JobEntry je = new JobEntry(0,120,-1,-1,-1,"DefaultScheduledJob");<br>
    081     *
    082     * Example 4: Run the DefaultScheduledJob every 30 seconds. - <br>
    083     *
    084     * JobEntry je = new JobEntry(30,-1,-1,-1,-1,"DefaultScheduledJob");<br>
    085     *
    086     * @param sec Value for entry "seconds".
    087     * @param min Value for entry "minutes".
    088     * @param hour Value for entry "hours".
    089     * @param wd Value for entry "week days".
    090     * @param day_mo Value for entry "month days".
    091     * @param task Task to execute.
    092     * @throws TurbineException a generic exception.
    093     */
    094    public AbstractJobEntry(int sec,
    095                    int min,
    096                    int hour,
    097                    int wd,
    098                    int day_mo,
    099                    String task)
    100            throws TurbineException
    101    {
    102        this();
    103
    104        if (StringUtils.isEmpty(task))
    105        {
    106            throw new TurbineException("Error in JobEntry. " +
    107                    "Bad Job parameter. Task not set.");
    108        }
    109
    110        setSecond(sec);
    111        setMinute(min);
    112        setHour(hour);
    113        setWeekDay(wd);
    114        setDayOfMonth(day_mo);
    115        setTask(task);
    116
    117        calcRunTime();
    118    }
    119
    120    /**
    121     * Used for ordering Jobentries
    122     * Note: this comparator imposes orderings that are inconsistent with
    123     * equals.
    124     *
    125     * @param je The first <code>JobEntry</code> object.
    126     * @return An <code>int</code> indicating the result of the comparison.
    127     */
    128    @Override
    129    public int compareTo(JobEntry je)
    130    {
    131        return getJobId() - je.getJobId();
    132    }
    133
    134    /**
    135     * Sets whether the job is running.
    136     *
    137     * @param isActive Whether the job is running.
    138     */
    139    @Override
    140    public void setActive(boolean isActive)
    141    {
    142        jobIsActive = isActive;
    143    }
    144
    145    /**
    146     * Check to see if job is currently active/running
    147     *
    148     * @return true if job is currently queuing run by the
    149     *  worker thread, otherwise false
    150     */
    151    @Override
    152    public boolean isActive()
    153    {
    154        return jobIsActive;
    155    }
    156
    157    /**
    158     * Get the next runtime for this job as a long.
    159     *
    160     * @return The next run time as a long.
    161     */
    162    @Override
    163    public long getNextRuntime()
    164    {
    165        return runtime;
    166    }
    167
    168    /**
    169     * Gets the next runtime as a date
    170     *
    171     * @return Next run date
    172     */
    173    @Override
    174    public Date getNextRunDate()
    175    {
    176        return new Date(runtime);
    177    }
    178
    179    /**
    180     * Get the next runtime for this job as a String.
    181     *
    182     * @return The next run time as a String.
    183     */
    184    @Override
    185    public String getNextRunAsString()
    186    {
    187        return getNextRunDate().toString();
    188    }
    189
    190    /**
    191     * Calculate how long before the next runtime.<br>
    192     *
    193     * The runtime determines it's position in the job queue.
    194     * Here's the logic:<br>
    195     *
    196     * 1. Create a date the represents when this job is to run.<br>
    197     *
    198     * 2. If this date has expired, them "roll" appropriate date
    199     * fields forward to the next date.<br>
    200     *
    201     * 3. Calculate the diff in time between the current time and the
    202     * next run time.<br>
    203     *
    204     * @throws TurbineException a generic exception.
    205     */
    206    @Override
    207    public void calcRunTime()
    208            throws TurbineException
    209    {
    210        Calendar schedrun = Calendar.getInstance();
    211        Calendar now = Calendar.getInstance();
    212
    213        switch (evaluateJobType())
    214        {
    215            case SECOND:
    216                // SECOND (every so many seconds...)
    217                schedrun.add(Calendar.SECOND, getSecond());
    218                runtime = schedrun.getTime().getTime();
    219                break;
    220
    221            case MINUTE:
    222                // MINUTE (every so many minutes...)
    223                schedrun.add(Calendar.SECOND, getSecond());
    224                schedrun.add(Calendar.MINUTE, getMinute());
    225                runtime = schedrun.getTime().getTime();
    226                break;
    227
    228            case WEEK_DAY:
    229                // WEEKDAY (day of the week)
    230                schedrun.set(Calendar.SECOND, getSecond());
    231                schedrun.set(Calendar.MINUTE, getMinute());
    232                schedrun.set(Calendar.HOUR_OF_DAY, getHour());
    233                schedrun.set(Calendar.DAY_OF_WEEK, getWeekDay());
    234
    235                if (now.before(schedrun))
    236                {
    237                    // Scheduled time has NOT expired.
    238                    runtime = schedrun.getTime().getTime();
    239                }
    240                else
    241                {
    242                    // Scheduled time has expired; roll to the next week.
    243                    schedrun.add(Calendar.DAY_OF_WEEK, 7);
    244                    runtime = schedrun.getTime().getTime();
    245                }
    246                break;
    247
    248            case DAY_OF_MONTH:
    249                // DAY_OF_MONTH (date of the month)
    250                schedrun.set(Calendar.SECOND, getSecond());
    251                schedrun.set(Calendar.MINUTE, getMinute());
    252                schedrun.set(Calendar.HOUR_OF_DAY, getHour());
    253                schedrun.set(Calendar.DAY_OF_MONTH, getDayOfMonth());
    254
    255                if (now.before(schedrun))
    256                {
    257                    // Scheduled time has NOT expired.
    258                    runtime = schedrun.getTime().getTime();
    259                }
    260                else
    261                {
    262                    // Scheduled time has expired; roll to the next month.
    263                    schedrun.add(Calendar.MONTH, 1);
    264                    runtime = schedrun.getTime().getTime();
    265                }
    266                break;
    267
    268            case DAILY:
    269                // DAILY (certain hour:minutes of the day)
    270                schedrun.set(Calendar.SECOND, getSecond());
    271                schedrun.set(Calendar.MINUTE, getMinute());
    272                schedrun.set(Calendar.HOUR_OF_DAY, getHour());
    273
    274                // Scheduled time has NOT expired.
    275                if (now.before(schedrun))
    276                {
    277                    runtime = schedrun.getTime().getTime();
    278                }
    279                else
    280                {
    281                    // Scheduled time has expired; roll forward 24 hours.
    282                    schedrun.add(Calendar.HOUR_OF_DAY, 24);
    283                    runtime = schedrun.getTime().getTime();
    284                }
    285                break;
    286
    287            default:
    288                // Do nothing.
    289        }
    290
    291        log.info("Next runtime for task " + this.getTask() + " is " + this.getNextRunDate());
    292    }
    293
    294    /**
    295     * What schedule am I on?
    296     *
    297     * I know this is kinda ugly!  If you can think of a cleaner way
    298     * to do this, please jump in!
    299     *
    300     * @return A number specifying the type of schedule. See
    301     * calcRunTime().
    302     * @throws TurbineException a generic exception.
    303     */
    304    private ScheduleType evaluateJobType()
    305            throws TurbineException
    306    {
    307
    308        // First start by checking if it's a day of the month job.
    309        if (getDayOfMonth() < 0)
    310        {
    311            // Not a day of the month job... check weekday.
    312            if (getWeekDay() < 0)
    313            {
    314                // Not a weekday job...check if by the hour.
    315                if (getHour() < 0)
    316                {
    317                    // Not an hourly job...check if it is by the minute
    318                    if (getMinute() < 0)
    319                    {
    320                        // Not a by the minute job so must be by the second
    321                        if (getSecond() < 0)
    322                        {
    323                            throw new TurbineException("Error in JobEntry. Bad Job parameter.");
    324                        }
    325
    326                        return ScheduleType.SECOND;
    327                    }
    328                    else
    329                    {
    330                        // Must be a job run by the minute so we need minutes and
    331                        // seconds.
    332                        if (getMinute() < 0 || getSecond() < 0)
    333                        {
    334                            throw new TurbineException("Error in JobEntry. Bad Job parameter.");
    335                        }
    336
    337                        return ScheduleType.MINUTE;
    338                    }
    339                }
    340                else
    341                {
    342                    // Must be a daily job by hours minutes, and seconds.  In
    343                    // this case, we need the minute, second, and hour params.
    344                    if (getMinute() < 0 || getHour() < 0 || getSecond() < 0)
    345                    {
    346                        throw new TurbineException("Error in JobEntry. Bad Job parameter.");
    347                    }
    348
    349                    return ScheduleType.DAILY;
    350                }
    351            }
    352            else
    353            {
    354                // Must be a weekday job.  In this case, we need
    355                // minute, second, and hour params
    356                if (getMinute() < 0 || getHour() < 0 || getSecond() < 0)
    357                {
    358                    throw new TurbineException("Error in JobEntry. Bad Job parameter.");
    359                }
    360
    361                return ScheduleType.WEEK_DAY;
    362            }
    363        }
    364        else
    365        {
    366            // Must be a day of the month job.  In this case, we need
    367            // minute, second, and hour params
    368            if (getMinute() < 0 || getHour() < 0)
    369            {
    370                throw new TurbineException("Error in JobEntry. Bad Job parameter.");
    371            }
    372
    373            return ScheduleType.DAY_OF_MONTH;
    374        }
    375    }
    376
    377    /**
    378     * Get the value of jobId.
    379     *
    380     * @return int
    381     */
    382    @Override
    383    public abstract int getJobId();
    384
    385    /**
    386     * Set the value of jobId.
    387     *
    388     * @param v new value
    389     */
    390    @Override
    391    public abstract void setJobId(int v);
    392
    393    /**
    394     * Get the value of second.
    395     *
    396     * @return int
    397     */
    398    public abstract int getSecond();
    399
    400    /**
    401     * Set the value of second.
    402     *
    403     * @param v new value
    404     */
    405    public abstract void setSecond(int v);
    406
    407    /**
    408     * Get the value of minute.
    409     *
    410     * @return int
    411     */
    412    public abstract int getMinute();
    413
    414    /**
    415     * Set the value of minute.
    416     *
    417     * @param v new value
    418     */
    419    public abstract void setMinute(int v);
    420
    421    /**
    422     * Get the value of hour.
    423     *
    424     * @return int
    425     */
    426    public abstract int getHour();
    427
    428    /**
    429     * Set the value of hour.
    430     *
    431     * @param v new value
    432     */
    433    public abstract void setHour(int v);
    434
    435    /**
    436     * Get the value of weekDay.
    437     *
    438     * @return int
    439     */
    440    public abstract int getWeekDay();
    441
    442    /**
    443     * Set the value of weekDay.
    444     *
    445     * @param v new value
    446     */
    447    public abstract void setWeekDay(int v);
    448
    449    /**
    450     * Get the value of dayOfMonth.
    451     *
    452     * @return int
    453     */
    454    public abstract int getDayOfMonth();
    455
    456    /**
    457     * Set the value of dayOfMonth.
    458     *
    459     * @param v new value
    460     */
    461    public abstract void setDayOfMonth(int v);
    462
    463    /**
    464     * Get the value of task.
    465     *
    466     * @return String
    467     */
    468    @Override
    469    public abstract String getTask();
    470
    471    /**
    472     * Set the value of task.
    473     *
    474     * @param v new value
    475     */
    476    @Override
    477    public abstract void setTask(String v);
    478}