Hi

It looks good (just came back from Europe) so I am
a little bit jet-lagged.
Could you do me a favour and check out the new
ScheduleManager and its ScheduleProvider and see
if you could adapt this CronSchedulable to the new
Scheduler.
I am going to deprecate the old Scheduler in favour of
the ScheduleManager as soon as it is stable.

Have fun and thanx

xxxxxxxxxxxxxxxxx
Andreas Schaefer
Senior Consultant
JBoss Group, LLC
xxxxxxxxxxxxxxxxx

----- Original Message -----
From: "Michael Bartmann" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Tuesday, August 13, 2002 3:53 PM
Subject: [JBoss-dev] The Scheduler From Palma


> Hi,
>
> included is the code for a "CronSchedulable" you can use to run jobs at
> a specific time of day.
> It's far from perfect but has helped me a lot so far.
> Marc called me names at the Palma training for not giving this one to
> the jboss community.
> (He hasn't seen the code so far :-)
>
> Enjoy,
>
> Michael.
>
> --
>
> "She won't live. But - then again - who does ?" -- Edward James Olmos in
> 'Blade Runner'
>


----------------------------------------------------------------------------
----


> package de.j4production.base.time;
>
> import java.util.*;
> import org.apache.log4j.*;
>
> /**
>  * A Schedulable to use from the JBoss Scheduler.
>  * It uses a format similar to the well known cron-command
>  * to specify the "exact" time to run.
>  *
>  * It is quite usefull to run cpu-intensive jobs in the
>  * midnight hours.
>  *
>  * To use it write a subclass which implements the
>  * performCron-method and instantiate it with an appropriate
>  * pattern.
>  *
>  * There are some limitations:
>  *
>  * 1) The advanceDay and nextTime functions are quite complex.
>  *    You have to trust them or come up with something simpler.
>  *
>  * 2) The resolution you can get depends on the intervall in
>  *    which the JBoss Scheduler calls this Schedulable.
>  *    But: If the Scheduler failed to call in time, this is
>  *    detected, and the performCron-method is immediatelly
>  *    called the next time.
>  *
>  * 3) Not all cron formats are supported right now (NO RANGES!)
>  *
>  * 4) It could be better to port the time calculation to the
>  *    Scheduler itself, so you can adjust the sleep-period
>  *    to the circumstances. But you would need a priority-queue
>  *    data structure to handle multiple Schedulables and adjust
>  *    the sleep time for the first one in an efficient way.
>  *
>  * This code is under the LGPL-license. See the COPYING-file
>  * in the JBoss distribution.
>  *
>  * @author Michael Bartmann ([EMAIL PROTECTED])
>  * @version 1.0
>  * @copyright 4Production AG 2001 (www.4production.de)
>  */
>
> public abstract class CronSchedulable
> {
>     private static Category log =
Category.getInstance(CronSchedulable.class);
>
>     protected long lastRunMillis;
>     protected long nextRunMillis;
>
>     private int[] minutes;
>     private int[] hours;
>     private int[] daysOfMonth;
>     private int[] months;
>     private int[] daysOfWeek;
>
>     /**
>      * This constructor uses five separate Strings
>      * for the match patterns.
>      *
>      * Their format is similar to the well known cron command.
>      * See the main method below for an example.
>      *
>      * @param minutesPattern
>      * @param hourPattern
>      * @param dayPattern
>      * @param monthPattern
>      * @param weekdayPattern
>      */
>     public CronSchedulable(String minutesPattern,
>                            String hourPattern,
>                            String dayPattern,
>                            String monthPattern,
>                            String weekdayPattern)
>     {
>         minutes = string2IntArray(minutesPattern,0,0,59,"minute");
>         hours = string2IntArray(hourPattern,0,0,23,"hour");
>         daysOfMonth = string2IntArray(dayPattern,0,1,31,"dayOfMonth");
>         months = string2IntArray(monthPattern,-1,0,11,"month");
>         daysOfWeek = string2IntArray(weekdayPattern,0,1,7,"dayOfWeek");
>         lastRunMillis = System.currentTimeMillis();
>         nextRunMillis = nextTime(lastRunMillis);
>         log.info(this+" started at: "+new Date(lastRunMillis)+", next run
at approx.: "+new Date(nextRunMillis));
>     }
>
>
>     /**
>      * helper function to parse the cron format
>      * @param xa
>      * @param min
>      * @param max
>      * @return
>      */
>     private static int[] string2IntArray(String s, int offs, int min, int
max, String fieldName)
>     {
>         if ((s==null)||(s.equals(""))||(s.equals("*")))
>         {
>             return new int[0];
>         }
>         StringTokenizer t = new StringTokenizer(s,"|",false);
>         int[] h = new int[t.countTokens()];
>         for (int i=0; i<h.length; i++)
>         {
>             int x = Integer.parseInt(t.nextToken()) + offs;
>             if ((x<min)||(x>max))
>             {
>                 throw new IllegalArgumentException("parameter "+(x-offs)+"
is out of range for field "+fieldName);
>             }
>             h[i] = x;
>         }
>         return h;
>     }
>
>     /**
>      * helper function to parse the cron format
>      * @param xa
>      * @param min
>      * @param max
>      * @return
>      */
>     private static boolean matches(int x, int[]xa, int min, int max)
>     {
>         if (xa.length==0)
>         {
>             return true;
>         }
>         else
>         {
>             for (int i=0;i<xa.length;i++)
>             {
>                 if (xa[i]==x)
>                 {
>                     return true;
>                 }
>             }
>             return false;
>         }
>     }
>
>     /**
>      * helper function to parse the cron format
>      * @param xa
>      * @param min
>      * @param max
>      * @return
>      */
>     private static boolean hasMoreMatches(int x, int[]xa, int min, int
max)
>     {
>         if (xa.length==0)
>         {
>             return x<max;
>         }
>         else
>         {
>             for (int i=0;i<xa.length;i++)
>             {
>                 if (xa[i]>x)
>                 {
>                     return true;
>                 }
>             }
>             return false;
>         }
>     }
>
>     /**
>      * helper function to parse the cron format
>      * @param xa
>      * @param min
>      * @param max
>      * @return
>      */
>     private static int nextMatching(int x, int[]xa, int min, int max)
>     {
>         if (xa.length==0)
>         {
>             return x+1;
>         }
>         else
>         {
>             for (int i=0;i<xa.length;i++)
>             {
>                 if (xa[i]>x)
>                 {
>                     return xa[i];
>                 }
>             }
>             return max; // should not happen!!!
>         }
>     }
>
>     /**
>      * helper function to parse the cron format
>      * @param xa
>      * @param min
>      * @param max
>      * @return
>      */
>     private static int first(int[]xa, int min, int max)
>     {
>         if (xa.length==0)
>         {
>             return min;
>         }
>         else
>         {
>             return xa[0];
>         }
>     }
>
>     /**
>      * Helper function to advance a calendar by one day.
>      * There should be a simpler way...
>      * @param gCal
>      */
>     private void advanceDay(GregorianCalendar gCal)
>     {
>         do
>         {
>             gCal.add(GregorianCalendar.DATE,1);
>         } while (!(
matches(gCal.get(GregorianCalendar.DAY_OF_MONTH),daysOfMonth,1,gCal.getActua
lMaximum(GregorianCalendar.DAY_OF_MONTH))
>                       &&
matches(gCal.get(GregorianCalendar.MONTH),months,0,11)
>                       &&
matches(gCal.get(GregorianCalendar.DAY_OF_WEEK),daysOfWeek,1,7)
>                       ));
>     }
>
>     /**
>      * Calculate the next time to run performCron, if we know that
>      * it was last run at the given argument.
>      * @param lastTime the last time performCron() was actually run.
>      * @return the next time to run performCron()
>      */
>     private long nextTime(long lastTime)
>     {
>         GregorianCalendar gCal = new GregorianCalendar();
>         gCal.setTime(new Date(lastTime));
>         gCal.set(GregorianCalendar.SECOND,0);
>         gCal.set(GregorianCalendar.MILLISECOND,0);
>         if (
matches(gCal.get(GregorianCalendar.DAY_OF_WEEK),daysOfWeek,0,6)
>                 && matches(gCal.get(GregorianCalendar.MONTH),months,0,11)
>                 &&
matches(gCal.get(GregorianCalendar.DAY_OF_MONTH),daysOfMonth,0,31))
>         {
>             // ok, so this is a matching day.
>             // if we find a next schedule for this day we're done,
>             // but if this is the last schedule for this day, we must
advance
>             // to the next schedule on the next possible day.
>             if
(matches(gCal.get(GregorianCalendar.HOUR_OF_DAY),hours,0,23))
>             {
>                 // everything matches up to the hour, we check the seconds
>                 if
(hasMoreMatches(gCal.get(GregorianCalendar.MINUTE),minutes,0,59))
>                 {
>
gCal.set(GregorianCalendar.MINUTE,nextMatching(gCal.get(GregorianCalendar.MI
NUTE),minutes,0,59));
>                     // the rest of the fields remain intact
>                 }
>                 else
>                 {
>                     // oops, no more minute this hour
>
gCal.set(GregorianCalendar.MINUTE,first(minutes,0,59));
>                     // all other fields match, so we must advance hour
>                     if
(hasMoreMatches(gCal.get(GregorianCalendar.HOUR_OF_DAY),hours,0,23))
>                     {
>
gCal.set(GregorianCalendar.HOUR_OF_DAY,nextMatching(gCal.get(GregorianCalend
ar.HOUR_OF_DAY),hours,0,23));
>                         // the rest of the fields remain intact
>                     }
>                     else
>                     {
>
gCal.set(GregorianCalendar.HOUR_OF_DAY,first(hours,0,23));
>                         // all other fields match, so we must advance date
>                         advanceDay(gCal);
>                     }
>                 }
>             }
>             else if
(hasMoreMatches(gCal.get(GregorianCalendar.HOUR_OF_DAY),hours,0,23))
>             {
>                 gCal.set(GregorianCalendar.MINUTE,first(minutes,0,59));
>
gCal.set(GregorianCalendar.HOUR_OF_DAY,nextMatching(gCal.get(GregorianCalend
ar.HOUR_OF_DAY),hours,0,23));
>                 // the rest of the fields remain intact
>             }
>             else
>             {
>                 gCal.set(GregorianCalendar.MINUTE,first(minutes,0,59));
>                 gCal.set(GregorianCalendar.HOUR_OF_DAY,first(hours,0,23));
>                 advanceDay(gCal);
>             }
>         }
>         else
>         {
>             gCal.set(GregorianCalendar.MINUTE,first(minutes,0,59));
>             gCal.set(GregorianCalendar.HOUR_OF_DAY,first(hours,0,23));
>             advanceDay(gCal);
>         }
>         return gCal.getTime().getTime();
>     }
>
>     /**
>      * This method is called by the JBoss build-in-scheduler.
>      * That scheduler must be configured to call this method as least as
often
>      * to allow it to run performCron.
>      * @param pTimeOfCall
>      * @param pRemainingRepetitions
>      */
>     public void perform(Date pTimeOfCall, long pRemainingRepetitions)
>     {
>         long now = System.currentTimeMillis();
>         if (now>=nextRunMillis)
>         {
>             lastRunMillis = now;
>             nextRunMillis = nextTime(lastRunMillis);
>             log.info(this+" running at: "+new Date(lastRunMillis));
>             performCron();
>             log.info(this+" done, next run at approx.: "+new
Date(nextRunMillis));
>         }
>     }
>
>     /**
>      * This method is called if the cron-arguments allow.
>      * Put your code here, when extending this class to do something
useful.
>      */
>     protected abstract void performCron();
>
>
> //---------- SNIP HERE TO GET RID OF DEBUGGING/EXAMPLE
CODE ---------------
>
>
>     /**
>      * This method is only used by the example code in main.
>      */
>     private void debug(long then)
>     {
>         long result = nextTime(then);
>         log.debug("next after "+new Date(then)+" is: "+new Date(result));
>     }
>
>     /**
>      * This main method constructs a simple CronSchedulable and calls
>      * the internal nextTime()-method.
>      * Normal debugging would last years :-)
>      */
>     public static void main(String args[])
>     {
>         CronSchedulable cron = new
CronSchedulable("0|15|30|45","0|6|12|18","13","","6")
>         {
>             public void performCron()
>             {
>                 log.debug("performCron " + new Date());
>             }
>         };
>         Random r = new Random();
>         long now = System.currentTimeMillis();
>         long then = now;
>         cron.debug(now);
>         for (int i=0; i<1000; i++)
>         {
>             long millisPerSecond = 1000;
>             long millisPerMinute = millisPerSecond * 60;
>             long millisPerHour   = millisPerMinute * 60;
>             long millisPerDay    = millisPerHour * 24;
>             long millisPerYear   = millisPerDay * 366;
>             cron.debug(now+(r.nextLong()%(millisPerYear*40)));
>         }
>     }
>
> }




-------------------------------------------------------
This sf.net email is sponsored by: Dice - The leading online job board
for high-tech professionals. Search and apply for tech jobs today!
http://seeker.dice.com/seeker.epl?rel_code=31
_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to