package org.oddjob.schedules.schedules; import java.io.Serializable; import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.oddjob.arooa.deploy.annotations.ArooaAttribute; import org.oddjob.schedules.CalendarUnit; import org.oddjob.schedules.CalendarUtils; import org.oddjob.schedules.ConstrainedSchedule; import org.oddjob.schedules.units.Month; /** * @oddjob.description A schedule for the periods of the year. * The periods may be specified either as the dates of days of the year * or as months. * <p> * The format for dates is MM-dd, i.e. 03-02 is The second of March. * <p> * The format for months is either the month number, 1 to 12 or one of * JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, * OCTOBER, NOVEMBER, DECEMBER (case insensitive). * * @oddjob.description A schedule for a range of months, or a month. The month * is specified as an integer between 1 and 12 where 1 is January and * 12 is December. * * @oddjob.example * * A schedule for two different month ranges. From April to September the * job will run daily at 10 am, and from October to March the job will run * daily at 11 am. * * {@oddjob.xml.resource org/oddjob/schedules/schedules/MonthScheduleExample.xml} * * Instead of month numbers, English month names can be used. This is * equivalent to the above. * * {@oddjob.xml.resource org/oddjob/schedules/schedules/MonthScheduleExample2.xml} * * @oddjob.example * * A from day of year to day of year example. * * {@oddjob.xml.resource org/oddjob/schedules/schedules/DayOfYearFromTo.xml} * * @oddjob.example * * An on day of year example. * * {@oddjob.xml.resource org/oddjob/schedules/schedules/DayOfYearOn.xml} * * @author Rob Gordon */ final public class YearlySchedule extends ConstrainedSchedule implements Serializable { private static final long serialVersionUID = 20050226; public static final Pattern DAY_FORMAT = Pattern.compile("(\\d?\\d)-(\\d?\\d)"); /** * @oddjob.property * @oddjob.description The from month. * @oddjob.required No, defaults to 1 (January). */ private Month fromMonth; /** * @oddjob.property * @oddjob.description The to month. * @oddjob.required No, defaults to 12 (December). */ private Month toMonth; @ArooaAttribute public void setFromMonth(Month from) { this.fromMonth = from; } public Month getFromMonth() { return fromMonth; } @ArooaAttribute public void setToMonth(Month to) { this.toMonth = to; } public Month getToMonth() { return toMonth; } /** * @oddjob.property inMonth * @oddjob.description The month in which this schedule is for. * This has the same effect as setting fromMonth and toMonth to the same thing. * @oddjob.required No. * * @param in The in month. */ @ArooaAttribute public void setInMonth(Month in) { this.setFromMonth(in); this.setToMonth(in); } /** * @oddjob.property * @oddjob.description The from month and day. * @oddjob.require No. */ private String fromDate; /** * @oddjob.property * @oddjob.description The to month and day. * @oddjob.require No. */ private String toDate; public void setFromDate(String from) { this.fromDate = from; } public String getFromDate() { return fromDate; } public void setToDate(String to) { this.toDate = to; } public String getToDate() { return toDate; } /** * @oddjob.property onDate * @oddjob.description The day on which this schedule is for. * This has the same effect as setting fromDate and toDate to the same thing. * @oddjob.required No. * * @param on The day on which this schedule is for. */ public void setOnDate(String on) { this.setFromDate(on); this.setToDate(on); } @Override protected CalendarUnit intervalBetween() { return new CalendarUnit(Calendar.YEAR, 1); } /** * Parse the day of the year. * * @param text The day of the year * @param timeZone The time zone. * @return */ static Calendar parseDay(String text, Date referenceDate, TimeZone timeZone) throws ParseException { Matcher matcher = DAY_FORMAT.matcher(text); if (!matcher.matches()) { throw new ParseException(text, 0); } int month = Integer.parseInt(matcher.group(1)); int day = Integer.parseInt(matcher.group(2)); CalendarUtils calendarUtils = new CalendarUtils(referenceDate, timeZone); return calendarUtils.dayOfYear(day, month); } protected Calendar fromCalendar(Date referenceDate, TimeZone timeZone) { if (fromDate != null) { try { return parseDay(fromDate, referenceDate, timeZone); } catch (ParseException e) { throw new RuntimeException("Failed to parse from day.", e); } } else if (fromMonth != null) { return CalendarUtils.monthOfYear(referenceDate, fromMonth.getMonthNumber(), timeZone); } else { return CalendarUtils.startOfYear(referenceDate, timeZone); } } protected Calendar toCalendar(Date referenceDate, TimeZone timeZone) { if (toDate != null) { try { Calendar cal = parseDay(toDate, referenceDate, timeZone); CalendarUtils.setEndOfDay(cal); return cal; } catch (ParseException e) { throw new RuntimeException("Failed to parse to day.", e); } } else if (toMonth != null) { Calendar toCal = CalendarUtils.monthOfYear(referenceDate, toMonth.getMonthNumber(), timeZone); CalendarUtils.setEndOfMonth(toCal); return toCal; } else { return CalendarUtils.endOfYear(referenceDate, timeZone); } } /** * Override toString. * * @return A description of the schedule. */ public String toString() { return this.getClass().getSimpleName() + " from " + getFromDate() + " to " + getToDate(); } }