001/* 002 * #%L 003 * Netarchivesuite - harvester 004 * %% 005 * Copyright (C) 2005 - 2018 The Royal Danish 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 */ 023package dk.netarkivet.harvester.datamodel; 024 025import java.io.Serializable; 026import java.util.Date; 027 028import dk.netarkivet.common.exceptions.ArgumentNotValid; 029import dk.netarkivet.common.utils.Named; 030 031/** 032 * This class implements a schedule that can be either repeating or timed, depending on the subclass. 033 * <p> 034 * A schedule is a combination of a frequency, defining how often this schedule and at which points in time will trigger 035 * an event , plus information about when to start and when to stop triggering events. 036 * <p> 037 * Methods are provided to check when the first event should happen, and to calculate the next events from the previous 038 * event time. 039 */ 040@SuppressWarnings({"serial"}) 041public abstract class Schedule implements Serializable, Named { 042 043 /** Human readable name for the schedule. */ 044 protected String name; 045 /** Any comments added by the user. */ 046 protected String comments; 047 /** first run of job: date, time (hour:min:sec). May be null, meaning at any time */ 048 protected Date startDate; 049 /** Frequency of runs, possibly with a time it should happen at. */ 050 protected Frequency frequency; 051 /** Edition is used by the DAO to keep track of changes. */ 052 long edition = -1; 053 /** ID autogenerated by DB, ignored otherwise. */ 054 private Long id; 055 056 /** 057 * Create a new schedule starting at a specific time and going on for an undefined time. 058 * 059 * @param startDate Time at which the schedule starts happening (though not necessarily the time of the first 060 * event). May be null, meaning at any time. 061 * @param frequency How frequently the events should happen 062 * @param name The unique name of this schedule. 063 * @param comments Comments entered by the user 064 * @throws ArgumentNotValid if frequency, name or comments is null, or name is "" 065 */ 066 protected Schedule(Date startDate, Frequency frequency, String name, String comments) { 067 ArgumentNotValid.checkNotNullOrEmpty(name, "name"); 068 // startDate can be null in case of "start now" 069 ArgumentNotValid.checkNotNull(frequency, "frequency"); 070 ArgumentNotValid.checkNotNull(comments, "comments"); 071 072 this.name = name; 073 this.startDate = startDate; 074 this.frequency = frequency; 075 this.comments = comments; 076 } 077 078 /** 079 * Get a new Schedule instance for a schedule that runs over a certain period. 080 * 081 * @param startDate The first date an event is allowed to happen. May be null, meaning at any time. 082 * @param endDate The last date an event is allowed to happen. May be null meaning continue forever. 083 * @param freq How frequently the events should happen. 084 * @param name The name of this schedule. 085 * @param comments Comments entered by the user 086 * @return A new Schedule. 087 * @throws ArgumentNotValid if frequency, name or comments is null, or name is "" 088 */ 089 public static Schedule getInstance(Date startDate, Date endDate, Frequency freq, String name, String comments) { 090 return new TimedSchedule(startDate, endDate, freq, name, comments); 091 } 092 093 /** 094 * Get a new Schedule instance for a schedule that runs a certain number of times. 095 * 096 * @param startDate The first date an event is allowed to happen. May be null, meaning at any time. 097 * @param repeats How many events should happen on this schedule. 098 * @param freq How frequently the events should happen. 099 * @param name The name of this schedule. 100 * @param comments Comments entered by the user 101 * @return A new Schedule. 102 * @throws ArgumentNotValid if frequency, name or comments is null, or name is "" or repeats is 0 or negative 103 */ 104 public static Schedule getInstance(Date startDate, int repeats, Frequency freq, String name, String comments) { 105 return new RepeatingSchedule(startDate, repeats, freq, name, comments); 106 } 107 108 /** 109 * Return the date at which the first event will happen. 110 * 111 * @param now The first time it can happen. Will be normalized to only second precision, milliseconds are set to 0. 112 * @return The date of the first event to happen after startDate. 113 * @throws ArgumentNotValid if now is null 114 */ 115 public Date getFirstEvent(Date now) { 116 ArgumentNotValid.checkNotNull(now, "now"); 117 118 now = new Date(now.getTime() / 1000 * 1000); 119 if (startDate != null && now.before(startDate)) { 120 return frequency.getFirstEvent(startDate); 121 } 122 return frequency.getFirstEvent(now); 123 } 124 125 /** 126 * Return the date at which the next event will happen. 127 * 128 * @param lastEvent The time at which the previous event happened. 129 * @param numPreviousEvents How many events have previously happened. 130 * @return The date of the next event to happen or null for no more events. 131 * @throws ArgumentNotValid if numPreviousEvents is negative 132 */ 133 public abstract Date getNextEvent(Date lastEvent, int numPreviousEvents); 134 135 /** 136 * Get the name of this schedule. 137 * 138 * @return The name 139 */ 140 public String getName() { 141 return name; 142 } 143 144 /** 145 * Get the first possible date this schedule is allowed to run. 146 * 147 * @return The first possible date or null for any time 148 */ 149 public Date getStartDate() { 150 return startDate; 151 } 152 153 /** 154 * Get the frequency defining how often and when this schedule should be run. 155 * 156 * @return The frequency 157 */ 158 public Frequency getFrequency() { 159 return frequency; 160 } 161 162 /** 163 * Autogenerated equals. 164 * 165 * @param o The object to compare with 166 * @return Whether objects are equal 167 */ 168 public boolean equals(Object o) { 169 if (this == o) { 170 return true; 171 } 172 if (!(o instanceof Schedule)) { 173 return false; 174 } 175 176 final Schedule schedule = (Schedule) o; 177 178 if (!comments.equals(schedule.comments)) { 179 return false; 180 } 181 if (!frequency.equals(schedule.frequency)) { 182 return false; 183 } 184 if (!name.equals(schedule.name)) { 185 return false; 186 } 187 if (startDate != null ? !startDate.equals(schedule.startDate) : schedule.startDate != null) { 188 return false; 189 } 190 191 return true; 192 } 193 194 /** 195 * Autogenerated hashcode method. 196 * 197 * @return the hashcode 198 */ 199 public int hashCode() { 200 int result; 201 result = name.hashCode(); 202 result = 29 * result + (startDate != null ? startDate.hashCode() : 0); 203 result = 29 * result + frequency.hashCode(); 204 result = 29 * result + comments.hashCode(); 205 return result; 206 } 207 208 /** 209 * Returns any user-entered comments about this schedule. 210 * 211 * @return A string of free-form comments. 212 */ 213 public String getComments() { 214 return comments; 215 } 216 217 /** 218 * Set the comments for the schedule. 219 * 220 * @param comments The new comments 221 */ 222 public void setComments(String comments) { 223 ArgumentNotValid.checkNotNull(comments, "comments"); 224 this.comments = comments; 225 } 226 227 /** 228 * Get the edition number. 229 * 230 * @return The edition number 231 */ 232 public long getEdition() { 233 return edition; 234 } 235 236 /** 237 * Set the edition number. 238 * 239 * @param theEdition The new edition 240 */ 241 public void setEdition(long theEdition) { 242 edition = theEdition; 243 } 244 245 /** 246 * Get the ID of this schedule. Only for use by DBDAO 247 * 248 * @return the ID of this schedule 249 */ 250 long getID() { 251 return id; 252 } 253 254 /** 255 * Set the ID of this schedule. Only for use by DBDAO 256 * 257 * @param id the new ID of this schedule 258 */ 259 void setID(long id) { 260 this.id = id; 261 } 262 263 /** 264 * Check if this schedule has an ID set yet (doesn't happen until the DBDAO persists it). 265 * 266 * @return true if this schedule has an ID set yet 267 */ 268 boolean hasID() { 269 return id != null; 270 } 271 272}