1 package org.apache.turbine.services.schedule;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.util.Calendar;
23 import java.util.Date;
24
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.turbine.util.TurbineException;
29
30 /**
31 * This class provides the basic implementation of common features for a scheduled job entry.
32 *
33 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
34 */
35 public abstract class AbstractJobEntry implements JobEntry
36 {
37 /** Logging */
38 protected static Log log = LogFactory.getLog(ScheduleService.LOGGER_NAME);
39
40 /** indicates if job is currently running */
41 private boolean jobIsActive = false;
42
43 /** Next runtime. **/
44 private long runtime = 0;
45
46 /** schedule types **/
47 protected enum ScheduleType {
48 SECOND,
49 MINUTE,
50 WEEK_DAY,
51 DAY_OF_MONTH,
52 DAILY
53 }
54
55 /**
56 * Default constructor
57 */
58 public AbstractJobEntry()
59 {
60 super();
61 }
62
63 /**
64 * Constructor.
65 *
66 * Schedule a job to run on a certain point of time.<br>
67 *
68 * Example 1: Run the DefaultScheduledJob at 8:00am every 15th of
69 * the month - <br>
70 *
71 * JobEntry je = new JobEntry(0,0,8,-1,15,"DefaultScheduledJob");<br>
72 *
73 * Example 2: Run the DefaultScheduledJob at 8:00am every day -
74 * <br>
75 *
76 * JobEntry je = new JobEntry(0,0,8,-1,-1,"DefaultScheduledJob");<br>
77 *
78 * Example 3: Run the DefaultScheduledJob every 2 hours. - <br>
79 *
80 * JobEntry je = new JobEntry(0,120,-1,-1,-1,"DefaultScheduledJob");<br>
81 *
82 * Example 4: Run the DefaultScheduledJob every 30 seconds. - <br>
83 *
84 * JobEntry je = new JobEntry(30,-1,-1,-1,-1,"DefaultScheduledJob");<br>
85 *
86 * @param sec Value for entry "seconds".
87 * @param min Value for entry "minutes".
88 * @param hour Value for entry "hours".
89 * @param wd Value for entry "week days".
90 * @param day_mo Value for entry "month days".
91 * @param task Task to execute.
92 * @throws TurbineException a generic exception.
93 */
94 public AbstractJobEntry(int sec,
95 int min,
96 int hour,
97 int wd,
98 int day_mo,
99 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 " + this.getTask() + " is " + 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 }