From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: Removed unnecessary pki folder. Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131 --- .../src/com/netscape/cmscore/jobs/CronItem.java | 168 +++++++ .../src/com/netscape/cmscore/jobs/CronRange.java | 84 ++++ .../src/com/netscape/cmscore/jobs/JobCron.java | 355 ++++++++++++++ .../com/netscape/cmscore/jobs/JobsScheduler.java | 509 +++++++++++++++++++++ 4 files changed, 1116 insertions(+) create mode 100644 base/common/src/com/netscape/cmscore/jobs/CronItem.java create mode 100644 base/common/src/com/netscape/cmscore/jobs/CronRange.java create mode 100644 base/common/src/com/netscape/cmscore/jobs/JobCron.java create mode 100644 base/common/src/com/netscape/cmscore/jobs/JobsScheduler.java (limited to 'base/common/src/com/netscape/cmscore/jobs') diff --git a/base/common/src/com/netscape/cmscore/jobs/CronItem.java b/base/common/src/com/netscape/cmscore/jobs/CronItem.java new file mode 100644 index 000000000..91574c6cc --- /dev/null +++ b/base/common/src/com/netscape/cmscore/jobs/CronItem.java @@ -0,0 +1,168 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.jobs; + +import java.util.StringTokenizer; +import java.util.Vector; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.logging.ILogger; + +/** + * class representing one Job cron item + *

+ * here, an "item" refers to one of the 5 fields in a cron string; "element" refers to any comma-deliminated element in + * an "item"...which includes both numbers and '-' separated ranges. + *

+ * for each of the 5 cron fields, it's represented as a CronItem + * + * @author cfu + * @version $Revision$, $Date$ + */ +public class CronItem { + protected static final String ALL = "*"; + protected static final String DELIM = ","; + protected static final String RANGE = "-"; + private ILogger mLogger = CMS.getLogger(); + + int mMin; // minimum + int mMax; // maximum + + // store all elements in a field. + // elements can either be numbers or ranges (CronRange) + protected Vector mElements = new Vector(); + + public CronItem(int min, int max) { + mMin = min; + mMax = max; + } + + /** + * parses and sets a string cron item + * + * @param sItem the string representing an item of a cron string. + * item can be potentially comma separated with ranges specified + * with '-'s + */ + public void set(String sItem) throws EBaseException { + + if (sItem.equals(ALL)) { + // System.out.println("CronItem set(): item is ALL"); + CronRange cr = new CronRange(); + + cr.setBegin(mMin); + cr.setEnd(mMax); + mElements.addElement(cr); + } else { + // break comma-separated elements + StringTokenizer st = new StringTokenizer(sItem, DELIM); + + while (st.hasMoreTokens()) { + String tok = (String) st.nextToken(); + // elements could be ranges (separated by '-') + int r = tok.indexOf(RANGE); + + if (r != -1) { + // potential range + String sBegin = tok.substring(0, r); + int begin = 0; + int end = 0; + + try { + begin = Integer.parseInt(sBegin); + } catch (NumberFormatException e) { + // throw ... + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_INVALID_TOKEN", tok, e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + String sEnd = tok.substring(r + 1, tok.length()); + + try { + end = Integer.parseInt(sEnd); + } catch (NumberFormatException e) { + // throw ... + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_INVALID_TOKEN", tok, e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + // got both begin and end for range + CronRange cr = new CronRange(); + + cr.setBegin(begin); + cr.setEnd(end); + // check range + if (!cr.isValidRange(mMin, mMax)) { + // throw... + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_INVALID_RANGE", + tok)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + // System.out.println("CronItem set(): adding a range"); + mElements.addElement(cr); + } else { + // number element, begin and end are the same + try { + CronRange cr = new CronRange(); + int num = Integer.parseInt(tok); + + cr.setBegin(num); + cr.setEnd(num); + // check range + if (!cr.isValidRange(mMin, mMax)) { + // throw... + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_INVALID_MIN_MAX_RANGE", Integer.toString(mMin), + Integer.toString(mMax))); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + // System.out.println("CronItem set(): adding a number"); + mElements.addElement(cr); + } catch (NumberFormatException e) { + // throw... + log(ILogger.LL_FAILURE, + "invalid item in cron: " + tok); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + } + } + } + } + + /** + * get the vector stuffed with elements where each element is + * represented as CronRange + * + * @return a vector of CronRanges + */ + public Vector getElements() { + return mElements; + } + + /** + * logs an entry in the log file. + */ + protected void log(int level, String msg) { + if (mLogger == null) + return; + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + level, "jobs/CronItem: " + msg); + } +} diff --git a/base/common/src/com/netscape/cmscore/jobs/CronRange.java b/base/common/src/com/netscape/cmscore/jobs/CronRange.java new file mode 100644 index 000000000..af5ae2a51 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/jobs/CronRange.java @@ -0,0 +1,84 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.jobs; + +/** + * class representing one Job cron element + *

+ * here, an "item" refers to one of the 5 fields in a cron string; "element" refers to any comma-deliminated element in + * an "item"...which includes both numbers and '-' separated ranges. + *

+ * an Element can contain either an integer number or a range specified as CronRange. In case of integer numbers, begin + * and end are of the same value + * + * @author cfu + * @version $Revision$, $Date$ + */ +public class CronRange { + int mBegin = 0; + int mEnd = 0; + + public CronRange() { + } + + /** + * sets the lower boundary value of the range + */ + public void setBegin(int i) { + mBegin = i; + } + + /** + * gets the lower boundary value of the range + */ + public int getBegin() { + return mBegin; + } + + /** + * sets the higher boundary value of the range + */ + public void setEnd(int i) { + mEnd = i; + } + + /** + * gets the higher boundary value of the range + */ + public int getEnd() { + return mEnd; + } + + /** + * checks to see if the lower and higher boundary values are + * within the min/max. + * + * @param min the minimum value one can specify in this field + * @param max the maximum value one can specify in this field + * @return a boolean (true/false) on whether the begin/end values + * are within the min/max passed in the params + */ + public boolean isValidRange(int min, int max) { + if ((mEnd < mBegin) || + (mBegin < min) || + (mEnd > max)) + return false; + else + return true; + } +} diff --git a/base/common/src/com/netscape/cmscore/jobs/JobCron.java b/base/common/src/com/netscape/cmscore/jobs/JobCron.java new file mode 100644 index 000000000..164c1250e --- /dev/null +++ b/base/common/src/com/netscape/cmscore/jobs/JobCron.java @@ -0,0 +1,355 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.jobs; + +import java.util.Calendar; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.jobs.IJobCron; +import com.netscape.certsrv.logging.ILogger; + +/** + * class representing one Job cron information + *

+ * here, an "item" refers to one of the 5 fields in a cron string; "element" refers to any comma-deliminated element in + * an "item"...which includes both numbers and '-' separated ranges. A cron string in the configuration takes the + * following format: minute (0-59), hour (0-23), day of the month (1-31), month of the year (1-12), day of the week + * (0-6 with 0=Sunday) + *

+ * e.g. jobsScheduler.job.rnJob1.cron=30 11,23 * * 1-5 In this example, the job "rnJob1" will be executed from Monday + * through Friday, at 11:30am and 11:30pm. + *

+ * + * @author cfu + * @version $Revision$, $Date$ + */ +public class JobCron implements IJobCron { + + /** + * CRON_MINUTE, CRON_HOUR, CRON_DAY_OF_MONTH, CRON_MONTH_OF_YEAR, + * and CRON_DAY_OF_WEEK are to be used in getItem() to + * retrieve the corresponding CronItem + */ + public static final String CRON_MINUTE = "minute"; + public static final String CRON_HOUR = "hour"; + public static final String CRON_DAY_OF_MONTH = "dom"; + public static final String CRON_MONTH_OF_YEAR = "moy"; + public static final String CRON_DAY_OF_WEEK = "dow"; + private ILogger mLogger = CMS.getLogger(); + + String mCronString = null; + + CronItem cMinute = null; + CronItem cHour = null; + CronItem cDOM = null; + CronItem cMOY = null; + CronItem cDOW = null; + + public JobCron(String cronString) + throws EBaseException { + mCronString = cronString; + + // create all 5 items in the cron + cMinute = new CronItem(0, 59); + cHour = new CronItem(0, 23); + cDOM = new CronItem(1, 31); + cMOY = new CronItem(1, 12); + cDOW = new CronItem(0, 6); // 0=Sunday + + cronToVals(mCronString); + } + + private void cronToVals(String cronString) + throws EBaseException { + StringTokenizer st = new StringTokenizer(cronString); + + String sMinute = null; + String sHour = null; + String sDayOMonth = null; + String sMonthOYear = null; + String sDayOWeek = null; + + try { + if (st.hasMoreTokens()) { + sMinute = st.nextToken(); + cMinute.set(sMinute); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_INVALID_MIN", e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + + try { + if (st.hasMoreTokens()) { + sHour = st.nextToken(); + cHour.set(sHour); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INVALID_HOUR", e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + + if (st.hasMoreTokens()) { + sDayOMonth = st.nextToken(); + // cDOM.set(sDayOMonth); + } + + try { + if (st.hasMoreTokens()) { + sMonthOYear = st.nextToken(); + cMOY.set(sMonthOYear); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INVALID_MONTH", e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + + if (st.hasMoreTokens()) { + sDayOWeek = st.nextToken(); + // cDOW.set(sDayOWeek); + } + + /** + * day-of-month or day-of-week, or both? + * if only one of them is '*', the non '*' one prevails, + * the '*' one will remain empty (no elements) + */ + // day-of-week + if ((sDayOMonth != null) + && sDayOMonth.equals(CronItem.ALL) && (sDayOWeek != null) && !sDayOWeek.equals(CronItem.ALL)) { + try { + cDOW.set(sDayOWeek); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INVALID_DAY_OF_WEEK", e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + } else if ((sDayOMonth != null) + && !sDayOMonth.equals(CronItem.ALL) && (sDayOWeek != null) && sDayOWeek.equals(CronItem.ALL)) { + try { + cDOM.set(sDayOMonth); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INVALID_DAY_OF_MONTH", e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + } else { // if both '*', every day, if neither is '*', do both + try { + if (sDayOWeek != null) { + cDOW.set(sDayOWeek); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INVALID_DAY_OF_WEEK", e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + try { + if (sDayOMonth != null) { + cDOM.set(sDayOMonth); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INVALID_DAY_OF_MONTH", e.toString())); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_JOB_CRON")); + } + } + } + + /** + * retrieves the cron item + * + * @param item name of the item. must be one of the CRON_* + * strings defined in this class + * @return an instance of the CronItem class which represents the + * requested cron item + */ + public CronItem getItem(String item) { + if (item.equals(CRON_MINUTE)) { + return cMinute; + } else if (item.equals(CRON_HOUR)) { + return cHour; + } else if (item.equals(CRON_DAY_OF_MONTH)) { + return cDOM; + } else if (item.equals(CRON_MONTH_OF_YEAR)) { + return cMOY; + } else if (item.equals(CRON_DAY_OF_WEEK)) { + return cDOW; + } else { + // throw... + } + + return null; + } + + /** + * Does the element fit any element in the item + * + * @param element the element of "now" in cron format + * @param item the item consists of a vector of elements + * @return boolean (true/false) on whether the element is one of + * the elements in the item + */ + boolean isElement(int element, Vector item) { + // loop through all of the elements of an item + for (Enumeration e = item.elements(); e.hasMoreElements();) { + CronRange cElement = e.nextElement(); + + // is a number + if (cElement.getBegin() == cElement.getEnd()) { + if (element == cElement.getBegin()) { + return true; + } + } else { // is a range + if ((element >= cElement.getBegin()) && + (element <= cElement.getEnd())) { + return true; + } + } + } + // no fit + return false; + } + + /** + * convert the day of the week representation from Calendar to + * cron + * + * @param time the Calendar value represents a moment of time + * @return an integer value that represents a cron Day-Of-Week + * element + */ + public int DOW_cal2cron(Calendar time) { + int calDow = time.get(Calendar.DAY_OF_WEEK); + int cronDow = 0; // default should never be used + + // convert the Calendar representation of dow to the cron one + switch (calDow) { + case Calendar.SUNDAY: + cronDow = 0; + break; + + case Calendar.MONDAY: + cronDow = 1; + break; + + case Calendar.TUESDAY: + cronDow = 2; + break; + + case Calendar.WEDNESDAY: + cronDow = 3; + break; + + case Calendar.THURSDAY: + cronDow = 4; + break; + + case Calendar.FRIDAY: + cronDow = 5; + break; + + case Calendar.SATURDAY: + cronDow = 6; + break; + + default: + throw new IllegalArgumentException(); + } + + return cronDow; + } + + /** + * convert the month of year representation from Calendar to cron + * + * @param time the Calendar value represents a moment of time + * @return an integer value that represents a cron Month-Of-Year + * element + */ + public int MOY_cal2cron(Calendar time) { + int calMoy = time.get(Calendar.MONTH); + int cronMoy = 0; + + // convert the Calendar representation of moy to the cron one + switch (calMoy) { + case Calendar.JANUARY: + cronMoy = 1; + break; + + case Calendar.FEBRUARY: + cronMoy = 2; + break; + + case Calendar.MARCH: + cronMoy = 3; + break; + + case Calendar.APRIL: + cronMoy = 4; + break; + + case Calendar.MAY: + cronMoy = 5; + break; + + case Calendar.JUNE: + cronMoy = 6; + break; + + case Calendar.JULY: + cronMoy = 7; + break; + + case Calendar.AUGUST: + cronMoy = 8; + break; + + case Calendar.SEPTEMBER: + cronMoy = 9; + break; + + case Calendar.OCTOBER: + cronMoy = 10; + break; + + case Calendar.NOVEMBER: + cronMoy = 11; + break; + + case Calendar.DECEMBER: + cronMoy = 12; + break; + + default: + throw new IllegalArgumentException(); + } + + return cronMoy; + } + + /** + * logs an entry in the log file. + */ + protected void log(int level, String msg) { + if (mLogger == null) + return; + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + level, msg); + } +} diff --git a/base/common/src/com/netscape/cmscore/jobs/JobsScheduler.java b/base/common/src/com/netscape/cmscore/jobs/JobsScheduler.java new file mode 100644 index 000000000..b35f8c340 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/jobs/JobsScheduler.java @@ -0,0 +1,509 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.jobs; + +import java.util.Calendar; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.jobs.EJobsException; +import com.netscape.certsrv.jobs.IJob; +import com.netscape.certsrv.jobs.IJobCron; +import com.netscape.certsrv.jobs.IJobsScheduler; +import com.netscape.certsrv.jobs.JobPlugin; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cmscore.util.Debug; + +/** + * This is a daemon thread that handles scheduled jobs like cron would + * do with different jobs. This daemon wakes up at a pre-configured + * interval to see + * if there is any job to be done, if so, a thread is created to execute + * the job(s). + *

+ * The interval jobsScheduler.interval in the configuration is specified as number of minutes. If not set, the + * default is 1 minute. Note that the cron specification for each job CAN NOT be finer than the granularity of the + * Scheduler daemon interval. For example, if the daemon interval is set to 5 minute, a job cron for every minute at 7am + * on each Tuesday (e.g. * 7 * * 2) will result in the execution of the job thread only once every 5 minutes during that + * hour. The inteval value is recommended at 1 minute, setting it otherwise has the potential of forever missing the + * beat. Use with caution. + * + * @author cfu + * @see JobCron + * @version $Revision$, $Date$ + */ +public class JobsScheduler implements Runnable, IJobsScheduler { + + protected static final long MINUTE_MILLI = 60000; + protected static final String DELIM = ","; + + /** + * Scheduler thread doing job scheduling + */ + protected String mId = ID; + protected Thread mScheduleThread = null; + + public Hashtable mJobPlugins = new Hashtable(); + public Hashtable mJobs = new Hashtable(); + private Hashtable mJobThreads = new Hashtable(); + + private IConfigStore mConfig = null; + private ILogger mLogger = null; + + // in milliseconds. daemon wakeup interval, default 1 minute. + private long mInterval = 0; + + // singleton enforcement + + private static JobsScheduler mInstance = new JobsScheduler(); + + public static JobsScheduler getInstance() { + return mInstance; + } + + // end singleton enforcement. + + private JobsScheduler() { + } + + /** + * read from the config file all implementations of Jobs, + * register and initialize them + *

+ * the config params have the following formats: jobScheduler.impl.[implementation name].class=[package name] + * jobScheduler.job.[job name].pluginName=[implementation name] jobScheduler.job.[job name].cron=[crontab format] + * jobScheduler.job.[job name].[any job specific params]=[values] + * + * @param config jobsScheduler configStore + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException, EJobsException { + mLogger = CMS.getLogger(); + + // read in config parameters and set variables + mConfig = config; + + // getting/setting interval + int i; + + try { + i = mConfig.getInteger(PROP_INTERVAL); + } catch (Exception e) { + i = 1; // default 1 minute + } + setInterval(i); + + IConfigStore c = mConfig.getSubStore(PROP_IMPL); + Enumeration mImpls = c.getSubStoreNames(); + + // register all job plugins + while (mImpls.hasMoreElements()) { + String id = mImpls.nextElement(); + String pluginPath = c.getString(id + "." + PROP_CLASS); + + JobPlugin plugin = new JobPlugin(id, pluginPath); + + mJobPlugins.put(id, plugin); + } + + // register all jobs + c = config.getSubStore(PROP_JOB); + Enumeration jobs = c.getSubStoreNames(); + + while (jobs.hasMoreElements()) { + String jobName = jobs.nextElement(); + String implName = c.getString(jobName + "." + PROP_PLUGIN); + JobPlugin plugin = mJobPlugins.get(implName); + + if (plugin == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_CLASS_NOT_FOUND", + implName)); + throw new EJobsException(CMS.getUserMessage("CMS_JOB_PLUGIN_NOT_FOUND", implName)); + } + String classPath = plugin.getClassPath(); + + // instantiate and init the job + try { + IJob job = (IJob) + Class.forName(classPath).newInstance(); + IConfigStore jconfig = c.getSubStore(jobName); + + job.init(this, jobName, implName, jconfig); + + // register the job + mJobs.put(jobName, job); + + } catch (ClassNotFoundException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INIT_ERROR", e.toString())); + throw new EJobsException(CMS.getUserMessage("CMS_JOB_LOAD_CLASS_FAILED", classPath)); + + } catch (IllegalAccessException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INIT_ERROR", e.toString())); + throw new EJobsException(CMS.getUserMessage("CMS_JOB_LOAD_CLASS_FAILED", classPath)); + + } catch (InstantiationException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INIT_ERROR", e.toString())); + throw new EJobsException(CMS.getUserMessage("CMS_JOB_LOAD_CLASS_FAILED", classPath)); + + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_JOBS_INIT_ERROR", e.toString())); + throw e; + } + } + + // are we enabled? + if (mConfig.getBoolean(PROP_ENABLED, false) == true) { + // start the daemon thread + startDaemon(); + } + } + + public Hashtable getPlugins() { + return mJobPlugins; + } + + public Hashtable getInstances() { + return mJobs; + } + + /** + * when wake up: + * . execute the scheduled job(s) + * * if job still running from previous interval, skip it + * . figure out when is the next wakeup time (every interval). If + * current wakup time runs over the interval, skip the missed interval(s) + * . sleep till the next wakeup time + */ + public void run() { + long wokeupTime = 0; + + while (true) { + // get time now + Calendar cal = Calendar.getInstance(); + long rightNow = cal.getTime().getTime(); + long duration; + long second = cal.get(Calendar.SECOND); + + if (second != 1) { // scheduler needs adjustment + // adjust to wake up at 1st second + long milliSec = cal.get(Calendar.MILLISECOND); + + // possible to be at exactly second 1, millisecond 0, + // just let it skip to next second, fine. + duration = (60 - second) * 1000 + 1000 - milliSec; + log(ILogger.LL_INFO, + "adjustment for cron behavior: sleep for " + + duration + " milliseconds"); + } else { + + // when is the next wakeup time for the JobsScheduler? + // reset next wakeup time - wake up every preset interval + + duration = mInterval - rightNow + wokeupTime; + + } + + while (duration < 0) { + duration += mInterval; + } + + if (duration != 0) { + try { + Thread.sleep(duration); + } catch (InterruptedException e) { + System.out.println(e); + } + } + + // if (duration == 0), it's time + + // woke up... + try { + if (mConfig.getBoolean(PROP_ENABLED, false) == false) { + return; + } + } catch (Exception e) { + return; + } + + // check to see if new jobs are registered + // ... later + + // get time now + cal = Calendar.getInstance(); + + /** + * Get the current time outside the jobs while loop + * to make sure that the rightful jobs are run + * -- milliseconds from the epoch + */ + wokeupTime = cal.getTime().getTime(); + + for (Enumeration e = mJobs.elements(); e.hasMoreElements(); ) { + IJob job = e.nextElement(); + + // is it enabled? + IConfigStore cs = job.getConfigStore(); + + try { + if (cs.getBoolean(PROP_ENABLED, false) == false) + continue; + } catch (Exception ex) { + continue; // ignore this job + } + + // first, check to see if thread already running + // ... + + // start the job thread if necessary + if (isShowTime(job, cal) == true) { + // log(ILogger.LL_INFO, "show time for: "+job.getId()); + + // if previous thread still alive, skip + Thread jthread = mJobThreads.get(job.getId()); + + if ((jthread == null) || (!jthread.isAlive())) { + Thread jobThread = new Thread((Runnable) job, job.getId()); + + jobThread.start(); + // put into job thread control + mJobThreads.put(job.getId(), jobThread); + } else { + // previous thread still alive, log it + log(ILogger.LL_INFO, "Job " + job.getId() + + " still running...skipping this round"); + } + } + } // for + + } + } + + public IJobCron createJobCron(String cs) throws EBaseException { + return new JobCron(cs); + } + + /** + * Is it time for the job? + */ + protected boolean isShowTime(IJob job, Calendar now) { + JobCron jcron = (JobCron) job.getJobCron(); + + if (jcron == null) { + // the impossible has happened + log(ILogger.LL_INFO, "isShowTime(): jobcron null"); + return false; + } + + /** + * is it the right month? + */ + Vector moy = + jcron.getItem(JobCron.CRON_MONTH_OF_YEAR).getElements(); + + int cronMoy = jcron.MOY_cal2cron(now); + + if (jcron.isElement(cronMoy, moy) == false) { + return false; + } + // is the right month! + + /** + * is it the right date? + */ + Vector dow = jcron.getItem(JobCron.CRON_DAY_OF_WEEK).getElements(); + Vector dom = jcron.getItem(JobCron.CRON_DAY_OF_MONTH).getElements(); + + // can't be both empty + if ((dow.isEmpty()) && dom.isEmpty()) { + // throw... or return false? + } + + int cronDow = jcron.DOW_cal2cron(now); + + if ((jcron.isElement(cronDow, dow) == false) && + (jcron.isElement(now.get(Calendar.DAY_OF_MONTH), dom) == false)) { + return false; + } + // is the right date! + + /** + * is it the right hour? + */ + Vector hour = jcron.getItem(JobCron.CRON_HOUR).getElements(); + + if (jcron.isElement(now.get(Calendar.HOUR_OF_DAY), hour) == false) { + return false; + } + // is the right hour! + + /** + * is it the right minute? + */ + Vector minute = jcron.getItem(JobCron.CRON_MINUTE).getElements(); + + if (jcron.isElement(now.get(Calendar.MINUTE), minute) == false) { + return false; + } + // is the right minute! We're on! + + return true; + } + + /** + * Retrieves id (name) of this subsystem. + * + * @return name of the Jobs Scheduler subsystem + */ + public String getId() { + return mId; + } + + /** + * Sets id string to this subsystem. + *

+ * Use with caution. Should not do it when sharing with others + * + * @param id name to be applied to an Jobs Scheduler subsystem + */ + public void setId(String id) throws EBaseException { + mId = id; + } + + /** + * creates and starts the daemon thread + */ + public void startDaemon() { + mScheduleThread = new Thread(this, "JobScheduler"); + log(ILogger.LL_INFO, "started Jobs Scheduler daemon thread"); + mScheduleThread.setDaemon(true); + mScheduleThread.start(); + } + + /** + * registers the administration servlet with the administration subsystem. + */ + public void startup() throws EBaseException { + //remove, already logged from S_ADMIN + //String infoMsg = "Jobs Scheduler subsystem administration Servlet registered"; + //log(ILogger.LL_INFO, infoMsg); + } + + /** + * shuts down Jobs one by one. + *

+ */ + public void shutdown() { + for (IJob job : mJobs.values()) { + job.stop(); + } + } + + /** + * Returns the root configuration storage of this system. + *

+ * + * @return configuration store of this subsystem + */ + public IConfigStore getConfigStore() { + return mConfig; + } + + /** + * Gets configuration parameters for the given + * job plugin. + * + * @param implName Name of the job plugin. + * @return Hashtable of required parameters. + */ + public String[] getConfigParams(String implName) + throws EJobsException { + if (Debug.ON) + Debug.trace("in getCofigParams()"); + + // is this a registered implname? + JobPlugin plugin = mJobPlugins.get(implName); + + if (plugin == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_CLASS_NOT_FOUND", implName)); + if (Debug.ON) + Debug.trace("Job plugin " + implName + " not found."); + throw new EJobsException(CMS.getUserMessage("CMS_JOB_PLUGIN_NOT_FOUND", + implName)); + } + + // XXX can find an instance of this plugin in existing + // auth manager instantces to avoid instantiation just for this. + + // a temporary instance + String className = plugin.getClassPath(); + + if (Debug.ON) + Debug.trace("className = " + className); + try { + IJob jobInst = (IJob) + Class.forName(className).newInstance(); + if (Debug.ON) + Debug.trace("class instantiated"); + return (jobInst.getConfigParams()); + } catch (InstantiationException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_CREATE_NEW", e.toString())); + if (Debug.ON) + Debug.trace("class NOT instantiated: " + e); + throw new EJobsException(CMS.getUserMessage("CMS_JOB_LOAD_CLASS_FAILED", className)); + } catch (ClassNotFoundException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_CREATE_NEW", e.toString())); + if (Debug.ON) + Debug.trace("class NOT instantiated: " + e); + throw new EJobsException(CMS.getUserMessage("CMS_JOB_LOAD_CLASS_FAILED", className)); + } catch (IllegalAccessException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_JOBS_CREATE_NEW", e.toString())); + if (Debug.ON) + Debug.trace("class NOT instantiated: " + e); + throw new EJobsException(CMS.getUserMessage("CMS_JOB_LOAD_CLASS_FAILED", className)); + } + } + + public void setInterval(int minutes) { + mInterval = minutes * MINUTE_MILLI; + } + + /** + * logs an entry in the log file. + */ + public void log(int level, String msg) { + if (mLogger == null) + return; + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + level, msg); + } + + public Hashtable getJobPlugins() { + return mJobPlugins; + } +} -- cgit