All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.util.scheduler.CronSchedule Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.util.scheduler;

import com.hfg.util.StringUtil;
import com.hfg.util.collection.CollectionUtil;
import com.hfg.util.collection.OrderedSet;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

//------------------------------------------------------------------------------
/**
 Scheduler that uses the same specification syntax as the Unix cron utility.
 See Wikipedia.
 The text-based specification has five fields:
 
  * * * * *  command to execute
  | | | | |
  | | | | |
  | | | | +------ day of week (0 - 6) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0)
  | | | +----------- month (1 - 12)
  | | +---------------- day of month (1 - 31)
  | +--------------------- hour (0 - 23)
  +-------------------------- min (0 - 59)
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg Library // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ // TODO: More to do to fully support cron syntax. public class CronSchedule implements Schedule { private String mMinuteSpec; private String mHourSpec; private String mDayOfMonthSpec; private String mMonthSpec; private String mDayOfWeekSpec; private OrderedSet mMinuteValues; private OrderedSet mHourValues; private OrderedSet mDayOfMonthValues; private OrderedSet mMonthValues; private OrderedSet mDayOfWeekValues; //########################################################################### // CONSTRUCTORS //########################################################################### //--------------------------------------------------------------------------- public CronSchedule(String inCronString) { parse(inCronString); } //########################################################################### // PUBLIC METHODS //########################################################################### //--------------------------------------------------------------------------- public Date next() { return nextAfter(new Date()); } //--------------------------------------------------------------------------- public Date nextAfter(Date inReferenceDate) { Calendar calendar = new GregorianCalendar(); calendar.setTime(inReferenceDate); // Cron doesn't specify times with a precision below minutes calendar.set(Calendar.MILLISECOND, 0); calendar.set(Calendar.SECOND, 0); calendar.add(Calendar.MINUTE, 1); // Every minute value is valid for execution unless values have been specified if (CollectionUtil.hasValues(mMinuteValues)) { while (! mMinuteValues.contains(calendar.get(Calendar.MINUTE))) { calendar.add(Calendar.MINUTE, 1); } } // Every hour value is valid for execution unless values have been specified if (CollectionUtil.hasValues(mHourValues)) { while (! mHourValues.contains(calendar.get(Calendar.HOUR_OF_DAY))) { calendar.add(Calendar.HOUR_OF_DAY, 1); if (null == mMinuteValues) { // Set the minute value to zero zeroCalendarField(calendar, Calendar.MINUTE); } } } if (CollectionUtil.hasValues(mDayOfMonthValues) || CollectionUtil.hasValues(mDayOfWeekValues)) { boolean modified = false; while ((mDayOfMonthValues != null && ! mDayOfMonthValues.contains(calendar.get(Calendar.DAY_OF_MONTH))) || (mDayOfWeekValues != null && ! mDayOfWeekValues.contains(calendar.get(Calendar.DAY_OF_WEEK)))) { calendar.add(Calendar.DAY_OF_MONTH, 1); modified = true; } if (modified) { if (null == mHourValues) { // Set the hour value to zero zeroCalendarField(calendar, Calendar.HOUR_OF_DAY); } if (null == mMinuteValues) { // Set the minute value to zero zeroCalendarField(calendar, Calendar.MINUTE); } } } if (CollectionUtil.hasValues(mMonthValues)) { boolean modified = false; while ((mMonthValues != null && ! mMonthValues.contains(calendar.get(Calendar.MONTH) + 1)) || (mDayOfMonthValues != null && ! mDayOfMonthValues.contains(calendar.get(Calendar.DAY_OF_MONTH))) || (mDayOfWeekValues != null && ! mDayOfWeekValues.contains(calendar.get(Calendar.DAY_OF_WEEK)))) { modified = true; // Are we already at the end of the month? if (calendar.get(Calendar.DAY_OF_MONTH) == calendar.getActualMaximum(Calendar.DAY_OF_MONTH)) { calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.add(Calendar.MONTH, 1); while (! mMonthValues.contains(calendar.get(Calendar.MONTH) + 1)) { calendar.add(Calendar.MONTH, 1); } } else { calendar.add(Calendar.DAY_OF_MONTH, 1); } } if (modified) { if (null == mHourValues) { // Set the hour value to zero zeroCalendarField(calendar, Calendar.HOUR_OF_DAY); } if (null == mMinuteValues) { // Set the minute value to zero zeroCalendarField(calendar, Calendar.MINUTE); } } } return calendar.getTime(); } //--------------------------------------------------------------------------- public CronSchedule setMinuteSpec(String inMinuteSpec) { mMinuteValues = null; if (StringUtil.isSet(inMinuteSpec)) { String spec = inMinuteSpec.trim(); if (! spec.equals("*")) { List values = new ArrayList(60); String[] pieces = spec.split(","); for (String piece : pieces) { int startValue; int endValue; int dashIdx = piece.indexOf("-"); if (dashIdx > 0) { startValue = Integer.parseInt(piece.substring(0, dashIdx)); endValue = Integer.parseInt(piece.substring(dashIdx + 1)); } else { startValue = endValue = Integer.parseInt(piece); } for (int i = startValue; i <= endValue; i++) { if (i < 0 || i > 59) { throw new RuntimeException("Invalid minute value: " + StringUtil.singleQuote(i) + "! Valid value range: 0-59."); } values.add(i); } } // Make sure the values are sorted low to high Collections.sort(values); mMinuteValues = new OrderedSet(values); } } return this; } //--------------------------------------------------------------------------- public CronSchedule setHourSpec(String inHourSpec) { mHourValues = null; if (StringUtil.isSet(inHourSpec)) { String spec = inHourSpec.trim(); if (! spec.equals("*")) { List values = new ArrayList(24); String[] pieces = spec.split(","); for (String piece : pieces) { int startValue; int endValue; int dashIdx = piece.indexOf("-"); if (dashIdx > 0) { startValue = Integer.parseInt(piece.substring(0, dashIdx)); endValue = Integer.parseInt(piece.substring(dashIdx + 1)); } else { startValue = endValue = Integer.parseInt(piece); } for (int i = startValue; i <= endValue; i++) { if (i < 0 || i > 23) { throw new RuntimeException("Invalid hour value: " + StringUtil.singleQuote(i) + "! Valid value range: 0-23."); } values.add(i); } } // Make sure the values are sorted low to high Collections.sort(values); mHourValues = new OrderedSet(values); } } return this; } //--------------------------------------------------------------------------- public CronSchedule setDayOfMonthSpec(String inDayOfMonthSpec) { mDayOfMonthValues = null; if (StringUtil.isSet(inDayOfMonthSpec)) { String spec = inDayOfMonthSpec.trim(); if (! spec.equals("*")) { List values = new ArrayList(32); String[] pieces = spec.split(","); for (String piece : pieces) { int startValue; int endValue; int dashIdx = piece.indexOf("-"); if (dashIdx > 0) { startValue = Integer.parseInt(piece.substring(0, dashIdx)); endValue = Integer.parseInt(piece.substring(dashIdx + 1)); } else { startValue = endValue = Integer.parseInt(piece); } for (int i = startValue; i <= endValue; i++) { if (i < 1 || i > 31) { throw new RuntimeException("Invalid day of month value: " + StringUtil.singleQuote(i) + "! Valid value range: 1-31."); } values.add(i); } } // Make sure the values are sorted low to high Collections.sort(values); mDayOfMonthValues = new OrderedSet(values); } } return this; } //--------------------------------------------------------------------------- public CronSchedule setMonthSpec(String inMonthSpec) { mMonthValues = null; if (StringUtil.isSet(inMonthSpec)) { String spec = inMonthSpec.trim(); if (! spec.equals("*")) { List values = new ArrayList(13); String[] pieces = spec.split(","); for (String piece : pieces) { int startValue; int endValue; int dashIdx = piece.indexOf("-"); if (dashIdx > 0) { startValue = Integer.parseInt(piece.substring(0, dashIdx)); endValue = Integer.parseInt(piece.substring(dashIdx + 1)); } else { startValue = endValue = Integer.parseInt(piece); } for (int i = startValue; i <= endValue; i++) { if (i < 1 || i > 12) { throw new RuntimeException("Invalid day of month value: " + StringUtil.singleQuote(i) + "! Valid value range: 1-12."); } values.add(i); } } // Make sure the values are sorted low to high Collections.sort(values); mMonthValues = new OrderedSet(values); } } return this; } //--------------------------------------------------------------------------- public CronSchedule setDayOfWeekSpec(String inDayOfWeekSpec) { mDayOfWeekValues = null; if (StringUtil.isSet(inDayOfWeekSpec)) { String spec = inDayOfWeekSpec.trim(); if (! spec.equals("*")) { List values = new ArrayList(13); String[] pieces = spec.split(","); for (String piece : pieces) { int startValue; int endValue; int dashIdx = piece.indexOf("-"); if (dashIdx > 0) { startValue = Integer.parseInt(piece.substring(0, dashIdx)); endValue = Integer.parseInt(piece.substring(dashIdx + 1)); } else { startValue = endValue = Integer.parseInt(piece); } for (int i = startValue; i <= endValue; i++) { if (i < 0 || i > 6) { throw new RuntimeException("Invalid day of month value: " + StringUtil.singleQuote(i) + "! Valid value range: 0-6."); } values.add(i + 1); } } // Make sure the values are sorted low to high Collections.sort(values); mDayOfWeekValues = new OrderedSet(values); } } return this; } //########################################################################### // PRIVATE METHODS //########################################################################### //--------------------------------------------------------------------------- private void parse(String inCronString) { String[] pieces = inCronString.trim().split("\\s+"); if (pieces.length != 5) { throw new RuntimeException("The cron string " + StringUtil.singleQuote(inCronString) + " did not have the expected 5 cron fields!"); } mMinuteSpec = pieces[0]; mHourSpec = pieces[1]; mDayOfMonthSpec = pieces[2]; mMonthSpec = pieces[3]; mDayOfWeekSpec = pieces[4]; setMinuteSpec(pieces[0]); setHourSpec(pieces[1]); setDayOfMonthSpec(pieces[2]); setMonthSpec(pieces[3]); setDayOfWeekSpec(pieces[4]); } //--------------------------------------------------------------------------- private void zeroCalendarField(Calendar inCalendar, int inField) { inCalendar.add(inField, - inCalendar.get(inField)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy