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