001/* 002 * #%L 003 * Netarchivesuite - harvester 004 * %% 005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library, 006 * the National Library of France and the Austrian National Library. 007 * %% 008 * This program is free software: you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation, either version 2.1 of the 011 * License, or (at your option) any later version. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Lesser Public License for more details. 017 * 018 * You should have received a copy of the GNU General Lesser Public 019 * License along with this program. If not, see 020 * <http://www.gnu.org/licenses/lgpl-2.1.html>. 021 * #L% 022 */ 023 024package dk.netarkivet.harvester.datamodel; 025 026import java.util.Calendar; 027import java.util.Date; 028import java.util.GregorianCalendar; 029 030import dk.netarkivet.common.exceptions.ArgumentNotValid; 031 032/** 033 * This class implements a frequency of a number of days. 034 */ 035public class DailyFrequency extends Frequency { 036 037 /** The minute of the hour the event should happen at. */ 038 private int minute; 039 /** The hour of the day the event should happen at. */ 040 private int hour; 041 042 /** 043 * Create a new daily frequency that happens every numUnits days, anytime. 044 * 045 * @param numUnits Number of days from event to event. 046 * @throws ArgumentNotValid if numUnits if 0 or negative 047 */ 048 public DailyFrequency(int numUnits) { 049 super(numUnits, true); 050 } 051 052 /** 053 * Create a new daily frequency that happens every numUnits days, on the given hour and minute. 054 * 055 * @param numUnits Number of days from event to event. 056 * @param hour The hour on which the event should happen. 057 * @param minute The minute of hour on which the event should happen. 058 * @throws ArgumentNotValid if numUnits if 0 or negative or hours is <0 or >23 or minutes is <0 or >59 059 */ 060 public DailyFrequency(int numUnits, int hour, int minute) { 061 super(numUnits, false); 062 Calendar cal = GregorianCalendar.getInstance(); 063 if (hour < cal.getMinimum(Calendar.HOUR_OF_DAY) || hour > cal.getMaximum(Calendar.HOUR_OF_DAY)) { 064 throw new ArgumentNotValid("Hour of day must be in legal range '" + cal.getMinimum(Calendar.HOUR_OF_DAY) 065 + "' to '" + cal.getMaximum(Calendar.HOUR_OF_DAY) + "'"); 066 } 067 if (minute < cal.getMinimum(Calendar.MINUTE) || minute > cal.getMaximum(Calendar.MINUTE)) { 068 throw new ArgumentNotValid("Minute must be in legal range '" + cal.getMinimum(Calendar.MINUTE) + "' to '" 069 + cal.getMaximum(Calendar.MINUTE) + "'"); 070 } 071 072 this.minute = minute; 073 this.hour = hour; 074 } 075 076 /** 077 * Given when the last event happened, tell us when the next event should happen (even if the new event is in the 078 * past). 079 * <p> 080 * The time of the next event is guaranteed to be later that lastEvent. For certain frequencies (e.g. once a day, 081 * any time of day), the time of the next event is derived from lastEvent, for others (e.g. once a day at 13:00) the 082 * time of the next event is the first matching time after lastEvent. 083 * 084 * @param lastEvent A time from which the next event should be calculated. 085 * @return At what point the event should happen next. 086 */ 087 public Date getNextEvent(Date lastEvent) { 088 ArgumentNotValid.checkNotNull(lastEvent, "lastEvent"); 089 090 Calendar last = new GregorianCalendar(); 091 last.setTime(getFirstEvent(lastEvent)); 092 last.add(Calendar.DAY_OF_YEAR, getNumUnits()); 093 return getFirstEvent(last.getTime()); 094 } 095 096 /** 097 * Given a starting time, tell us when the first event should happen. 098 * 099 * @param startTime The earliest time the event can happen. 100 * @return At what point the event should happen the first time. 101 */ 102 public Date getFirstEvent(Date startTime) { 103 ArgumentNotValid.checkNotNull(startTime, "startTime"); 104 105 if (isAnytime()) { 106 return startTime; 107 } 108 Calendar start = new GregorianCalendar(); 109 start.setTime(startTime); 110 start.set(Calendar.MINUTE, minute); 111 start.set(Calendar.HOUR_OF_DAY, hour); 112 if (start.getTime().before(startTime)) { 113 start.add(Calendar.DAY_OF_YEAR, 1); 114 } 115 return start.getTime(); 116 } 117 118 /** 119 * If not anytime, the minute at which events should start. 120 * 121 * @return the minute 122 */ 123 public int getMinute() { 124 return minute; 125 } 126 127 /** 128 * If not anytime, the hour at which events should start. 129 * 130 * @return the hour 131 */ 132 public int getHour() { 133 return hour; 134 } 135 136 /** 137 * Autogenerated equals. 138 * 139 * @param o The object to compare with 140 * @return Whether objects are equal 141 */ 142 public boolean equals(Object o) { 143 if (this == o) { 144 return true; 145 } 146 if (!(o instanceof DailyFrequency)) { 147 return false; 148 } 149 if (!super.equals(o)) { 150 return false; 151 } 152 153 final DailyFrequency dailyFrequency = (DailyFrequency) o; 154 155 if (isAnytime()) { 156 return true; 157 } 158 159 if (hour != dailyFrequency.hour) { 160 return false; 161 } 162 if (minute != dailyFrequency.minute) { 163 return false; 164 } 165 166 return true; 167 } 168 169 /** 170 * Autogenerated hashcode method. 171 * 172 * @return the hashcode 173 */ 174 public int hashCode() { 175 int result = super.hashCode(); 176 result = 29 * result + minute; 177 result = 29 * result + hour; 178 return result; 179 } 180 181 /** 182 * Return the exact minute event should happen on, or null if this is an anyTime event or doesn't define what minute 183 * it should happen on. 184 * 185 * @return the exact minute event should happen on, or null if this is an anyTime event or doesn't define what 186 * minute it should happen on 187 */ 188 public Integer getOnMinute() { 189 if (!isAnytime()) { 190 return minute; 191 } 192 return null; 193 } 194 195 /** 196 * Return the exact hour event should happen on, or null if this is an anyTime event or doesn't define what hour it 197 * should happen on. 198 * 199 * @return the exact hour event should happen on, or null if this is an anyTime event or doesn't define what hour it 200 * should happen on 201 */ 202 public Integer getOnHour() { 203 if (!isAnytime()) { 204 return hour; 205 } 206 return null; 207 } 208 209 /** 210 * Return the exact day of week event should happen on, or null if this is an anyTime event or doesn't define what 211 * day of week it should happen on. 212 * 213 * @return the exact day of week event should happen on, or null if this is an anyTime event or doesn't define what 214 * day of week it should happen on 215 */ 216 public Integer getOnDayOfWeek() { 217 return null; 218 } 219 220 /** 221 * Return the exact day of month event should happen on, or null if this is an anyTime event or doesn't define what 222 * day of month it should happen on. 223 * 224 * @return the exact day of month event should happen on, or null if this is an anyTime event or doesn't define what 225 * day of month it should happen on 226 */ 227 public Integer getOnDayOfMonth() { 228 return null; 229 } 230 231 /** 232 * Return an integer that can be used to identify the kind of frequency. No two subclasses should use the same 233 * integer 234 * 235 * @return an integer that can be used to identify the kind of frequency 236 */ 237 public int ordinal() { 238 return TimeUnit.DAILY.ordinal(); 239 } 240 241 /** 242 * Human readable representation of this object. 243 * 244 * @return Human readable representation 245 */ 246 public String toString() { 247 if (isAnytime()) { 248 return "every " + getNumUnits() + " days"; 249 } 250 return "every " + getNumUnits() + " days at " + hour + ":" + minute; 251 } 252 253}