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.webinterface; 025 026import java.text.ParseException; 027import java.text.SimpleDateFormat; 028import java.util.Date; 029 030import javax.servlet.ServletRequest; 031import javax.servlet.jsp.PageContext; 032 033import dk.netarkivet.common.exceptions.ArgumentNotValid; 034import dk.netarkivet.common.exceptions.ForwardedToErrorPage; 035import dk.netarkivet.common.utils.I18n; 036import dk.netarkivet.common.webinterface.HTMLUtils; 037import dk.netarkivet.harvester.datamodel.DailyFrequency; 038import dk.netarkivet.harvester.datamodel.Frequency; 039import dk.netarkivet.harvester.datamodel.HourlyFrequency; 040import dk.netarkivet.harvester.datamodel.MinuteFrequency; 041import dk.netarkivet.harvester.datamodel.MonthlyFrequency; 042import dk.netarkivet.harvester.datamodel.Schedule; 043import dk.netarkivet.harvester.datamodel.ScheduleDAO; 044import dk.netarkivet.harvester.datamodel.WeeklyFrequency; 045 046/** 047 * Contains utility methods for creating and editing schedule definitions for harvests. 048 */ 049public final class ScheduleDefinition { 050 051 /* 052 * Parameters for the Definitions-edit-schedule.jsp page. They should be self explanatory. 053 */ 054 /** BeginAt parameter. */ 055 static final String BEGIN_AT_PARAMETER = "beginAt"; 056 /** FirsrHarvestTime parameter. */ 057 static final String FIRST_HARVEST_TIME_PARAMETER = "firstHarvestTime"; 058 /** Continue parameter. */ 059 static final String CONTINUE_PARAMETER = "continue"; 060 /** EndHarvestTime parameter. */ 061 static final String END_HARVEST_TIME_PARAMETER = "endHarvestTime"; 062 /** Timespan parameter. */ 063 static final String TIMESPAN_PARAMETER = "timespan"; 064 /** HarvestTime parameter. */ 065 static final String HARVEST_TIME_PARAMETER = "harvestTime"; 066 /** Frequency in minutes parameter. */ 067 static final String FREQUENCY_MINUTES_PARAMETER = "frequency_minutes"; 068 /** Frequency in hours parameter. */ 069 static final String FREQUENCY_HOURS_PARAMETER = "frequency_hours"; 070 /** Frequency defined by day parameter. */ 071 static final String FREQUENCY_DAY_PARAMETER = "frequency_day"; 072 /** Frequency defined by date parameter. */ 073 static final String FREQUENCY_DATE_PARAMETER = "frequency_date"; 074 /** Comments parameter. */ 075 static final String COMMENTS_PARAMETERS = "comments"; 076 /** Edition parameter. */ 077 static final String EDITION_PARAMETER = "edition"; 078 /** Number of harvests parameter. */ 079 static final String NUMBER_OF_HARVESTS_PARAMETER = "numberOfHarvests"; 080 /** name parameter. */ 081 static final String NAME_PARAMETER = "name"; 082 /** update parameter. */ 083 static final String UPDATE_PARAMETER = "update"; 084 /** Frequency parameter. */ 085 static final String FREQUENCY_PARAMETER = "frequency"; 086 087 /** 088 * Private constructor. No instances. 089 */ 090 private ScheduleDefinition() { 091 092 } 093 094 /** 095 * Processes the request parameters for the page Definitions-edit-schedule.jsp The parameters are first checked for 096 * validity. If they are not acceptable, an exception is thrown, otherwise the parameters are passed on to the 097 * methods editScheduleDefinition() which edits or creates the relevant schedule. 098 * <p> 099 * update: if set, execute this method name: the name of the schedule If name is unset and update is unset, the GUI 100 * can be used to create a new schedule. It is an error condition to have name unset and update set. 101 * <p> 102 * edition: the edition of the schedule being edited. If not specified, the name must not refer to an existing 103 * schedule. frequency: castable to an integer > 0. Actually the period between harvests in units of ... timespan: 104 * allowable values dage, timer, uger, m\u00e5neder 105 * <p> 106 * harvestTime: allowable values, whenever, aTime 107 * <p> 108 * If whenever is set then ignore remaining values in this group frequency_hours: the hour time for harvesting, 109 * integer 0<=x<=23, must be set if aTime is set and timespan is not "hours" frequency_minutes: the minute time for 110 * harvesting, integer 0<=x<=59, must be set if aTime is set and timespan is not "hours" frequency_day: the day of 111 * the week on which the harvest is to take place. Allowable values 1-7. Must be set if timespan is set to "weeks". 112 * frequency_date: the date of the month on which harvests are to occur. Integer 1<=x<=31. Must be set if timespan 113 * is "months" 114 * <p> 115 * beginAt: allowable values "asSoonAsPossible", "beginning". Not null firstHarvestTime: a date/time field in format 116 * DD/MM YYYY hh:mm. Must be set if beginAt="beginning" 117 * <p> 118 * continue: allowable values "forever", "toTime", "numberOfHarvests" endHarvestTime: a date/time field in format 119 * DD/MM YYYY hh:mm. Must be set if continue="beginning" numberOfHarvests: int > 0. Must be set if 120 * continue="numberOfHarvests" 121 * 122 * @param context Context of web request 123 * @param i18n I18N information 124 */ 125 public static void processRequest(PageContext context, I18n i18n) { 126 ArgumentNotValid.checkNotNull(context, "PageContext context"); 127 ArgumentNotValid.checkNotNull(i18n, "I18n i18n"); 128 129 ServletRequest request = context.getRequest(); 130 String update = request.getParameter(UPDATE_PARAMETER); 131 if (update == null) { 132 return; 133 } 134 135 HTMLUtils.forwardOnEmptyParameter(context, NAME_PARAMETER); 136 137 String name = request.getParameter(NAME_PARAMETER).trim(); 138 139 long edition = HTMLUtils.parseOptionalLong(context, EDITION_PARAMETER, -1L); 140 if (ScheduleDAO.getInstance().exists(name)) { 141 if (ScheduleDAO.getInstance().read(name).getEdition() != edition) { 142 HTMLUtils.forwardWithRawErrorMessage( 143 context, 144 i18n, 145 "errormsg;schedule.has.changed.0.retry.1", 146 "<br/><a href=\"Definitions-edit-schedule.jsp?name=" 147 + HTMLUtils.escapeHtmlValues(HTMLUtils.encode(name)) + "\">", "</a>"); 148 throw new ForwardedToErrorPage("Schedule '" + name + "' has changed"); 149 } 150 } else { 151 // Creating new schedule, always edition 0 152 edition = 0; 153 } 154 155 Frequency freq = getFrequency(context, i18n); 156 Date startDate = getStartDate(context, i18n); 157 Date endDate = getEndDate(context, i18n); 158 String continueS = request.getParameter(CONTINUE_PARAMETER); 159 int repeats = HTMLUtils.parseOptionalLong(context, NUMBER_OF_HARVESTS_PARAMETER, 0L).intValue(); 160 161 String comments = request.getParameter(COMMENTS_PARAMETERS); 162 updateSchedule(freq, startDate, continueS, endDate, repeats, name, edition, comments); 163 } 164 165 /** 166 * Update or create the schedule in persistent storage. 167 * 168 * @param freq The frequency of the schedule 169 * @param startDate The start date of the schedule 170 * @param continueS The continue-mode of the schedule 171 * @param endDate The end date for the schedule (if any) 172 * @param repeats How many time should the schedule be repeated 173 * @param name The name of the schedule 174 * @param edition The edition of the schedule 175 * @param comments Any comments associated with the schedule 176 */ 177 private static void updateSchedule(Frequency freq, Date startDate, String continueS, Date endDate, int repeats, 178 String name, long edition, String comments) { 179 ScheduleDAO sdao = ScheduleDAO.getInstance(); 180 Schedule schedule; 181 182 if (comments == null) { 183 comments = ""; 184 } 185 if (continueS.equals(NUMBER_OF_HARVESTS_PARAMETER)) { 186 schedule = Schedule.getInstance(startDate, repeats, freq, name, comments); 187 } else { 188 schedule = Schedule.getInstance(startDate, endDate, freq, name, comments); 189 } 190 191 if (sdao.exists(name)) { 192 schedule.setEdition(edition); 193 sdao.update(schedule); 194 } else { 195 sdao.create(schedule); 196 } 197 } 198 199 /** 200 * If the beginAt parameter is set then this returns the first time at which the harvest is to be run. Otherwise it 201 * returns null. 202 * 203 * @param context Web context of the request 204 * @param i18n I18N information 205 * @return the first time to run the harvest 206 */ 207 private static Date getStartDate(PageContext context, I18n i18n) { 208 Date startDate = null; 209 HTMLUtils.forwardOnIllegalParameter(context, BEGIN_AT_PARAMETER, "asSoonAsPossible", "beginning"); 210 String beginAt = context.getRequest().getParameter(BEGIN_AT_PARAMETER); 211 if (beginAt.equals("beginning")) { 212 String firstHarvestTime = context.getRequest().getParameter(FIRST_HARVEST_TIME_PARAMETER); 213 try { 214 startDate = (new SimpleDateFormat(I18n.getString(dk.netarkivet.harvester.Constants.TRANSLATIONS_BUNDLE, 215 context.getResponse().getLocale(), "harvestdefinition.schedule.edit.timeformat"))) 216 .parse(firstHarvestTime); 217 } catch (ParseException e) { 218 HTMLUtils.forwardWithErrorMessage(context, i18n, "errormsg;illegal.time.value.0", firstHarvestTime); 219 throw new ForwardedToErrorPage("Illegal start time format. '" + firstHarvestTime + "'", e); 220 } 221 } 222 return startDate; 223 } 224 225 /** 226 * If the toTime parameter is set then this returns the last time at which the harvest is to be run. Otherwise it 227 * returns null. 228 * 229 * @param context Web context of the request 230 * @param i18n I18N information 231 * @return the last time to run the harvest 232 */ 233 private static Date getEndDate(PageContext context, I18n i18n) { 234 Date endDate = null; 235 HTMLUtils.forwardOnIllegalParameter(context, CONTINUE_PARAMETER, "forever", "toTime", "numberOfHarvests"); 236 String continueS = context.getRequest().getParameter(CONTINUE_PARAMETER); 237 if (continueS.equals("toTime")) { 238 String endHarvestTime = context.getRequest().getParameter(END_HARVEST_TIME_PARAMETER); 239 try { 240 endDate = (new SimpleDateFormat(I18n.getString(dk.netarkivet.harvester.Constants.TRANSLATIONS_BUNDLE, 241 context.getResponse().getLocale(), "harvestdefinition.schedule.edit.timeformat"))) 242 .parse(endHarvestTime); 243 } catch (ParseException e) { 244 HTMLUtils.forwardWithErrorMessage(context, i18n, "errormsg;illegal.time.value.0", endHarvestTime, e); 245 throw new ForwardedToErrorPage("Illegal end time format. '" + endHarvestTime + "'", e); 246 } 247 } 248 return endDate; 249 } 250 251 /** 252 * Returns a frequency object specifying whether the harvest is to be minute, hourly, daily, weekly, or monthly and 253 * how often it is to be run. 254 * 255 * @param context Web context of the request 256 * @param i18n I18N information 257 * @return the Frequency for the harvest 258 */ 259 private static Frequency getFrequency(PageContext context, I18n i18n) { 260 int frequency = HTMLUtils.parseAndCheckInteger(context, FREQUENCY_PARAMETER, 1, Integer.MAX_VALUE); 261 HTMLUtils.forwardOnEmptyParameter(context, TIMESPAN_PARAMETER, HARVEST_TIME_PARAMETER); 262 HTMLUtils.forwardOnIllegalParameter(context, TIMESPAN_PARAMETER, "days", "hours", "weeks", "months", "minutes"); 263 HTMLUtils.forwardOnIllegalParameter(context, HARVEST_TIME_PARAMETER, "whenever", "aTime"); 264 ServletRequest request = context.getRequest(); 265 String timespan = request.getParameter(TIMESPAN_PARAMETER); 266 String harvestTime = request.getParameter(HARVEST_TIME_PARAMETER); 267 if (harvestTime.equals("whenever")) { 268 if (timespan.equals("hours")) { 269 return new HourlyFrequency(frequency); 270 } else if (timespan.equals("days")) { 271 return new DailyFrequency(frequency); 272 } else if (timespan.equals("weeks")) { 273 return new WeeklyFrequency(frequency); 274 } else if (timespan.equals("minutes")) { 275 return new MinuteFrequency(frequency); 276 } else { 277 return new MonthlyFrequency(frequency); 278 } 279 } 280 int frequencyMinutes; 281 int frequencyHours = 0; 282 int frequencyDay = 0; 283 int frequencyDate = 0; 284 frequencyMinutes = HTMLUtils.parseAndCheckInteger(context, FREQUENCY_MINUTES_PARAMETER, 0, 59); 285 if (!timespan.equals("hours")) { 286 frequencyHours = HTMLUtils.parseAndCheckInteger(context, FREQUENCY_HOURS_PARAMETER, 0, 23); 287 } 288 if (timespan.equals("weeks")) { 289 frequencyDay = HTMLUtils.parseAndCheckInteger(context, FREQUENCY_DAY_PARAMETER, 1, 7); 290 } 291 if (timespan.equals("months")) { 292 frequencyDate = HTMLUtils.parseAndCheckInteger(context, FREQUENCY_DATE_PARAMETER, 1, 31); 293 } 294 if (timespan.equals("hours")) { 295 return new HourlyFrequency(frequency, frequencyMinutes); 296 } else if (timespan.equals("days")) { 297 return new DailyFrequency(frequency, frequencyHours, frequencyMinutes); 298 } else if (timespan.equals("weeks")) { 299 return new WeeklyFrequency(frequency, frequencyDay, frequencyHours, frequencyMinutes); 300 } else if (timespan.equals("minutes")) { 301 return new MinuteFrequency(frequency); 302 } else { 303 return new MonthlyFrequency(frequency, frequencyDate, frequencyHours, frequencyMinutes); 304 } 305 } 306}