View Javadoc

1   package org.apache.turbine.services.schedule;
2   
3   /*
4    * Copyright 2001-2005 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.util.Calendar;
20  import java.util.Date;
21  
22  import org.apache.commons.lang.StringUtils;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import org.apache.turbine.util.TurbineException;
28  
29  /***
30   * This is a wrapper for a scheduled job.  It is modeled after the
31   * Unix scheduler cron.  Note: BaseJobEntry is generated by Torque
32   * at compile time, and is therefore NOT in CVS.
33   *
34   * @author <a href="mailto:mbryson@mont.mindspring.com">Dave Bryson</a>
35   * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
36   * @version $Id: JobEntry.java 264148 2005-08-29 14:21:04Z henning $
37   */
38  public class JobEntry
39          extends BaseJobEntry
40          implements Comparable
41  {
42      /*** Logging */
43      private static Log log = LogFactory.getLog(ScheduleService.LOGGER_NAME);
44  
45      /*** indicates if job is currently running */
46      private boolean jobIsActive = false;
47  
48      /*** Next runtime. **/
49      private long runtime = 0;
50  
51      /*** schedule types **/
52      private static final int SECOND = 0;
53      private static final int MINUTE = 1;
54      private static final int WEEK_DAY = 2;
55      private static final int DAY_OF_MONTH = 3;
56      private static final int DAILY = 4;
57  
58      /***
59       * default constructor
60       */
61      public JobEntry()
62      {
63      }
64  
65      /***
66       * Constuctor.
67       *
68       * Schedule a job to run on a certain point of time.<br>
69       *
70       * Example 1: Run the DefaultScheduledJob at 8:00am every 15th of
71       * the month - <br>
72       *
73       * JobEntry je = new JobEntry(0,0,8,15,"DefaultScheduledJob");<br>
74       *
75       * Example 2: Run the DefaultScheduledJob at 8:00am every day -
76       * <br>
77       *
78       * JobEntry je = new JobEntry(0,0,8,-1,"DefaultScheduledJob");<br>
79       *
80       * Example 3: Run the DefaultScheduledJob every 2 hours. - <br>
81       *
82       * JobEntry je = new JobEntry(0,120,-1,-1,"DefaultScheduledJob");<br>
83       *
84       * Example 4: Run the DefaultScheduledJob every 30 seconds. - <br>
85       *
86       * JobEntry je = new JobEntry(30,-1,-1,-1,"DefaultScheduledJob");<br>
87       *
88       * @param sec Value for entry "seconds".
89       * @param min Value for entry "minutes".
90       * @param hour Value for entry "hours".
91       * @param wd Value for entry "week days".
92       * @param day_mo Value for entry "month days".
93       * @param task Task to execute.
94       * @exception TurbineException a generic exception.
95       */
96      public JobEntry(int sec,
97                      int min,
98                      int hour,
99                      int wd,
100                     int day_mo,
101                     String task)
102             throws TurbineException
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     public int compareTo(Object je)
129     {
130         int result = -1;
131         if (je instanceof JobEntry)
132         {
133             result = getJobId() - ((JobEntry) je).getJobId();
134         }
135         return result;
136     }
137 
138     /***
139      * Sets whether the job is running.
140      *
141      * @param isActive Whether the job is running.
142      */
143     public void setActive(boolean isActive)
144     {
145         jobIsActive = isActive;
146     }
147 
148     /***
149      * Check to see if job is currently active/running
150      *
151      * @return true if job is currently geing run by the
152      *  workerthread, otherwise false
153      */
154     public boolean isActive()
155     {
156         return jobIsActive;
157     }
158 
159     /***
160      * Get the next runtime for this job as a long.
161      *
162      * @return The next run time as a long.
163      */
164     public long getNextRuntime()
165     {
166         return runtime;
167     }
168 
169     /***
170      * Gets the next runtime as a date
171      *
172      * @return Next run date
173      */
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     public String getNextRunAsString()
185     {
186         return getNextRunDate().toString();
187     }
188 
189     /***
190      * Calculate how long before the next runtime.<br>
191      *
192      * The runtime determines it's position in the job queue.
193      * Here's the logic:<br>
194      *
195      * 1. Create a date the represents when this job is to run.<br>
196      *
197      * 2. If this date has expired, them "roll" appropriate date
198      * fields forward to the next date.<br>
199      *
200      * 3. Calculate the diff in time between the current time and the
201      * next run time.<br>
202      *
203      * @exception TurbineException a generic exception.
204      */
205     public void calcRunTime()
206             throws TurbineException
207     {
208         Calendar schedrun = Calendar.getInstance();
209         Calendar now = Calendar.getInstance();
210 
211         switch (evaluateJobType())
212         {
213             case SECOND:
214                 // SECOND (every so many seconds...)
215                 schedrun.add(Calendar.SECOND, getSecond());
216                 runtime = schedrun.getTime().getTime();
217                 break;
218 
219             case MINUTE:
220                 // MINUTE (every so many minutes...)
221                 schedrun.add(Calendar.SECOND, getSecond());
222                 schedrun.add(Calendar.MINUTE, getMinute());
223                 runtime = schedrun.getTime().getTime();
224                 break;
225 
226             case WEEK_DAY:
227                 // WEEKDAY (day of the week)
228                 schedrun.set(Calendar.SECOND, getSecond());
229                 schedrun.set(Calendar.MINUTE, getMinute());
230                 schedrun.set(Calendar.HOUR_OF_DAY, getHour());
231                 schedrun.set(Calendar.DAY_OF_WEEK, getWeekDay());
232 
233                 if (now.before(schedrun))
234                 {
235                     // Scheduled time has NOT expired.
236                     runtime = schedrun.getTime().getTime();
237                 }
238                 else
239                 {
240                     // Scheduled time has expired; roll to the next week.
241                     schedrun.add(Calendar.DAY_OF_WEEK, 7);
242                     runtime = schedrun.getTime().getTime();
243                 }
244                 break;
245 
246             case DAY_OF_MONTH:
247                 // DAY_OF_MONTH (date of the month)
248                 schedrun.set(Calendar.SECOND, getSecond());
249                 schedrun.set(Calendar.MINUTE, getMinute());
250                 schedrun.set(Calendar.HOUR_OF_DAY, getHour());
251                 schedrun.set(Calendar.DAY_OF_MONTH, getDayOfMonth());
252 
253                 if (now.before(schedrun))
254                 {
255                     // Scheduled time has NOT expired.
256                     runtime = schedrun.getTime().getTime();
257                 }
258                 else
259                 {
260                     // Scheduled time has expired; roll to the next month.
261                     schedrun.add(Calendar.MONTH, 1);
262                     runtime = schedrun.getTime().getTime();
263                 }
264                 break;
265 
266             case DAILY:
267                 // DAILY (certain hour:minutes of the day)
268                 schedrun.set(Calendar.SECOND, getSecond());
269                 schedrun.set(Calendar.MINUTE, getMinute());
270                 schedrun.set(Calendar.HOUR_OF_DAY, getHour());
271 
272                 // Scheduled time has NOT expired.
273                 if (now.before(schedrun))
274                 {
275                     runtime = schedrun.getTime().getTime();
276                 }
277                 else
278                 {
279                     // Scheduled time has expired; roll forward 24 hours.
280                     schedrun.add(Calendar.HOUR_OF_DAY, 24);
281                     runtime = schedrun.getTime().getTime();
282                 }
283                 break;
284 
285             default:
286                 // Do nothing.
287         }
288 
289         log.info("Next runtime for task " + this.getTask() + " is " + this.getNextRunDate());
290     }
291 
292     /***
293      * What schedule am I on?
294      *
295      * I know this is kinda ugly!  If you can think of a cleaner way
296      * to do this, please jump in!
297      *
298      * @return A number specifying the type of schedule. See
299      * calcRunTime().
300      * @exception TurbineException a generic exception.
301      */
302     private int evaluateJobType()
303             throws TurbineException
304     {
305 
306         // First start by checking if it's a day of the month job.
307         if (getDayOfMonth() < 0)
308         {
309             // Not a day of the month job... check weekday.
310             if (getWeekDay() < 0)
311             {
312                 // Not a weekday job...check if by the hour.
313                 if (getHour() < 0)
314                 {
315                     // Not an hourly job...check if it is by the minute
316                     if (getMinute() < 0)
317                     {
318                         // Not a by the minute job so must be by the second
319                         if (getSecond() < 0)
320                             throw new TurbineException("Error in JobEntry. Bad Job parameter.");
321 
322                         return SECOND;
323                     }
324                     else
325                     {
326                         // Must be a job run by the minute so we need minutes and
327                         // seconds.
328                         if (getMinute() < 0 || getSecond() < 0)
329                             throw new TurbineException("Error in JobEntry. Bad Job parameter.");
330 
331                         return MINUTE;
332                     }
333                 }
334                 else
335                 {
336                     // Must be a daily job by hours minutes, and seconds.  In
337                     // this case, we need the minute, second, and hour params.
338                     if (getMinute() < 0 || getHour() < 0 || getSecond() < 0)
339                         throw new TurbineException("Error in JobEntry. Bad Job parameter.");
340 
341                     return DAILY;
342                 }
343             }
344             else
345             {
346                 // Must be a weekday job.  In this case, we need
347                 // minute, second, and hour params
348                 if (getMinute() < 0 || getHour() < 0 || getSecond() < 0)
349                     throw new TurbineException("Error in JobEntry. Bad Job parameter.");
350 
351                 return WEEK_DAY;
352             }
353         }
354         else
355         {
356             // Must be a day of the month job.  In this case, we need
357             // minute, second, and hour params
358             if (getMinute() < 0 || getHour() < 0)
359                 throw new TurbineException("Error in JobEntry. Bad Job parameter.");
360 
361             return DAY_OF_MONTH;
362         }
363     }
364 
365 }