001package org.apache.turbine.services.schedule; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.util.Calendar; 023import java.util.Date; 024 025import org.apache.commons.lang3.StringUtils; 026import org.apache.logging.log4j.LogManager; 027import org.apache.logging.log4j.Logger; 028import org.apache.turbine.util.TurbineException; 029 030/** 031 * This class provides the basic implementation of common features for a scheduled job entry. 032 * 033 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a> 034 */ 035public abstract class AbstractJobEntry implements JobEntry 036{ 037 /** Logging */ 038 protected static final Logger log = LogManager.getLogger(ScheduleService.LOGGER_NAME); 039 040 /** indicates if job is currently running */ 041 private boolean jobIsActive = false; 042 043 /** Next runtime. **/ 044 private long runtime = 0; 045 046 /** schedule types **/ 047 protected enum ScheduleType { 048 SECOND, 049 MINUTE, 050 WEEK_DAY, 051 DAY_OF_MONTH, 052 DAILY 053 } 054 055 /** 056 * Default constructor 057 */ 058 public AbstractJobEntry() 059 { 060 super(); 061 } 062 063 /** 064 * Constructor. 065 * 066 * Schedule a job to run on a certain point of time.<br> 067 * 068 * Example 1: Run the DefaultScheduledJob at 8:00am every 15th of 069 * the month - <br> 070 * 071 * JobEntry je = new JobEntry(0,0,8,-1,15,"DefaultScheduledJob");<br> 072 * 073 * Example 2: Run the DefaultScheduledJob at 8:00am every day - 074 * <br> 075 * 076 * JobEntry je = new JobEntry(0,0,8,-1,-1,"DefaultScheduledJob");<br> 077 * 078 * Example 3: Run the DefaultScheduledJob every 2 hours. - <br> 079 * 080 * JobEntry je = new JobEntry(0,120,-1,-1,-1,"DefaultScheduledJob");<br> 081 * 082 * Example 4: Run the DefaultScheduledJob every 30 seconds. - <br> 083 * 084 * JobEntry je = new JobEntry(30,-1,-1,-1,-1,"DefaultScheduledJob");<br> 085 * 086 * @param sec Value for entry "seconds". 087 * @param min Value for entry "minutes". 088 * @param hour Value for entry "hours". 089 * @param wd Value for entry "week days". 090 * @param day_mo Value for entry "month days". 091 * @param task Task to execute. 092 * @throws TurbineException a generic exception. 093 */ 094 public AbstractJobEntry(int sec, 095 int min, 096 int hour, 097 int wd, 098 int day_mo, 099 String task) 100 throws TurbineException 101 { 102 this(); 103 104 if (StringUtils.isEmpty(task)) 105 { 106 throw new TurbineException("Error in JobEntry. " + 107 "Bad Job parameter. Task not set."); 108 } 109 110 setSecond(sec); 111 setMinute(min); 112 setHour(hour); 113 setWeekDay(wd); 114 setDayOfMonth(day_mo); 115 setTask(task); 116 117 calcRunTime(); 118 } 119 120 /** 121 * Used for ordering Jobentries 122 * Note: this comparator imposes orderings that are inconsistent with 123 * equals. 124 * 125 * @param je The first <code>JobEntry</code> object. 126 * @return An <code>int</code> indicating the result of the comparison. 127 */ 128 @Override 129 public int compareTo(JobEntry je) 130 { 131 return getJobId() - je.getJobId(); 132 } 133 134 /** 135 * Sets whether the job is running. 136 * 137 * @param isActive Whether the job is running. 138 */ 139 @Override 140 public void setActive(boolean isActive) 141 { 142 jobIsActive = isActive; 143 } 144 145 /** 146 * Check to see if job is currently active/running 147 * 148 * @return true if job is currently queuing run by the 149 * worker thread, otherwise false 150 */ 151 @Override 152 public boolean isActive() 153 { 154 return jobIsActive; 155 } 156 157 /** 158 * Get the next runtime for this job as a long. 159 * 160 * @return The next run time as a long. 161 */ 162 @Override 163 public long getNextRuntime() 164 { 165 return runtime; 166 } 167 168 /** 169 * Gets the next runtime as a date 170 * 171 * @return Next run date 172 */ 173 @Override 174 public Date getNextRunDate() 175 { 176 return new Date(runtime); 177 } 178 179 /** 180 * Get the next runtime for this job as a String. 181 * 182 * @return The next run time as a String. 183 */ 184 @Override 185 public String getNextRunAsString() 186 { 187 return getNextRunDate().toString(); 188 } 189 190 /** 191 * Calculate how long before the next runtime.<br> 192 * 193 * The runtime determines it's position in the job queue. 194 * Here's the logic:<br> 195 * 196 * 1. Create a date the represents when this job is to run.<br> 197 * 198 * 2. If this date has expired, them "roll" appropriate date 199 * fields forward to the next date.<br> 200 * 201 * 3. Calculate the diff in time between the current time and the 202 * next run time.<br> 203 * 204 * @throws TurbineException a generic exception. 205 */ 206 @Override 207 public void calcRunTime() 208 throws TurbineException 209 { 210 Calendar schedrun = Calendar.getInstance(); 211 Calendar now = Calendar.getInstance(); 212 213 switch (evaluateJobType()) 214 { 215 case SECOND: 216 // SECOND (every so many seconds...) 217 schedrun.add(Calendar.SECOND, getSecond()); 218 runtime = schedrun.getTime().getTime(); 219 break; 220 221 case MINUTE: 222 // MINUTE (every so many minutes...) 223 schedrun.add(Calendar.SECOND, getSecond()); 224 schedrun.add(Calendar.MINUTE, getMinute()); 225 runtime = schedrun.getTime().getTime(); 226 break; 227 228 case WEEK_DAY: 229 // WEEKDAY (day of the week) 230 schedrun.set(Calendar.SECOND, getSecond()); 231 schedrun.set(Calendar.MINUTE, getMinute()); 232 schedrun.set(Calendar.HOUR_OF_DAY, getHour()); 233 schedrun.set(Calendar.DAY_OF_WEEK, getWeekDay()); 234 235 if (now.before(schedrun)) 236 { 237 // Scheduled time has NOT expired. 238 runtime = schedrun.getTime().getTime(); 239 } 240 else 241 { 242 // Scheduled time has expired; roll to the next week. 243 schedrun.add(Calendar.DAY_OF_WEEK, 7); 244 runtime = schedrun.getTime().getTime(); 245 } 246 break; 247 248 case DAY_OF_MONTH: 249 // DAY_OF_MONTH (date of the month) 250 schedrun.set(Calendar.SECOND, getSecond()); 251 schedrun.set(Calendar.MINUTE, getMinute()); 252 schedrun.set(Calendar.HOUR_OF_DAY, getHour()); 253 schedrun.set(Calendar.DAY_OF_MONTH, getDayOfMonth()); 254 255 if (now.before(schedrun)) 256 { 257 // Scheduled time has NOT expired. 258 runtime = schedrun.getTime().getTime(); 259 } 260 else 261 { 262 // Scheduled time has expired; roll to the next month. 263 schedrun.add(Calendar.MONTH, 1); 264 runtime = schedrun.getTime().getTime(); 265 } 266 break; 267 268 case DAILY: 269 // DAILY (certain hour:minutes of the day) 270 schedrun.set(Calendar.SECOND, getSecond()); 271 schedrun.set(Calendar.MINUTE, getMinute()); 272 schedrun.set(Calendar.HOUR_OF_DAY, getHour()); 273 274 // Scheduled time has NOT expired. 275 if (now.before(schedrun)) 276 { 277 runtime = schedrun.getTime().getTime(); 278 } 279 else 280 { 281 // Scheduled time has expired; roll forward 24 hours. 282 schedrun.add(Calendar.HOUR_OF_DAY, 24); 283 runtime = schedrun.getTime().getTime(); 284 } 285 break; 286 287 default: 288 // Do nothing. 289 } 290 291 log.info("Next runtime for task {} is {}", this::getTask, this::getNextRunDate); 292 } 293 294 /** 295 * What schedule am I on? 296 * 297 * I know this is kinda ugly! If you can think of a cleaner way 298 * to do this, please jump in! 299 * 300 * @return A number specifying the type of schedule. See 301 * calcRunTime(). 302 * @throws TurbineException a generic exception. 303 */ 304 private ScheduleType evaluateJobType() 305 throws TurbineException 306 { 307 308 // First start by checking if it's a day of the month job. 309 if (getDayOfMonth() < 0) 310 { 311 // Not a day of the month job... check weekday. 312 if (getWeekDay() < 0) 313 { 314 // Not a weekday job...check if by the hour. 315 if (getHour() < 0) 316 { 317 // Not an hourly job...check if it is by the minute 318 if (getMinute() < 0) 319 { 320 // Not a by the minute job so must be by the second 321 if (getSecond() < 0) 322 { 323 throw new TurbineException("Error in JobEntry. Bad Job parameter."); 324 } 325 326 return ScheduleType.SECOND; 327 } 328 else 329 { 330 // Must be a job run by the minute so we need minutes and 331 // seconds. 332 if (getMinute() < 0 || getSecond() < 0) 333 { 334 throw new TurbineException("Error in JobEntry. Bad Job parameter."); 335 } 336 337 return ScheduleType.MINUTE; 338 } 339 } 340 else 341 { 342 // Must be a daily job by hours minutes, and seconds. In 343 // this case, we need the minute, second, and hour params. 344 if (getMinute() < 0 || getHour() < 0 || getSecond() < 0) 345 { 346 throw new TurbineException("Error in JobEntry. Bad Job parameter."); 347 } 348 349 return ScheduleType.DAILY; 350 } 351 } 352 else 353 { 354 // Must be a weekday job. In this case, we need 355 // minute, second, and hour params 356 if (getMinute() < 0 || getHour() < 0 || getSecond() < 0) 357 { 358 throw new TurbineException("Error in JobEntry. Bad Job parameter."); 359 } 360 361 return ScheduleType.WEEK_DAY; 362 } 363 } 364 else 365 { 366 // Must be a day of the month job. In this case, we need 367 // minute, second, and hour params 368 if (getMinute() < 0 || getHour() < 0) 369 { 370 throw new TurbineException("Error in JobEntry. Bad Job parameter."); 371 } 372 373 return ScheduleType.DAY_OF_MONTH; 374 } 375 } 376 377 /** 378 * Get the value of jobId. 379 * 380 * @return int 381 */ 382 @Override 383 public abstract int getJobId(); 384 385 /** 386 * Set the value of jobId. 387 * 388 * @param v new value 389 */ 390 @Override 391 public abstract void setJobId(int v); 392 393 /** 394 * Get the value of second. 395 * 396 * @return int 397 */ 398 public abstract int getSecond(); 399 400 /** 401 * Set the value of second. 402 * 403 * @param v new value 404 */ 405 public abstract void setSecond(int v); 406 407 /** 408 * Get the value of minute. 409 * 410 * @return int 411 */ 412 public abstract int getMinute(); 413 414 /** 415 * Set the value of minute. 416 * 417 * @param v new value 418 */ 419 public abstract void setMinute(int v); 420 421 /** 422 * Get the value of hour. 423 * 424 * @return int 425 */ 426 public abstract int getHour(); 427 428 /** 429 * Set the value of hour. 430 * 431 * @param v new value 432 */ 433 public abstract void setHour(int v); 434 435 /** 436 * Get the value of weekDay. 437 * 438 * @return int 439 */ 440 public abstract int getWeekDay(); 441 442 /** 443 * Set the value of weekDay. 444 * 445 * @param v new value 446 */ 447 public abstract void setWeekDay(int v); 448 449 /** 450 * Get the value of dayOfMonth. 451 * 452 * @return int 453 */ 454 public abstract int getDayOfMonth(); 455 456 /** 457 * Set the value of dayOfMonth. 458 * 459 * @param v new value 460 */ 461 public abstract void setDayOfMonth(int v); 462 463 /** 464 * Get the value of task. 465 * 466 * @return String 467 */ 468 @Override 469 public abstract String getTask(); 470 471 /** 472 * Set the value of task. 473 * 474 * @param v new value 475 */ 476 @Override 477 public abstract void setTask(String v); 478}