/*
* The contents of this file are subject to the Sapient Public License
* Version 1.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://carbon.sf.net/License.html.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is The Carbon Component Framework.
*
* The Initial Developer of the Original Code is Sapient Corporation
*
* Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
*/
package org.sape.carbon.services.scheduler;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Timer;
import org.sape.carbon.core.config.InvalidConfigurationException;
import org.sape.carbon.core.util.calendar.DayOfWeekEnum;
import org.sape.carbon.core.util.calendar.MonthEnum;
import org.sape.carbon.services.threadpool.ThreadPool;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Utility class used to interperet FixedRateTaskConfiguration and
* schedule fixed rate tasks.
*
* Copyright 2002 Sapient
* @since carbon 1.0
* @author Douglas Voet, June 2002
* @version $Revision: 1.16 $($Author: dvoet $ / $Date: 2003/11/20 21:46:15 $)
*/
class FixedRateTask extends AbstractTask {
/**
* Provides a handle to Apache-commons logger
*/
private Log log = LogFactory.getLog(this.getClass());
// constants specifying the range of valid configuration values
/** Mininum valid minute value. */
private static final int MIN_MINUTE = 0;
/** Maximum valid minute value. */
private static final int MAX_MINUTE = 59;
/** Mininum valid hour value. */
private static final int MIN_HOUR = 0;
/** Maximum valid hour value. */
private static final int MAX_HOUR = 23;
/** Mininum valid day of month value. */
private static final int MIN_DAY_OF_MONTH = 1;
/** Maximum valid day of month value. */
private static final int MAX_DAY_OF_MONTH = 31;
// constants used to set the appropriate period for task execution
/** Milliseconds for one minute. */
private static final long EVERY_MINUTE = 1000 * 60;
/** Milliseconds for one hour. */
private static final long EVERY_HOUR = EVERY_MINUTE * 60;
/** Milliseconds for one day. */
private static final long EVERY_DAY = EVERY_HOUR * 24;
/** Milliseconds for one week. */
private static final long EVERY_WEEK = EVERY_DAY * 7;
/** Milliseconds for one month. */
private static final long EVERY_MONTH = EVERY_DAY * 30;
/** Milliseconds for one year. */
private static final long EVERY_YEAR = EVERY_DAY * 365;
/** Holds the period of how often the task will execute. */
private long period;
/** Holds the first run time of the task. */
private Date time;
/**
* This constructor determines the starting time and date and the repeat
* period of the task. See the class javadoc for FixedRateTaskConfiguration
* for valid configuration and related behavior.
*
* @see org.sape.carbon.services.scheduler.FixedRateTaskConfiguration
*
* @param taskConfiguration
*/
protected FixedRateTask(
FixedRateTaskConfiguration taskConfiguration,
ThreadPool threadPool) {
super(taskConfiguration, threadPool);
Integer minute = taskConfiguration.getMinute();
Integer hour = taskConfiguration.getHour();
Integer dayOfMonth = taskConfiguration.getDayOfMonth();
MonthEnum month = taskConfiguration.getMonth();
DayOfWeekEnum dayOfWeek = taskConfiguration.getDayOfWeek();
//validate configuration information is in the right range
validate(
taskConfiguration.getConfigurationName(),
"Minute",
minute,
MIN_MINUTE,
MAX_MINUTE);
validate(
taskConfiguration.getConfigurationName(),
"Hour",
hour,
MIN_HOUR,
MAX_HOUR);
validate(
taskConfiguration.getConfigurationName(),
"DayOfMonth",
dayOfMonth,
MIN_DAY_OF_MONTH,
MAX_DAY_OF_MONTH);
Calendar firstRunTime = new GregorianCalendar();
firstRunTime.set(Calendar.MILLISECOND, 0);
firstRunTime.set(Calendar.SECOND, 0);
// this section of if statements determines when the task should
// execute first and how often it should execute after that
if (minute == null) {
// task runs every minute starting at the next minute
// make sure there is not extra configuration specified
if (!(hour == null && dayOfMonth == null
&& month == null && dayOfWeek == null)) {
throw new InvalidConfigurationException(
this.getClass(),
taskConfiguration.getConfigurationName(),
"Minute",
"Minute was not specifed, but other configuration "
+ "information exists. Either specify Minute "
+ "or remove all other configuration information");
}
// run task every minute starting with the next minute
this.period = EVERY_MINUTE;
// start running at the next minute
firstRunTime.add(Calendar.MINUTE, 1);
} else if (hour == null) {
// task runs every hour starting at the next occurence of the
// specified minute
// make sure there is not extra configuration specified
if (!(dayOfMonth == null && month == null && dayOfWeek == null)) {
throw new InvalidConfigurationException(
this.getClass(),
taskConfiguration.getConfigurationName(),
"Hour",
"Hour was not specifed, but day and/or month "
+ "configuration information exists. Either "
+ "specify Hour or remove day and month "
+ "configuration information");
}
// run task every hour starting with the next hour
this.period = EVERY_HOUR;
firstRunTime.set(Calendar.MINUTE, minute.intValue());
Date now = new Date();
if (firstRunTime.getTime().compareTo(now) <= 0) {
firstRunTime.add(Calendar.HOUR_OF_DAY, 1);
}
} else if (dayOfMonth == null && dayOfWeek == null) {
// task runs every day starting at the next occurence
// of the specified hour and minute
// make sure there is not extra configuration specified
if (month != null) {
throw new InvalidConfigurationException(
this.getClass(),
taskConfiguration.getConfigurationName(),
"Month",
"Month was supplied without DayOfMonth, either remove "
+ "Month or add DayOfMonth");
}
this.period = EVERY_DAY;
firstRunTime.set(Calendar.MINUTE, minute.intValue());
firstRunTime.set(Calendar.HOUR_OF_DAY, hour.intValue());
Date now = new Date();
if (firstRunTime.getTime().compareTo(now) <= 0) {
// starting tomorrow if the scheduled
// time of day has passed today
firstRunTime.add(Calendar.DAY_OF_MONTH, 1);
}
} else if (dayOfMonth != null) {
// make sure there is not extra configuration specified
if (dayOfWeek != null) {
throw new InvalidConfigurationException(
this.getClass(),
taskConfiguration.getConfigurationName(),
"DayOfWeek",
"Both DayOfWeek and DayOfMonth were specified, only one "
+ "can be used");
}
if (month == null) {
// run task every month starting next month if the scheduled
// date and time has passed this month
this.period = EVERY_MONTH;
firstRunTime.set(Calendar.MINUTE, minute.intValue());
firstRunTime.set(Calendar.HOUR_OF_DAY, hour.intValue());
firstRunTime.set(Calendar.DAY_OF_MONTH, dayOfMonth.intValue());
Date now = new Date();
if (firstRunTime.getTime().compareTo(now) <= 0) {
firstRunTime.add(Calendar.MONTH, 1);
}
} else {
// run task every year starting next year if the scheduled
// date and time has passed this year
this.period = EVERY_YEAR;
firstRunTime.set(Calendar.MINUTE, minute.intValue());
firstRunTime.set(Calendar.HOUR_OF_DAY, hour.intValue());
firstRunTime.set(Calendar.DAY_OF_MONTH, dayOfMonth.intValue());
firstRunTime.set(Calendar.MONTH, month.getOrdinal());
Date now = new Date();
if (firstRunTime.getTime().compareTo(now) <= 0) {
firstRunTime.add(Calendar.YEAR, 1);
}
}
} else if (dayOfWeek != null) {
// run task every week starting next week if the scheduled
// day and time has passed this week
// make sure there is not extra configuration specified
if (month != null) {
throw new InvalidConfigurationException(
this.getClass(),
taskConfiguration.getConfigurationName(),
"Month",
"Month cannot be used with DayOfWeek, "
+ "it can only be used in conjunction with "
+ "DayOfMonth");
}
this.period = EVERY_WEEK;
firstRunTime.set(Calendar.MINUTE, minute.intValue());
firstRunTime.set(Calendar.HOUR_OF_DAY, hour.intValue());
firstRunTime.set(Calendar.DAY_OF_WEEK, dayOfWeek.getOrdinal());
Date now = new Date();
if (firstRunTime.getTime().compareTo(now) <= 0) {
firstRunTime.add(Calendar.WEEK_OF_MONTH, 1);
}
} else {
// I don't think this can ever happen
throw new InvalidConfigurationException(
this.getClass(),
taskConfiguration.getConfigurationName(),
"all attributes",
"Could not determine first run time or repeat period");
}
this.time = firstRunTime.getTime();
if (log.isTraceEnabled()) {
log.trace("Creating task defined by configuration ["
+ taskConfiguration.getConfigurationName()
+ "] to run starting at ["
+ this.time
+ "] with period ["
+ this.period
+ "] ms");
}
}
/**
* @see AbstractTask#schedule(Timer)
*/
public void schedule(Timer timer) {
timer.scheduleAtFixedRate(getTask(), this.time, this.period);
}
/**
* Checks to make sure that value is within min and max values
*
* @param configName configuration the value being validated comes from
* @param attributeName name of attribute being validated
* @param value the value of the attribute
* @param minValue the minimum valid value
* @param maxValue the maximum valid value
*/
private void validate(String configName,
String attributeName,
Integer value,
int minValue,
int maxValue) {
if (value != null
&& !isWithinRange(value.intValue(), minValue, maxValue)) {
throw new InvalidConfigurationException(
this.getClass(),
configName,
attributeName,
"Value ["
+ value
+ "] out of range: min ["
+ minValue
+ "], max ["
+ maxValue
+ "] inclusive");
}
}
/**
* Checks if a value is in given range.
*
* @param value the value to check
* @param min the mininum the value should be
* @param max the maximum the value should be
* @return if the value is with the range
*/
private boolean isWithinRange(int value, int min, int max) {
if (value < min || value > max) {
return false;
} else {
return true;
}
}
}
|