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 hours. 034 */ 035public class HourlyFrequency extends Frequency { 036 037 /** The minute of the hour the event should happen at. */ 038 private int minute; 039 040 /** 041 * Create a new HourlyFrequency that happens every numUnits hours, at an unspecified minute. 042 * 043 * @param numUnits Number of hours from one event to the next 044 * @throws ArgumentNotValid if numUnits if 0 or negative 045 */ 046 public HourlyFrequency(int numUnits) { 047 super(numUnits, true); 048 } 049 050 /** 051 * Create a new HourlyFrequency that happens every numUnits hours, on the minute. 052 * 053 * @param numUnits Number of hours from one event to the next 054 * @param minute What minute of the hour the event should happen on. 055 * @throws ArgumentNotValid if numUnits if 0 or negative or minutes is <0 or >59 056 */ 057 public HourlyFrequency(int numUnits, int minute) { 058 super(numUnits, false); 059 Calendar cal = GregorianCalendar.getInstance(); 060 if (minute < cal.getMinimum(Calendar.MINUTE) || minute > cal.getMaximum(Calendar.MINUTE)) { 061 throw new ArgumentNotValid("Minute must be in legal range '" + cal.getMinimum(Calendar.MINUTE) + "' to '" 062 + cal.getMaximum(Calendar.MINUTE) + "'"); 063 } 064 065 this.minute = minute; 066 } 067 068 /** 069 * Given when the last event happened, tell us when the next event should happen (even if the new event is in the 070 * past). 071 * <p> 072 * The time of the next event is guaranteed to be later that lastEvent. For certain frequencies (e.g. once a day, 073 * 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 074 * time of the next event is the first matching time after lastEvent. 075 * 076 * @param lastEvent A time from which the next event should be calculated. 077 * @return At what point the event should happen next. 078 * @throws ArgumentNotValid if lastEvent is null 079 */ 080 public Date getNextEvent(Date lastEvent) { 081 ArgumentNotValid.checkNotNull(lastEvent, "lastEvent"); 082 083 Calendar last = new GregorianCalendar(); 084 last.setTime(getFirstEvent(lastEvent)); 085 last.add(Calendar.HOUR_OF_DAY, getNumUnits()); 086 return getFirstEvent(last.getTime()); 087 } 088 089 /** 090 * Given a starting time, tell us when the first event should happen. 091 * 092 * @param startTime The earliest time the event can happen. 093 * @return At what point the event should happen the first time. 094 * @throws ArgumentNotValid if startTime is null 095 */ 096 public Date getFirstEvent(Date startTime) { 097 ArgumentNotValid.checkNotNull(startTime, "startTime"); 098 099 if (isAnytime()) { 100 return startTime; 101 } 102 Calendar start = new GregorianCalendar(); 103 start.setTime(startTime); 104 start.set(Calendar.MINUTE, minute); 105 if (start.getTime().before(startTime)) { 106 start.add(Calendar.HOUR_OF_DAY, 1); 107 } 108 return start.getTime(); 109 110 } 111 112 /** 113 * If not anytime, the minute at which events should start. 114 * 115 * @return the minute 116 */ 117 public int getMinute() { 118 return minute; 119 } 120 121 /** 122 * Autogenerated equals. 123 * 124 * @param o The object to compare with 125 * @return Whether objects are equal 126 */ 127 public boolean equals(Object o) { 128 if (this == o) { 129 return true; 130 } 131 if (!(o instanceof HourlyFrequency)) { 132 return false; 133 } 134 if (!super.equals(o)) { 135 return false; 136 } 137 138 final HourlyFrequency hourlyFrequency = (HourlyFrequency) o; 139 140 if (isAnytime()) { 141 return true; 142 } 143 144 if (minute != hourlyFrequency.minute) { 145 return false; 146 } 147 148 return true; 149 } 150 151 /** 152 * Autogenerated hashcode method. 153 * 154 * @return the hashcode 155 */ 156 public int hashCode() { 157 int result = super.hashCode(); 158 result = 29 * result + minute; 159 return result; 160 } 161 162 /** 163 * Return the exact minute event should happen on, or null if this is an anyTime event or doesn't define what minute 164 * it should happen on. 165 * 166 * @return the exact minute event should happen on 167 */ 168 public Integer getOnMinute() { 169 if (!isAnytime()) { 170 return minute; 171 } 172 return null; 173 } 174 175 /** 176 * Return the exact hour event should happen on, or null if this is an anyTime event or doesn't define what hour it 177 * should happen on. 178 * 179 * @return null always 180 */ 181 public Integer getOnHour() { 182 return null; 183 } 184 185 /** 186 * Return the exact day of week event should happen on, or null if this is an anyTime event or doesn't define what 187 * day of week it should happen on. 188 * 189 * @return null always 190 */ 191 public Integer getOnDayOfWeek() { 192 return null; 193 } 194 195 /** 196 * Return the exact day of month event should happen on, or null if this is an anyTime event or doesn't define what 197 * day of month it should happen on. 198 * 199 * @return null (always) 200 */ 201 public Integer getOnDayOfMonth() { 202 return null; 203 } 204 205 /** 206 * Return an integer that can be used to identify the kind of frequency. No two subclasses should use the same 207 * integer 208 * 209 * @return an integer that can be used to identify the kind of frequency 210 */ 211 public int ordinal() { 212 return TimeUnit.HOURLY.ordinal(); 213 } 214 215 /** 216 * Human readable representation of this object. 217 * 218 * @return Human readable representation 219 */ 220 public String toString() { 221 if (isAnytime()) { 222 return "every " + getNumUnits() + " hours"; 223 } 224 return "every " + getNumUnits() + " hours at " + minute; 225 } 226 227}